Tutorial: RC522 RFID Module aansluiten op een Arduino
Leer hier hoe je met de RC522 RFID Module kunt lezen, schrijven én authenticeren! Heb je vragen? Neem contact op: wij helpen je graag op weg.
De RC522 RFID module (koop hier in de webshop) moet met software worden aangestuurd om de 13.56MHz keyfobs te kunnen lezen en schrijven.
De reset pin (RST) is laag-actief, dat betekend dat de module gereset wordt als deze pin aan de 3.3V wordt aangesloten. Aangezien de module erg robuust is, en een zeer goede interne foute afhandeling heeft, heb je deze pin waarschijnlijk nooit nodig. Het is echter altijd handig om toch de module te kunnen resetten als het via software niet opgelost kan worden.
In totaal zijn er 5 signalen nodig om de RC522 aan te sturen, namelijk: RST, MISO, MOSI, SCK en SS. Als je gebruikt maakt van een 4-kanaals level converter dan denk je dat je 1 kanaal te kort komt. Echter kan het MISO (Master Input Slave Output) direct op de 5V Arduino aangesloten worden. Het MISO datasignaal komt namelijk van de RC522 af, en heeft een signaalniveau van 3.3V. Voor de Arduino is een 3.3V signaal hoog genoeg om als logisch hoog te worden herkend.
- Pin 3.3V aansluiten op een 3.3V voeding of de 3.3V output van de Arduino
- Pin GND aansluiten aan de massa van het systeem
- Pin RST (Reset, Active Low) via een level shifter aansluiten op pin 9 van de Arduino
- Pin IRQ (Interrupt) wordt in dit voorbeeld niet gebruikt
- Pin MISO direct op pin 12 van de Arduino
- Pin MOSI aansluiten via een level shifter op pin 11 van de Arduino
- Pin SCK (Serial Clock) aansluiten via een level shifter op pin 13 van de Arduino
- Pin SDA (SPI Slave Select, SS) aansluiten via een level shifter op pin 10 van de Arduino
De datasignalen SS en RST kun je ook op een andere digitale poort zetten als dat beter uitkomt. De overige datasignalen moeten op de genoemde pinnen van de Arduino blijven zitten, aangezien die in de SPI Library zijn vastgelegd.
De opbouw van data in een MIFARE Classic keyfob
Nu je alles hebt aangesloten kun je bijna beginnen aan het programmeren. Ben je nog niet bekend met de datastructuur van een MIFARE keyfob? Lees dan deze sectie even door zodat je weet hoe de interne datastructuur er uit ziet. In dit voorbeeld ga ik uit van een standaard MIFARE Classic 1KB keyfob (of kaart).

