Example project · Sensors
RFID door lock
An MFRC522 reader guarding a two-LED door. Toggle “Hold tag to reader” in the reader’s Inspector: the authorized card lights green and reads a note off block 1; edit the tag UID and tap again to get the red ACCESS DENIED path.

What's on the bench
- 2× LED
- 2× Resistor
- Battery
- ESP32-C6
- RFID reader (MFRC522)
How it's wired
- Battery · pos→ESP32-C6 · vin
- Battery · neg→ESP32-C6 · gnd
- ESP32-C6 · 3v3→RFID reader (MFRC522) · vcc
- ESP32-C6 · gnd2→RFID reader (MFRC522) · gnd
- ESP32-C6 · 3v3b→RFID reader (MFRC522) · rst
- ESP32-C6 · g6→RFID reader (MFRC522) · sck
- ESP32-C6 · g7→RFID reader (MFRC522) · mosi
- ESP32-C6 · g2→RFID reader (MFRC522) · miso
- ESP32-C6 · g20→RFID reader (MFRC522) · cs
- ESP32-C6 · g1→Resistor · a
- Resistor · b→LED · a
- LED · k→ESP32-C6 · gnd
- ESP32-C6 · g0→Resistor · a
- Resistor · b→LED · a
- LED · k→ESP32-C6 · gnd
The code
This MicroPython script runs on the emulated board every boot; edit it in the Code tab.
from machine import Pin, SPI import time class MFRC522: OK, ERR = 0, 2 def __init__(self, spi, cs): self.spi, self.cs = spi, cs self.cs.value(1) self._wreg(0x01, 0x0F) # soft reset for r, v in ((0x2A, 0x8D), (0x2B, 0x3E), (0x2D, 30), (0x2C, 0), (0x15, 0x40), (0x11, 0x3D)): self._wreg(r, v) self._wreg(0x14, self._rreg(0x14) | 0x03) # antenna on def _wreg(self, reg, val): self.cs.value(0) self.spi.write(bytes([(reg << 1) & 0x7E, val])) self.cs.value(1) def _rreg(self, reg): self.cs.value(0) self.spi.write(bytes([((reg << 1) & 0x7E) | 0x80])) val = self.spi.read(1, 0)[0] self.cs.value(1) return val def _crc(self, data): self._wreg(0x05, 0x04) self._wreg(0x0A, 0x80) for b in data: self._wreg(0x09, b) self._wreg(0x01, 0x03) # CalcCRC return [self._rreg(0x22), self._rreg(0x21)] def _tocard(self, cmd, send, bits=0): self._wreg(0x04, 0x7F) # clear irqs self._wreg(0x0A, 0x80) # flush FIFO self._wreg(0x0D, bits) for b in send: self._wreg(0x09, b) self._wreg(0x01, cmd) if cmd == 0x0C: self._wreg(0x0D, 0x80 | bits) # StartSend wait = 0x10 if cmd == 0x0E else 0x30 for _ in range(20): n = self._rreg(0x04) if n & 0x01: return self.ERR, [] # timer: nothing answered if n & wait: break else: return self.ERR, [] return self.OK, [self._rreg(0x09) for _ in range(self._rreg(0x0A))] def request(self): return self._tocard(0x0C, [0x26], 7)[0] def anticoll(self): stat, r = self._tocard(0x0C, [0x93, 0x20]) return r[:4] if stat == self.OK and len(r) == 5 else None def select(self, uid): buf = [0x93, 0x70] + uid + [uid[0] ^ uid[1] ^ uid[2] ^ uid[3]] return self._tocard(0x0C, buf + self._crc(buf))[0] def auth(self, block, key, uid): return self._tocard(0x0E, [0x60, block] + key + uid)[0] def read(self, block): buf = [0x30, block] stat, r = self._tocard(0x0C, buf + self._crc(buf)) return bytes(r[:16]) if stat == self.OK and len(r) >= 16 else None def halt(self): buf = [0x50, 0x00] self._tocard(0x0C, buf + self._crc(buf)) self._wreg(0x08, self._rreg(0x08) & 0xF7) # stop crypto1 # C6 hardware SPI (GPSPI2) fixed pins: sck=6, mosi=7, miso=2. rdr = MFRC522(SPI(1, baudrate=1000000), Pin(20, Pin.OUT)) print('MFRC522 version 0x%02x' % rdr._rreg(0x37)) green = Pin(1, Pin.OUT, value=0) red = Pin(0, Pin.OUT, value=0) KEY = [0xFF] * 6 AUTHORIZED = '9c5a1db3' print('Hold a tag to the reader (toggle in its Inspector)...') while True: if rdr.request() == rdr.OK: uid = rdr.anticoll() if uid and rdr.select(uid) == rdr.OK: s = ''.join('%02x' % b for b in uid) if s == AUTHORIZED and rdr.auth(1, KEY, uid) == rdr.OK: note = rdr.read(1) print('ACCESS GRANTED', s, note) green.value(1) red.value(0) else: print('ACCESS DENIED', s) red.value(1) green.value(0) rdr.halt() # one report per tap; lift + re-hold to scan again time.sleep_ms(300)



