Learn how to interface the MFRC522 RFID reader module with the ESP8266 NodeMCU board. You’ll learn how to get raw RFID data, get the RFID card UID, and add personal data to the RFID cards. We’ll use the Arduino_MFRC522v2 library and the ESP8266 will be programmed using Arduino IDE.
We have a similar guide for the ESP32 with MFRC522 RFID Reader/Writer (Arduino IDE)
In summary, in this tutorial we’ll cover:
- Introduction to the MFRC522 RFID Reader/Writer
- Wire the MFRC522 RFID Reader/Writer module to the ESP8266
- Read RFID card raw data
- Read the RFID card UID
- Write/Read personal data to and from the RFID card
MFRC522 RFID Reader/Writer
In this tutorial, we’ll be using the MFRC522 RFID reader/writer and that’s the one we recommend you getting to interface with the ESP8266.
RFID means radio-frequency identification. RFID uses electromagnetic fields to transfer data over short distances and it’s useful to identify people, make transactions, etc. Some stores also use RFID tags on their products’ labels to identify them.
An RFID system needs tags and a reader:
- Tags (proximity integrated circuit cards—PICC) are attached to the object to be identified, in this example, we have a keychain and an electromagnetic card that come with the MFRC522 RFID Reader/Writer module. Each tag has a unique identification (UID).
- Reader/Writer (proximity coupling device—PCD) is a two-way radio transmitter-receiver that sends a signal to the tag and reads its response.
The MFRC522 RFID reader works at 3.3V and supports SPI and I2C communication protocols. The library we’re going to use to control the RFID reader supports both protocols, but we’ll be using the SPI.
Parts Required
Here’s a list of the required components for this project:
- ESP8266 (read Best ESP8266 boards comparison)
- MFRC522 RFID Reader/Writer + tags
- Breadboard
- Jumper wires
You can use the preceding links or go directly to MakerAdvisor.com/tools to find all the parts for your projects at the best price!
To learn more about the RFID reader with the Arduino read: Security Access using MFRC522 RFID Reader with Arduino
Installing the Arduino_MFRC522v2 Library
For this tutorial, we’ll use the MFRC522v2.h library to control the RFID reader. In the Arduino IDE, go to Sketch > Include Library > Manage Libraries or click on the Libary Manager icon at the left sidebar.
Search for MFRC522v2 and install the library by GithubCommunity.
MFRC522 RFID Reader/Writer Pinout and Wiring to the ESP8266 NodeMCU
We’ll connect the MFRC522 RFID Reader using the ESP8266 NodeMCU default SPI pins. You can use the following table.
MFRC522 RFID Reader | ESP8266 | Description |
---|---|---|
SDA | GPIO 15 (D8) | SPI signal input, I2C data line, or UART data input |
SCK | GPIO 14 (D5) | SPI clock |
MOSI | GPIO 13 (D7) | SPI data input |
MISO | GPIO 12 (D6) | SPI master-in-slave-out, I2C serial clock, or UART serial output |
IRQ | Don’t connect | Interrupt pin; signals the microcontroller when an RFID tag is nearby |
GND | GND | |
RST | GPIO 0 (D3) | LOW signal to put the module in power-down mode; send a HIGH signal to reset the module |
3.3V | 3.3V | Power supply (2.5-3.3V) |
Note: this library is also compatible with the ESP32, Arduino, and other boards. If you are using a different board, you can check the recommended library pin assigment.
Read RFID Card Raw Data – Code
The following example reads raw data from the RFID tag. With this example, you’ll better understand how data is stored on the MIFARE 1K tags.
/*
Rui Santos & Sara Santos - Random Nerd Tutorials
Complete project details at https://RandomNerdTutorials.com/esp8266-nodemcu-mfrc522-rfid-reader-arduino/
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files.
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
*/
#include <MFRC522v2.h>
#include <MFRC522DriverSPI.h>
//#include <MFRC522DriverI2C.h>
#include <MFRC522DriverPinSimple.h>
#include <MFRC522Debug.h>
// Learn more about using SPI/I2C or check the pin assigment for your board: https://github.com/OSSLibraries/Arduino_MFRC522v2#pin-layout
MFRC522DriverPinSimple ss_pin(15);
MFRC522DriverSPI driver{ss_pin}; // Create SPI driver
//MFRC522DriverI2C driver{}; // Create I2C driver
MFRC522 mfrc522{driver}; // Create MFRC522 instance
void setup() {
Serial.begin(115200); // Initialize serial communication
while (!Serial); // Do nothing if no serial port is opened (added for Arduinos based on ATMEGA32U4).
mfrc522.PCD_Init(); // Init MFRC522 board.
MFRC522Debug::PCD_DumpVersionToSerial(mfrc522, Serial); // Show details of PCD - MFRC522 Card Reader details.
Serial.println(F("Scan PICC to see UID, SAK, type, and data blocks..."));
}
void loop() {
// Reset the loop if no new card present on the sensor/reader. This saves the entire process when idle.
if (!mfrc522.PICC_IsNewCardPresent()) {
return;
}
// Select one of the cards.
if (!mfrc522.PICC_ReadCardSerial()) {
return;
}
// Dump debug info about the card; PICC_HaltA() is automatically called.
MFRC522Debug::PICC_DumpToSerial(mfrc522, Serial, &(mfrc522.uid));
delay(2000);
}
After wiring the circuit, upload the previous code to your board.
After uploading, open the Serial Monitor at a baud rate of 115200. Approximate your tag to the reader and see the tag info being displayed.
It displays the card UID, the tag type, and the memory blocks. The tag is of type MIFARE with 1KB of memory.
Here are some essential aspects you need to take into account about how data is stored on the MIFARE 1K tag.
Memory Layout
The memory is organized into 16 sectors (0 to 15), and each sector is divided into 4 blocks (0 to 3), which gives a total of 64 blocks. Each block can store 16 bytes of data (0 to 15).
Manufacturer Block
Sector 0, block 0 stores the UID (first 4 bytes), a CRC check byte, and manufacturer data. This is read-only and cannot be changed (except on UID-changeable cards). As you can see from the results in the Serial Monitor, the UUID of our tag is 82 72 9F 0B.
Memory Storage and the Sector Trailer
The first three blocks of each sector can be used for storing data. The last block of each sector is a sector trailer. This sector trailer stores the 2 keys or passwords and controls access to the rest of the blocks in the sector. For example, block number 7 controls block 4, 5 and 6). You should not write on these sectors, otherwise, you’ll probably brick your card and it will become unusable.
In summary, the Mifare 1K cards have a net storage capacity of:
(16 sectors/card x 3 data blocks/sector X 16 bytes/block) - 16 bytes (first block) = 752 bytes/card
There are 16 sectors with 4 blocks each (64 blocks total). Each block is 16 bytes, giving 1024 bytes in total (1 KB). However, 16 blocks (one in each sector) are sector trailers that store access keys and permissions, not user data. This leaves 48 blocks available for user data. Subtracting 16 bytes for the read-only manufacturer block (Sector 0, Block 0), the effective user storage is 752 bytes.
Read the RFID Card UID – Code
The following example only reads the UID of the RFID tag. This can be useful if you just want to identify the card without caring about the rest of the stored data.
/*
Rui Santos & Sara Santos - Random Nerd Tutorials
Complete project details at https://RandomNerdTutorials.com/esp8266-nodemcu-mfrc522-rfid-reader-arduino/
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files.
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
*/
#include <MFRC522v2.h>
#include <MFRC522DriverSPI.h>
//#include <MFRC522DriverI2C.h>
#include <MFRC522DriverPinSimple.h>
#include <MFRC522Debug.h>
// Learn more about using SPI/I2C or check the pin assigment for your board: https://github.com/OSSLibraries/Arduino_MFRC522v2#pin-layout
MFRC522DriverPinSimple ss_pin(15);
MFRC522DriverSPI driver{ss_pin}; // Create SPI driver
//MFRC522DriverI2C driver{}; // Create I2C driver
MFRC522 mfrc522{driver}; // Create MFRC522 instance
void setup() {
Serial.begin(115200); // Initialize serial communication
while (!Serial); // Do nothing if no serial port is opened (added for Arduinos based on ATMEGA32U4).
mfrc522.PCD_Init(); // Init MFRC522 board.
MFRC522Debug::PCD_DumpVersionToSerial(mfrc522, Serial); // Show details of PCD - MFRC522 Card Reader details.
Serial.println(F("Scan PICC to see UID"));
}
void loop() {
// Reset the loop if no new card present on the sensor/reader. This saves the entire process when idle.
if (!mfrc522.PICC_IsNewCardPresent()) {
return;
}
// Select one of the cards.
if (!mfrc522.PICC_ReadCardSerial()) {
return;
}
Serial.print("Card UID: ");
MFRC522Debug::PrintUID(Serial, (mfrc522.uid));
Serial.println();
// Save the UID on a String variable
String uidString = "";
for (byte i = 0; i < mfrc522.uid.size; i++) {
if (mfrc522.uid.uidByte[i] < 0x10) {
uidString += "0";
}
uidString += String(mfrc522.uid.uidByte[i], HEX);
}
Serial.println(uidString);
}
This code is quite simple to understand. First, you initialize the reader on the setup().
mfrc522.PCD_Init(); // Init MFRC522 board.
MFRC522Debug::PCD_DumpVersionToSerial(mfrc522, Serial); // Show details of PCD - MFRC522 Card Reader details.
Serial.println(F("Scan PICC to see UID"));
Then, in the loop(), check if there is a card present.
// Reset the loop if no new card present on the sensor/reader. This saves the entire process when idle.
if (!mfrc522.PICC_IsNewCardPresent()) {
return;
}
If so, read the card.
// Select one of the cards.
if (!mfrc522.PICC_ReadCardSerial()) {
return;
}
Finally, print the UID and save it on a variable.
Serial.print("Card UID: ");
MFRC522Debug::PrintUID(Serial, (mfrc522.uid));
Serial.println();
// Save the UID on a String variable
String uidString = "";
for (byte i = 0; i < mfrc522.uid.size; i++) {
if (mfrc522.uid.uidByte[i] < 0x10) {
uidString += "0";
}
uidString += String(mfrc522.uid.uidByte[i], HEX);
}
Serial.println(uidString);
}
Upload the code to your board. Open the Serial Monitor at a baud rate of 115200.
Swipe different tags on the reader and see their unique UID being printed.
Write/Read Personal Data to and from the RFID Card – Code
In this example, we’ll show you how to write custom data on specific blocks. Then, we’ll also show you how to read the data from those same blocks.
/*
Rui Santos & Sara Santos - Random Nerd Tutorials
Complete project details at https://RandomNerdTutorials.com/esp8266-nodemcu-mfrc522-rfid-reader-arduino/
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files.
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
*/
#include <MFRC522v2.h>
#include <MFRC522DriverSPI.h>
//#include <MFRC522DriverI2C.h>
#include <MFRC522DriverPinSimple.h>
#include <MFRC522Debug.h>
// Learn more about using SPI/I2C or check the pin assigment for your board: https://github.com/OSSLibraries/Arduino_MFRC522v2#pin-layout
MFRC522DriverPinSimple ss_pin(15);
MFRC522DriverSPI driver{ss_pin}; // Create SPI driver
//MFRC522DriverI2C driver{}; // Create I2C driver
MFRC522 mfrc522{driver}; // Create MFRC522 instance
MFRC522::MIFARE_Key key;
byte blockAddress = 2;
byte newBlockData[17] = {"Rui Santos - RNT"};
//byte newBlockData[16] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; // CLEAR DATA
byte bufferblocksize = 18;
byte blockDataRead[18];
void setup() {
Serial.begin(115200); // Initialize serial communication
while (!Serial); // Do nothing if no serial port is opened (added for Arduinos based on ATMEGA32U4).
mfrc522.PCD_Init(); // Init MFRC522 board.
Serial.println(F("Warning: this example overwrites a block in your card, use with care!"));
// Prepare key - all keys are set to FFFFFFFFFFFF at chip delivery from the factory.
for (byte i = 0; i < 6; i++) {
key.keyByte[i] = 0xFF;
}
}
void loop() {
// Check if a new card is present
if (!mfrc522.PICC_IsNewCardPresent() || !mfrc522.PICC_ReadCardSerial()) {
delay(500);
return;
}
// Display card UID
Serial.print("----------------\nCard UID: ");
MFRC522Debug::PrintUID(Serial, (mfrc522.uid));
Serial.println();
// Authenticate the specified block using KEY_A = 0x60
if (mfrc522.PCD_Authenticate(0x60, blockAddress, &key, &(mfrc522.uid)) != 0) {
Serial.println("Authentication failed.");
return;
}
// Write data to the specified block
if (mfrc522.MIFARE_Write(blockAddress, newBlockData, 16) != 0) {
Serial.println("Write failed.");
} else {
Serial.print("Data written successfully in block: ");
Serial.println(blockAddress);
}
// Authenticate the specified block using KEY_A = 0x60
if (mfrc522.PCD_Authenticate(0x60, blockAddress, &key, &(mfrc522.uid)) != 0) {
Serial.println("Authentication failed.");
return;
}
// Read data from the specified block
if (mfrc522.MIFARE_Read(blockAddress, blockDataRead, &bufferblocksize) != 0) {
Serial.println("Read failed.");
} else {
Serial.println("Read successfully!");
Serial.print("Data in block ");
Serial.print(blockAddress);
Serial.print(": ");
for (byte i = 0; i < 16; i++) {
Serial.print((char)blockDataRead[i]); // Print as character
}
Serial.println();
}
// Halt communication with the card
mfrc522.PICC_HaltA();
mfrc522.PCD_StopCrypto1();
delay(2000); // Delay for readability
}
How Does the Code Work?
We start by including the necessary libraries to set up the RFID reader.
#include <MFRC522v2.h>
#include <MFRC522DriverSPI.h>
//#include <MFRC522DriverI2C.h>
#include <MFRC522DriverPinSimple.h>
#include <MFRC522Debug.h>
It defines the CS (Chip Select) pin as pin 15, which will be used for SPI communication with the reader.
// Learn more about using SPI/I2C or check the pin assigment for your board: https://github.com/OSSLibraries/Arduino_MFRC522v2#pin-layout
MFRC522DriverPinSimple ss_pin(15);
MFRC522DriverSPI driver{ss_pin}; // Create SPI driver
//MFRC522DriverI2C driver{}; // Create I2C driver
MFRC522 mfrc522{driver}; // Create MFRC522 instance
MFRC522::MIFARE_Key key;
Then, we define a variable called blockAddress. This specifies the block on the RFID tag where data will be written or read. In this example, blockAddress is set to 2, which means the code will interact with block 2 of the card’s memory. You can change this value if you want to write to a different block.
byte blockAddress = 2;
Important: the last block of each sector is a sector trailer. You should not write on that sector, otherwise, you’ll probably brick your card.
Next, newBlockData[17] holds the data you want to write to the card. Right now, it’s set to Rui Santos – RNT, but you can change it. Make sure it is no longer than 16 bytes.
byte newBlockData[17] = {"Rui Santos - RNT"};
If you want to clear the block data, you can pass the following bytes array:
byte newBlockData[16] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
In the setup(), initialize the MFRC522 module.
mfrc522.PCD_Init(); // Init MFRC522 board.
The default key for the RFID card is also set on the following lines. By default, all bytes are 0xFF for the factory key. This key allows access to the card’s data blocks.
// Prepare key - all keys are set to FFFFFFFFFFFF at chip delivery from the factory.
for (byte i = 0; i < 6; i++) {
key.keyByte[i] = 0xFF;
}
The loop() checks if a new RFID card is detected. If a card is present, it reads and displays the card’s UID.
if (!mfrc522.PICC_IsNewCardPresent() || !mfrc522.PICC_ReadCardSerial()) {
delay(500);
return;
}
// Display card UID
Serial.print("----------------\nCard UID: ");
MFRC522Debug::PrintUID(Serial, (mfrc522.uid));
Serial.println();
Next, the code tries to authenticate a specific block on the card using the default key (in this case, block 2).
// Authenticate the specified block using KEY_A = 0x60
if (mfrc522.PCD_Authenticate(0x60, blockAddress, &key, &(mfrc522.uid)) != 0) {
Serial.println("Authentication failed.");
return;
}
Note: 0x60 is a command that specifies the use of KEY_A to authenticate. KEY_A is one of two keys (KEY_A and KEY_B) available on RFID cards, each offering different permissions. Using 0x60 means the code is attempting to authenticate with KEY_A, which by default is 0xFF 0xFF 0xFF 0xFF 0xFF on MIFARE RFID cards.
If authentication is successful, it writes some data (saved on the newBlockData) to that block.
// Write data to the specified block
if (mfrc522.MIFARE_Write(blockAddress, newBlockData, 16) != 0) {
Serial.println("Write failed.");
} else {
Serial.print("Data written successfully in block: ");
Serial.println(blockAddress);
}
After writing, it reads the data back from the block and prints it to the Serial Monitor.
// Read data from the specified block
if (mfrc522.MIFARE_Read(blockAddress, blockDataRead, &bufferblocksize) != 0) {
Serial.println("Read failed.");
} else {
Serial.println("Read successfully!");
Serial.print("Data in block ");
Serial.print(blockAddress);
Serial.print(": ");
for (byte i = 0; i < 16; i++) {
Serial.print((char)blockDataRead[i]); // Print as character
}
Serial.println();
}
Finally, the code halts communication with the card and stops encryption.
// Halt communication with the card
mfrc522.PICC_HaltA();
mfrc522.PCD_StopCrypto1();
Testing the Example
In this example, we stored the following personal data “Rui Santos – RNT” in block number 2 on two different RFID cards.
Other Useful Examples
There are few examples that come with the Arduino_MFRC522v2 library that might be helpful. In the Hack submenu, you can find the ChangeUID and FixBrickedUID examples.
Important: most RFID cards don’t allow you to modify the UID. This code only works on specific MIFARE Classic cards that have a writable UID block. Most RFID cards have the UID set as read-only, so if you try to change the UID it won’t work.
Wrapping Up
In this guide, you learned how to interface the MFRC522 RFID Reader/Writer module with the ESP8266. We’ve taken a look at how storage on Mifare 1K cards works and how to dump the information of the cards. We also learned how to get the card UID, write new data on a specific block and how to read data from a specific block.
We hope you found this guide for the ESP8266 with MFRC522 RFID Reader/Writer useful. We have a similar guide for the Arduino board:
If you would like to learn more about the ESP8266, and for inspiration for new projects, make sure to take a look at our resources:
Thanks for reading.