MFRC522: RFID cards and key fobs on an RC522
The MFRC522 library by Miguel Balboa drives the NXP MFRC522 reader on the common RC522 boards that come with a white card and a blue key fob in starter kits. The reader works at 13.56 MHz and talks to the board over SPI; the library handles the radio exchange with MIFARE Classic, MIFARE Ultralight and NTAG cards.
Built in on Mokxi: #include <MFRC522.h> and it builds, with nothing to install. Free, and no account needed.
What MFRC522 does
Most projects only need the card’s UID, a 4 or 7-byte serial number. The loop pattern is fixed: PICC_IsNewCardPresent() checks whether a card has entered the field, PICC_ReadCardSerial() reads its UID into mfrc522.uid, and PICC_HaltA() puts it to sleep so it is not read again on every pass.
Reading or writing the data blocks of a MIFARE Classic card needs authentication with a key first, the factory key being six bytes of 0xFF. The RC522 runs on 3.3 V: on a 5 V board power it from the 3.3 V pin, as every tutorial does.
| Library Manager name | MFRC522 |
|---|---|
| Author | GithubCommunity (miguelbalboa) |
| Include | #include <MFRC522.h> |
| Boards | every board Mokxi compiles for but ATtiny85 |
| In the simulator | Simulated: it runs against the part the way it does on the bench. |
| Parts it drives | RFID reader, MFRC522 |
Install it
It builds on every board Mokxi compiles for but ATtiny85.
In Mokxi it is built in: #include <MFRC522.h> and the sketch compiles, with no download, no zip and no Library Manager.
On a real board, install "MFRC522" by GithubCommunity (miguelbalboa) from the Arduino IDE’s Library Manager (Sketch, Include Library, Manage Libraries), or add MFRC522 to lib_deps in PlatformIO. Mokxi follows the calls of release 1.4.11, so a sketch written here builds there too.
What to know in the simulator: The part’s cards answer READ and WRITE: increment, decrement, restore and transfer, the UID backdoor and NTAG passwords get the refusal a genuine card gives.
ESP32-C3 · Arduino Uno · Arduino Nano · Arduino Mega 2560 · Arduino Leonardo · SparkFun Pro Micro · Arduino Micro · ESP32-C6 · Raspberry Pi Pico · Raspberry Pi Pico W · Seeed XIAO SAMD21 · STM32 · STM32 Nucleo-F411RE · STM32 Blue Pill · micro:bit V2 · Arduino Uno R4 · ESP32 DevKit · ESP32-S3-DevKitC-1 · ESP8266 NodeMCU · Arduino Pro Mini 3.3 V · Seeed XIAO ESP32-C3 · ESP32-C3 SuperMini · Seeed XIAO ESP32-C6 · ESP32-DevKitC V4 · LOLIN32 Lite · Wemos D1 R32 · Cheap Yellow Display · TTGO T-Display · Seeed XIAO ESP32-S3 · Arduino Nano ESP32 · Arduino Nano RP2040 Connect · Seeed XIAO RP2040 · Waveshare RP2040-Zero · Arduino Uno R4 WiFi
The calls you will use
In the order a sketch meets them.
MFRC522 mfrc522(SS_PIN, RST_PIN)
Creates the reader with its chip select and reset pins (10 and 9 in most Uno tutorials).
mfrc522.PCD_Init()
Resets the reader and turns the antenna on. Call SPI.begin() first.
SPI.begin();
mfrc522.PCD_Init();
mfrc522.PCD_DumpVersionToSerial();mfrc522.PICC_IsNewCardPresent()
True when a new card is in the field.
mfrc522.PICC_ReadCardSerial()
Reads the card’s UID into mfrc522.uid. Returns false if the read failed.
mfrc522.uid.uidByte[i]
The UID bytes, with mfrc522.uid.size saying how many (4, 7 or 10).
mfrc522.PICC_HaltA()
Puts the card to sleep, so the same card is not read again until it leaves and returns.
mfrc522.PCD_Authenticate(MFRC522::PICC_CMD_MF_AUTH_KEY_A, block, &key, &(mfrc522.uid))
Unlocks a MIFARE Classic sector with key A before reading or writing it. key is a MFRC522::MIFARE_Key.
mfrc522.MIFARE_Read(block, buffer, &size)
Reads a 16-byte block into an 18-byte buffer. MIFARE_Write(block, data, 16) writes one.
mfrc522.PCD_StopCrypto1()
Ends the authenticated session after reading or writing, so the next card can be read.
Example: RFID door
On the Arduino Uno R3. It runs in the browser exactly as printed.
// RFID door: two of the four cards open it, the other two do not.
//
// Tap a card beside the reader to lay it on the antenna. The sketch reads its
// UID, looks it up in the list below, and lights the green LED for a card on
// the list or the red one for a card that is not. Every UID is printed, so a
// new card is added by tapping it, copying its UID from the serial monitor
// into ALLOWED, and running again.
//
// PICC_HaltA() at the end puts the card to sleep: it stays quiet until it
// leaves the field. That is why a card left on the reader opens the door once
// and not once a loop. Tap it off and on again to read it again.
#include <SPI.h>
#include <MFRC522.h>
MFRC522 reader(10, 9); // SDA (chip select) on 10, RST on 9
const int GREEN_LED = 7;
const int RED_LED = 6;
// The cards that open the door: the white card and the blue key fob.
const byte ALLOWED[][4] = {
{0xC3, 0x5A, 0x1E, 0x94},
{0x7B, 0x02, 0xD4, 0x19},
};
const int ALLOWED_COUNT = sizeof(ALLOWED) / sizeof(ALLOWED[0]);
bool onTheList()
{
if (reader.uid.size != 4) {
return false; // the seven-byte sticker is never on it
}
for (int card = 0; card < ALLOWED_COUNT; card++) {
bool same = true;
for (int i = 0; i < 4; i++) {
if (reader.uid.uidByte[i] != ALLOWED[card][i]) {
same = false;
}
}
if (same) {
return true;
}
}
return false;
}
void setup()
{
Serial.begin(9600);
pinMode(GREEN_LED, OUTPUT);
pinMode(RED_LED, OUTPUT);
SPI.begin();
reader.PCD_Init();
reader.PCD_DumpVersionToSerial();
Serial.println("Tap a card on the reader.");
}
void loop()
{
if (!reader.PICC_IsNewCardPresent() || !reader.PICC_ReadCardSerial()) {
return;
}
Serial.print("UID:");
for (byte i = 0; i < reader.uid.size; i++) {
Serial.print(reader.uid.uidByte[i] < 0x10 ? " 0" : " ");
Serial.print(reader.uid.uidByte[i], HEX);
}
Serial.println();
int led = onTheList() ? GREEN_LED : RED_LED;
Serial.println(led == GREEN_LED ? "Welcome in." : "Not this card.");
reader.PICC_HaltA();
digitalWrite(led, HIGH);
delay(1500);
digitalWrite(led, LOW);
}Open it in the editor, wired and ready to run · RFID door: the project page
Common errors and how to fix them
Firmware Version: 0x0 = (unknown)
PCD_DumpVersionToSerial() got no answer over SPI. Check the SPI wiring (on an Uno MOSI 11, MISO 12, SCK 13), the SS and RST pins in the constructor, and that the module is on 3.3 V.
Nothing happens when a card is held to the reader
The card must be within about 3 cm, flat to the antenna. Check SPI.begin() runs before PCD_Init(), and that the loop returns early only when PICC_IsNewCardPresent() is false.
PCD_Authenticate() failed: Timeout in communication.
The key or the block is wrong, or the card is not MIFARE Classic. Use the factory key (six 0xFF bytes), authenticate the sector the block is in, and call PCD_StopCrypto1() after each card.
Projects that use MFRC522
Built-in projects that include it. Each page has the full sketch and opens in the editor, already wired.
Keep going
Parts
More communication libraries
Try MFRC522 without installing anything
Open the example, change the sketch, and keep your version in a free account.