The RC522 is the cheapest way to add card or key-tag access to a project, and on a NodeMCU it pairs naturally with Wi-Fi for attendance logs or door locks that report to a server.
It uses SPI. The ESP8266 has one SPI bus free for you — D5, D6, D7 — plus D8 as chip select. Reset goes to D0, the odd pin that can’t do PWM or interrupts but is fine as a plain output. Both parts are 3.3 V, so the wiring is direct.
Wiring
| NodeMCU ESP8266 | RC522 RFID reader (MFRC522, 13.56 MHz) | Wire | Notes |
|---|---|---|---|
| 3V3 | 3.3V | red | 3.3 V only — never VIN. |
| GND | GND | black | |
| D5 | SCK | yellow | GPIO14, HSPI clock. |
| D6 | MISO | blue | GPIO12, HSPI MISO. |
| D7 | MOSI | green | GPIO13, HSPI MOSI. |
| D8 | SDA | purple | SDA is the RC522’s chip select. D8 (GPIO15) is the usual HSPI CS. |
| D0 | RST | orange | GPIO16 as a plain output. IRQ stays unconnected. |
3.3 V only part, 3.3 V board. Power the RC522 from 3.3 V — never 5 V. The MFRC522 chip’s pins are not rated for 5 V either: many people wire it straight to an Uno and it works for a while, but for a build that lasts, drop the Uno’s SCK, MOSI, SDA (SS) and RST signals to 3.3 V with a level shifter or dividers. ESP32 and Pico connect directly.
Board quirks
- The ESP8266’s free SPI bus (HSPI) is fixed to D5 = SCK, D6 = MISO, D7 = MOSI. The other SPI pins (SD0–SD3, CMD, CLK) belong to the flash chip — never wire anything there.
- D8 (GPIO15) must be LOW at reset. It works as chip select because the board pulls it down and the RC522 doesn’t pull it up. If your board stops booting with the reader attached, move SDA to D2 and change
SS_PIN. - RST is on D0 (GPIO16). D0 has no PWM or interrupts, but a plain reset output is exactly what it is good for — and it keeps D1/D2 free for an I2C display.
- The RC522 and the ESP8266 are both 3.3 V parts, so no level shifting is needed — the opposite of the Uno, where the signals must be dropped to 3.3 V.
- Keep the reader’s antenna away from the NodeMCU’s Wi-Fi antenna end and from metal. Range is 2–4 cm with the white card.
Code
// MFRC522 RFID reader (RC522 module) on a NodeMCU (ESP8266), hardware SPI (HSPI).
// 3.3V → 3V3, GND → GND, SCK → D5 (GPIO14), MISO → D6 (GPIO12), MOSI → D7 (GPIO13),
// SDA (chip select) → D8 (GPIO15), RST → D0 (GPIO16). IRQ is not used.
#include <SPI.h>
#include <MFRC522.h>
const uint8_t SS_PIN = D8; // GPIO15: the board's pull-down keeps it LOW at boot, which is what it needs
const uint8_t RST_PIN = D0; // GPIO16: fine as a plain output, and keeps D1/D2 free for I2C
MFRC522 rfid(SS_PIN, RST_PIN);
void setup() {
Serial.begin(115200);
Serial.println();
SPI.begin();
rfid.PCD_Init();
delay(10);
rfid.PCD_DumpVersionToSerial(); // 0x92 = v2.0, 0x91 = v1.0, 0x88 = clone; 0x00/0xFF = wiring problem
Serial.println("Tap a card or tag");
}
void loop() {
if (!rfid.PICC_IsNewCardPresent() || !rfid.PICC_ReadCardSerial()) {
delay(50);
return;
}
Serial.print("UID:");
for (byte i = 0; i < rfid.uid.size; i++) Serial.printf(" %02X", rfid.uid.uidByte[i]);
Serial.print(" (");
Serial.print(rfid.PICC_GetTypeName(rfid.PICC_GetType(rfid.uid.sak)));
Serial.println(")");
rfid.PICC_HaltA();
rfid.PCD_StopCrypto1();
}// MFRC522 RFID reader (RC522 module) on a NodeMCU (ESP8266), hardware SPI (HSPI).
// 3.3V → 3V3, GND → GND, SCK → D5 (GPIO14), MISO → D6 (GPIO12), MOSI → D7 (GPIO13),
// SDA (chip select) → D8 (GPIO15), RST → D0 (GPIO16). IRQ is not used.
#include <SPI.h>
#include <MFRC522.h>
const uint8_t SS_PIN = D8; // GPIO15: the board's pull-down keeps it LOW at boot, which is what it needs
const uint8_t RST_PIN = D0; // GPIO16: fine as a plain output, and keeps D1/D2 free for I2C
MFRC522 rfid(SS_PIN, RST_PIN);
void setup() {
Serial.begin(115200);
Serial.println();
SPI.begin();
rfid.PCD_Init();
delay(10);
rfid.PCD_DumpVersionToSerial(); // 0x92 = v2.0, 0x91 = v1.0, 0x88 = clone; 0x00/0xFF = wiring problem
Serial.println("Tap a card or tag");
}
void loop() {
if (!rfid.PICC_IsNewCardPresent() || !rfid.PICC_ReadCardSerial()) {
delay(50);
return;
}
Serial.print("UID:");
for (byte i = 0; i < rfid.uid.size; i++) Serial.printf(" %02X", rfid.uid.uidByte[i]);
Serial.print(" (");
Serial.print(rfid.PICC_GetTypeName(rfid.PICC_GetType(rfid.uid.sak)));
Serial.println(")");
rfid.PICC_HaltA();
rfid.PCD_StopCrypto1();
}Library: MFRC522 (GithubCommunity) — compiled with MFRC522 1.4.12.
Expected serial output
Firmware Version: 0x92 = v2.0
Tap a card or tag
UID: 4A 3F 9C 1B (MIFARE 1KB)
UID: 04 5E 21 7A 6B 4F 80 (MIFARE Ultralight or Ultralight C)Firmware Version: 0x92 = v2.0 Tap a card or tag UID: 4A 3F 9C 1B (MIFARE 1KB) UID: 04 5E 21 7A 6B 4F 80 (MIFARE Ultralight or Ultralight C)
Common errors
“Firmware Version: 0x0 = (unknown)” or 0xFF
The ESP8266 can’t talk to the chip: check D5/D6/D7 are not swapped, SDA is on D8 and 3.3V is powered. Full fix.
Board won’t boot with the reader connected
Something is holding D8 high at reset. Move SDA (chip select) to D2 and set SS_PIN = D2.
Reads cards only sometimes
Weak 3V3 supply or long jumper wires. Keep SPI wires under 10 cm and add a 10 µF capacitor across 3.3V/GND at the reader.