An RC522 reader on a D1 mini is the core of a Wi-Fi attendance register or a door lock that logs who came in. It talks SPI, and the ESP8266’s hardware SPI is fixed to D5, D6 and D7, with D8 as chip select and D0 for reset.
That uses six of the D1 mini’s eleven pins, so it is worth planning: D1/D2 stay free for an OLED or LCD, and nothing touches the boot pins D3 and D4. The sketch prints each card’s UID and checks it against one allowed card — paste your own UID into ALLOWED_UID.
Wiring
| Wemos D1 mini | RC522 RFID reader (MFRC522, 13.56 MHz) | Wire | Notes |
|---|---|---|---|
| 3V3 | 3.3V | red | Never 5V — the RC522 is a 3.3 V part. |
| GND | GND | black | |
| D5 | SCK | yellow | D5 = GPIO14, hardware SPI clock. |
| D6 | MISO | green | D6 = GPIO12. |
| D7 | MOSI | blue | D7 = GPIO13. |
| D8 | SDA | purple | The RC522’s SDA is its SPI chip select. D8 = GPIO15, the hardware CS. |
| D0 | RST | orange | D0 = GPIO16: a plain output is all RST needs. |
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 hardware SPI is fixed to D5 (SCK), D6 (MISO), D7 (MOSI), and
SPI.begin()takes no pin arguments on this core. The RC522 uses six of the D1 mini’s eleven GPIOs; D1/D2 are left for an I2C display. - Chip select on D8 (GPIO15) is safe: the board pulls it low for booting, and the RC522’s SDA input doesn’t fight that. Don’t add a pull-up to D8 — the board won’t boot.
- RST goes on D0, which has no interrupt or PWM but is perfect for a simple output. That keeps D3/D4 (boot pins) out of the circuit. If you later want deep sleep, D0 is needed for the RST jumper — move the RC522 RST to D3 then.
- IRQ is not connected; the library polls the reader.
- A UID is not a password: most cheap 13.56 MHz cards can be cloned. Fine for attendance or a hobby lock, not for anything that needs real security.
Code
// RC522 RFID reader on a Wemos D1 mini (ESP8266), hardware SPI.
// 3.3V → 3V3, GND → GND, SCK → D5, MISO → D6, MOSI → D7, SDA (chip select) → D8, RST → D0.
// Prints each card's UID and checks it against one allowed card.
#include <SPI.h>
#include <MFRC522.h>
const uint8_t SS_PIN = D8; // GPIO15: hardware CS, pulled low on the board so it boots fine
const uint8_t RST_PIN = D0; // GPIO16: a plain output is all RST needs, keeps D1-D4 free
MFRC522 rfid(SS_PIN, RST_PIN);
const char* ALLOWED_UID = "DE AD BE EF"; // replace with your card's UID as printed below
void setup() {
Serial.begin(115200);
Serial.println();
SPI.begin(); // ESP8266 HSPI: SCK = D5, MISO = D6, MOSI = D7
rfid.PCD_Init();
byte v = rfid.PCD_ReadRegister(MFRC522::VersionReg);
if (v == 0x00 || v == 0xFF) {
Serial.println("RC522 not answering - check 3.3V, SDA on D8 and the SPI wires");
} else {
Serial.printf("RC522 ready (version 0x%02X) - tap a card\n", v);
}
}
void loop() {
if (!rfid.PICC_IsNewCardPresent() || !rfid.PICC_ReadCardSerial()) {
delay(50);
return;
}
char uid[32] = "";
for (byte i = 0; i < rfid.uid.size && i < 10; i++) {
char b[4];
snprintf(b, sizeof b, i ? " %02X" : "%02X", rfid.uid.uidByte[i]);
strcat(uid, b);
}
MFRC522::PICC_Type type = rfid.PICC_GetType(rfid.uid.sak);
Serial.printf("UID %s (", uid);
Serial.print(rfid.PICC_GetTypeName(type)); // a flash string (F("...")), so print it on its own
Serial.printf(") %s\n", strcmp(uid, ALLOWED_UID) == 0 ? "ALLOWED" : "denied");
rfid.PICC_HaltA();
rfid.PCD_StopCrypto1();
}// RC522 RFID reader on a Wemos D1 mini (ESP8266), hardware SPI.
// 3.3V → 3V3, GND → GND, SCK → D5, MISO → D6, MOSI → D7, SDA (chip select) → D8, RST → D0.
// Prints each card's UID and checks it against one allowed card.
#include <SPI.h>
#include <MFRC522.h>
const uint8_t SS_PIN = D8; // GPIO15: hardware CS, pulled low on the board so it boots fine
const uint8_t RST_PIN = D0; // GPIO16: a plain output is all RST needs, keeps D1-D4 free
MFRC522 rfid(SS_PIN, RST_PIN);
const char* ALLOWED_UID = "DE AD BE EF"; // replace with your card's UID as printed below
void setup() {
Serial.begin(115200);
Serial.println();
SPI.begin(); // ESP8266 HSPI: SCK = D5, MISO = D6, MOSI = D7
rfid.PCD_Init();
byte v = rfid.PCD_ReadRegister(MFRC522::VersionReg);
if (v == 0x00 || v == 0xFF) {
Serial.println("RC522 not answering - check 3.3V, SDA on D8 and the SPI wires");
} else {
Serial.printf("RC522 ready (version 0x%02X) - tap a card\n", v);
}
}
void loop() {
if (!rfid.PICC_IsNewCardPresent() || !rfid.PICC_ReadCardSerial()) {
delay(50);
return;
}
char uid[32] = "";
for (byte i = 0; i < rfid.uid.size && i < 10; i++) {
char b[4];
snprintf(b, sizeof b, i ? " %02X" : "%02X", rfid.uid.uidByte[i]);
strcat(uid, b);
}
MFRC522::PICC_Type type = rfid.PICC_GetType(rfid.uid.sak);
Serial.printf("UID %s (", uid);
Serial.print(rfid.PICC_GetTypeName(type)); // a flash string (F("...")), so print it on its own
Serial.printf(") %s\n", strcmp(uid, ALLOWED_UID) == 0 ? "ALLOWED" : "denied");
rfid.PICC_HaltA();
rfid.PCD_StopCrypto1();
}Library: MFRC522 (GithubCommunity) — compiled with MFRC522 1.4.12.
Expected serial output
RC522 ready (version 0x92) - tap a card
UID 93 4A 1C 0E (MIFARE 1KB) denied
UID DE AD BE EF (MIFARE 1KB) ALLOWEDRC522 ready (version 0x92) - tap a card UID 93 4A 1C 0E (MIFARE 1KB) denied UID DE AD BE EF (MIFARE 1KB) ALLOWED
Common errors
“RC522 not answering” (version 0x00 or 0xFF)
Check 3.3V power, SDA on D8, and that MISO/MOSI are not swapped. Full fix.
Version 0x12 or 0x88 and some cards don’t read
Clone chips report odd versions but usually work. Hold the card flat and close — the antenna range is only 2–3 cm.
Board won’t boot with the reader connected
Something is pulling D8 high at reset. Use a plain RC522 module without extra pull-ups on SDA, or move CS to D1/D2 and pass that pin to the constructor.