- Sector 0 .. 15
- Block 0 .. 63
- Data - 16 bytes per blok
- Blok #0 - Manufacturer Blok
- 6 Access bytes in het Trailing Blok van elke sector. Standaard 0xFFFFFFFFFFFF.
De datastructuur bestaat uit 16 sectoren, waarbij elke sector bestaat uit 4 blokken, en elke blok 16 bytes aan data kan vasthouden. Hierbij komen we uit op 16 x 4 x 16 = 1024 bytes, precies 1KB. Maar.. niet alle blokken kunnen gebruikt worden voor het wegschrijven van data.. helaas. Effectief gezien kun je maximaal 752 bytes gebruiken voor opslag.
- Blok 0 (sector #0, blok 0) is het Manufacturer Blok, en dit blok mag nooit overschreven worden. Zekerheidshalve sla je Blok 0 het liefst in zijn geheel over.
- Elk laatste blok van een sector is een Trailing Blok en bevat informatie (access bits, een soort wachtwoord) voor het lezen en schrijven naar de overige 3 blokken binnen deze sector. Het gaat dus om de blokken 3, 7, 11, 15, etc.., 63.
Ook is er in de software geen sprake van sectoren, maar alleen van blokken. Wil je bijvoorbeeld blok 0 van sector 2 benaderen, dan zul je in de software blok 8 moeten aanroepen.
RC522 Arduino Software - Lezen & Schrijven
Voordat de software geschreven kan worden moet je eerst onderstaande Arduino Library downloaden.
Download Arduino Library <MFRC522.h>
Met onderstaande code kun je:
- Lezen: De keyfob (ook wel PICC, Proximity Integrated Circuit Card, genoemd) uitlezen
- Schrijven: Naar de keyfob schrijven
- Authenticeren: De keyfob uitlezen en dit vergelijken met een stukje data
Hieronder zijn de stappen weergegeven om te lezen, schrijven en authenticeren via de RC522 module:
- Nadat de kaart is geïdentificeerd wordt er wat basis informatie weergegeven.
- Controleer of deze kaart compitabel is met deze software
- Bereid de software voor op het schrijven en lezen van data
- Toegang krijgen tot de (beveiligde) sector van de kaart (Sector #1)
- Geef de data van Sector #1 (Blok 4 t/m Blok 7) weer op het scherm
- Schrijf data naar Blok 4 (Sector #1, Blok #1)
- Lees de data van Blok 4 uit, en controleer of deze overeenkomt met de geschreven data (zie vorige stap)
- De verbinding met de kaart sluiten, zodat een volgende kaart gelezen kan worden
#include <SPI.h>
#include <MFRC522.h>
#define ResetPin 9
#define SlaveSelectPin 10
MFRC522 mfrc522(SlaveSelectPin, ResetPin); // Create MFRC522 instance.
MFRC522::MIFARE_Key key; // Crytpokey for accessing blocks
void setup() {
Serial.begin(9600); // Initialize serial communications with the PC
while (!Serial); // Do nothing if no serial port is opened (added for Arduinos based on ATMEGA32U4)
SPI.begin(); // Init SPI bus
mfrc522.PCD_Init(); // Init MFRC522 Module
// Set default Crypto key for the trailer block (factory default)
for (byte i = 0; i < 6; i++) {
key.keyByte[i] = 0xFF;
}
Serial.println(F("WARNING: Data will be written to the PICC, in sector #1"));
}
void loop() {
// Reset the loop if no new card is presented
if (!mfrc522.PICC_IsNewCardPresent()) return;
// Select one of the cards
if (!mfrc522.PICC_ReadCardSerial()) return;
/*** [1] Show some basic information of the presented card ***/
Serial.print(F("Card UID:")); dump_byte_array(mfrc522.uid.uidByte, mfrc522.uid.size);
Serial.println();
Serial.print(F("PICC type: ")); MFRC522::PICC_Type piccType = mfrc522.PICC_GetType(mfrc522.uid.sak);
Serial.println(mfrc522.PICC_GetTypeName(piccType));
/*** [2] Check if this card is compatible with this software ***/
if ( piccType != MFRC522::PICC_TYPE_MIFARE_MINI
&& piccType != MFRC522::PICC_TYPE_MIFARE_1K
&& piccType != MFRC522::PICC_TYPE_MIFARE_4K) {
Serial.println(F("This sample only works with MIFARE Classic cards."));
return;
}
/*** [3] Preparing data for the PICC ***/
// To avoid damage to the PICC never write data to Sector #0
// In this example we will write data to Sector #1
// Covering Block #4 up to and including Block #7
byte sector = 1;
byte blockAddr = 4; // Sector #1, Block #0
byte dataBlock[] = {
0xE5, 0x02, 0x03, 0x04, // 1, 2, 3, 4,
0x05, 0x06, 0x07, 0x08, // 5, 6, 7, 8,
0x09, 0x0a, 0xff, 0x0b, // 9, 10, 255, 11,
0x0c, 0x0d, 0x0e, 0x0f // 12, 13, 14, 15
};
byte trailerBlock = 7; // Last block in Sector #1
MFRC522::StatusCode status;
byte buffer[18];
byte size = sizeof(buffer);
/*** [4] Accessing Sector #1 ***/
Serial.println(F("Accessing Sector #1 ..."));
status = (MFRC522::StatusCode) mfrc522.PCD_Authenticate(MFRC522::PICC_CMD_MF_AUTH_KEY_A, trailerBlock, &key, &(mfrc522.uid));
if (status != MFRC522::STATUS_OK) {
Serial.print(F("PCD_Authenticate() failed: "));
Serial.println(mfrc522.GetStatusCodeName(status));
return;
}
/*** [5] Reading data from Sector #1 ***/
// Print the data in the sector to the Serial Monitor
Serial.println(F("Current data in sector:"));
mfrc522.PICC_DumpMifareClassicSectorToSerial(&(mfrc522.uid), &key, sector);
Serial.println();
// Read data from the block we are interested in
Serial.print(F("Reading data from block ")); Serial.print(blockAddr);
Serial.println(F(" ..."));
status = (MFRC522::StatusCode) mfrc522.MIFARE_Read(blockAddr, buffer, &size);
if (status != MFRC522::STATUS_OK) {
Serial.print(F("MIFARE_Read() failed: "));
Serial.println(mfrc522.GetStatusCodeName(status));
}
// Show data present in block 4 (Sector #1, Block #0)
Serial.print(F("Data in block ")); Serial.print(blockAddr); Serial.println(F(":"));
dump_byte_array(buffer, 16); Serial.println();
Serial.println();
/*** [6] Write data to block 4 (Sector #1, Block #0) ***/
Serial.print(F("Writing data into block ")); Serial.print(blockAddr);
Serial.println(F(" ..."));
dump_byte_array(dataBlock, 16); Serial.println();
status = (MFRC522::StatusCode) mfrc522.MIFARE_Write(blockAddr, dataBlock, 16);
if (status != MFRC522::STATUS_OK) {
Serial.print(F("MIFARE_Write() failed: "));
Serial.println(mfrc522.GetStatusCodeName(status));
}
Serial.println();
/*** [7] Read data from block 4 (Sector #1, Block #0) ***/
Serial.print(F("Reading data from block ")); Serial.print(blockAddr);
Serial.println(F(" ..."));
status = (MFRC522::StatusCode) mfrc522.MIFARE_Read(blockAddr, buffer, &size);
if (status != MFRC522::STATUS_OK) {
Serial.print(F("MIFARE_Read() failed: "));
Serial.println(mfrc522.GetStatusCodeName(status));
}
Serial.print(F("Data in block ")); Serial.print(blockAddr); Serial.println(F(":"));
dump_byte_array(buffer, 16); Serial.println();
// Check that data in block is what we have written
// by counting the number of bytes that are equal
Serial.println(F("Checking result..."));
byte count = 0;
for (byte i = 0; i < 16; i++) {
// Compare buffer (= what we've read) with dataBlock (= what we've written)
if (buffer[i] == dataBlock[i])
count++;
}
Serial.print(F("Number of bytes that match = ")); Serial.println(count);
if (count == 16) {
Serial.println(F("Success :-)"));
} else {
Serial.println(F("Failure, no match :-("));
Serial.println(F(" perhaps the write didn't work properly..."));
}
Serial.println();
// Dump the sector data
Serial.println(F("Current data in sector:"));
mfrc522.PICC_DumpMifareClassicSectorToSerial(&(mfrc522.uid), &key, sector);
Serial.println();
/*** [8] Close Connection ***/
mfrc522.PICC_HaltA(); // Halt the PICC before stopping the encrypted session.
mfrc522.PCD_StopCrypto1(); // Stop encryption on PCD
}
/*** Helper function to dump a byte array as hex values to Serial Monitor. ***/
void dump_byte_array(byte *buffer, byte bufferSize) {
for (byte i = 0; i < bufferSize; i++) {
Serial.print(buffer[i] < 0x10 ? " 0" : " ");
Serial.print(buffer[i], HEX);
}
}