Skip to content

Instantly share code, notes, and snippets.

@idriszmy
Last active August 3, 2023 21:23
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save idriszmy/9fa14377eb3b5a1859e1ff4f41464900 to your computer and use it in GitHub Desktop.
Save idriszmy/9fa14377eb3b5a1859e1ff4f41464900 to your computer and use it in GitHub Desktop.
Interface RFid RC522 Reader using Maker Pi Pico and CircuitPython
"""
Interface RFid RC522 Reader using Maker Pi Pico and CircuitPython
https://tutorial.cytron.io/2022/01/11/interface-rfid-rc522-reader-using-maker-pi-pico-and-circuitpython/
Items:
- Maker Pi Pico
https://my.cytron.io/p-maker-pi-pico
- Mifare RC522 RFID Kit
https://my.cytron.io/p-mifare-rc522-rfid-kit
- Grove - Relay
https://my.cytron.io/p-grove-relay
- USB Micro B Cable
https://my.cytron.io/p-usb-micro-b-cable
Libraries required from bundle (https://circuitpython.org/libraries):
- simpleio.mpy
References:
- https://github.com/domdfcoding/circuitpython-mfrc522
Last update: 11 Jan 2022 (tested with CircuitPython 7.1.0)
"""
import time
import board
import digitalio
import simpleio
import busio
import mfrc522
NOTE_C5 = 523
NOTE_G5 = 784
buzzer = board.GP18
relay = digitalio.DigitalInOut(board.GP3)
relay.switch_to_output()
sck = board.GP6
mosi = board.GP7
miso = board.GP4
spi = busio.SPI(sck, MOSI=mosi, MISO=miso)
cs = digitalio.DigitalInOut(board.GP5)
rst = digitalio.DigitalInOut(board.GP8)
rfid = mfrc522.MFRC522(spi, cs, rst)
rfid.set_antenna_gain(0x07 << 4)
print("\n***** Scan your RFid tag/card *****\n")
prev_data = ""
prev_time = 0
timeout = 1
while True:
(status, tag_type) = rfid.request(rfid.REQALL)
if status == rfid.OK:
(status, raw_uid) = rfid.anticoll()
if status == rfid.OK:
rfid_data = "{:02x}{:02x}{:02x}{:02x}".format(raw_uid[0], raw_uid[1], raw_uid[2], raw_uid[3])
if rfid_data != prev_data:
prev_data = rfid_data
print("Card detected! UID: {}".format(rfid_data))
if rfid_data == "cc40b773":
simpleio.tone(buzzer, NOTE_C5, 0.08)
simpleio.tone(buzzer, NOTE_G5, 0.08)
time.sleep(1)
print("Activate relay for 5 seconds")
relay.value = True
time.sleep(5)
relay.value = False
else:
simpleio.tone(buzzer, NOTE_C5, 0.3)
prev_time = time.monotonic()
else:
if time.monotonic() - prev_time > timeout:
prev_data = ""
"""
References:
- https://github.com/domdfcoding/circuitpython-mfrc522
- https://github.com/wendlers/micropython-mfrc522
"""
from adafruit_bus_device.spi_device import SPIDevice
class MFRC522:
OK = 0
NOTAGERR = 1
ERR = 2
REQIDL = 0x26
REQALL = 0x52
AUTHENT1A = 0x60
AUTHENT1B = 0x61
def __init__(self, spi, cs, rst):
rst.switch_to_output()
rst.value = False
rst.value = True
self._spi = SPIDevice(spi, cs)
self.init()
def _wreg(self, reg: int, val):
with self._spi as spi:
spi.write(b'%c' % int(0xff & ((reg << 1) & 0x7e)))
spi.write(b'%c' % int(0xff & val))
def _rreg(self, reg: int):
with self._spi as spi:
spi.write(b'%c' % int(0xff & (((reg << 1) & 0x7e) | 0x80)))
val = bytearray(1)
spi.readinto(val)
return val[0]
def _sflags(self, reg: int, mask: int):
self._wreg(reg, self._rreg(reg) | mask)
def _cflags(self, reg: int, mask: int):
self._wreg(reg, self._rreg(reg) & (~mask))
def _tocard(self, cmd: int, send):
recv = []
bits = irq_en = wait_irq = 0
stat = self.ERR
if cmd == 0x0E:
irq_en = 0x12
wait_irq = 0x10
elif cmd == 0x0C:
irq_en = 0x77
wait_irq = 0x30
self._wreg(0x02, irq_en | 0x80)
self._cflags(0x04, 0x80)
self._sflags(0x0A, 0x80)
self._wreg(0x01, 0x00)
for c in send:
self._wreg(0x09, c)
self._wreg(0x01, cmd)
if cmd == 0x0C:
self._sflags(0x0D, 0x80)
i = 2000
while True:
n = self._rreg(0x04)
i -= 1
if ~((i != 0) and ~(n & 0x01) and ~(n & wait_irq)):
break
self._cflags(0x0D, 0x80)
if i:
if (self._rreg(0x06) & 0x1B) == 0x00:
stat = self.OK
if n & irq_en & 0x01:
stat = self.NOTAGERR
elif cmd == 0x0C:
n = self._rreg(0x0A)
lbits = self._rreg(0x0C) & 0x07
if lbits != 0:
bits = (n - 1) * 8 + lbits
else:
bits = n * 8
if n == 0:
n = 1
elif n > 16:
n = 16
for _ in range(n):
recv.append(self._rreg(0x09))
else:
stat = self.ERR
return stat, recv, bits
def _crc(self, data):
self._cflags(0x05, 0x04)
self._sflags(0x0A, 0x80)
for c in data:
self._wreg(0x09, c)
self._wreg(0x01, 0x03)
i = 0xFF
while True:
n = self._rreg(0x05)
i -= 1
if not ((i != 0) and not (n & 0x04)):
break
return [self._rreg(0x22), self._rreg(0x21)]
def init(self):
self.reset()
self._wreg(0x2A, 0x8D)
self._wreg(0x2B, 0x3E)
self._wreg(0x2D, 30)
self._wreg(0x2C, 0)
self._wreg(0x15, 0x40)
self._wreg(0x11, 0x3D)
self.antenna_on()
def reset(self):
self._wreg(0x01, 0x0F)
def antenna_on(self, on=True):
if on and ~(self._rreg(0x14) & 0x03):
self._sflags(0x14, 0x03)
else:
self._cflags(0x14, 0x03)
def request(self, mode):
self._wreg(0x0D, 0x07)
(stat, recv, bits) = self._tocard(0x0C, [mode])
if (stat != self.OK) | (bits != 0x10):
stat = self.ERR
return stat, bits
def anticoll(self):
ser_chk = 0
ser = [0x93, 0x20]
self._wreg(0x0D, 0x00)
(stat, recv, bits) = self._tocard(0x0C, ser)
if stat == self.OK:
if len(recv) == 5:
for i in range(4):
ser_chk = ser_chk ^ recv[i]
if ser_chk != recv[4]:
stat = self.ERR
else:
stat = self.ERR
return stat, recv
def select_tag(self, ser):
buf = [0x93, 0x70] + ser[:5]
buf += self._crc(buf)
(stat, recv, bits) = self._tocard(0x0C, buf)
return self.OK if (stat == self.OK) and (bits == 0x18) else self.ERR
def auth(self, mode, addr, sect, ser):
return self._tocard(0x0E, [mode, addr] + sect + ser[:4])[0]
def stop_crypto1(self):
self._cflags(0x08, 0x08)
def read(self, addr):
data = [0x30, addr]
data += self._crc(data)
(stat, recv, _) = self._tocard(0x0C, data)
return recv if stat == self.OK else None
def write(self, addr, data):
buf = [0xA0, addr]
buf += self._crc(buf)
(stat, recv, bits) = self._tocard(0x0C, buf)
if not (stat == self.OK) or not (bits == 4) or not ((recv[0] & 0x0F) == 0x0A):
stat = self.ERR
else:
buf = []
for i in range(16):
buf.append(data[i])
buf += self._crc(buf)
(stat, recv, bits) = self._tocard(0x0C, buf)
if not (stat == self.OK) or not (bits == 4) or not ((recv[0] & 0x0F) == 0x0A):
stat = self.ERR
return stat
def set_antenna_gain(self, gain: int):
"""
Set the MFRC522 Receiver Gain
:param gain:
Possible values are:
* ``0x00 << 4`` -- 000b - 18 dB, minimum
* ``0x01 << 4`` -- 001b - 23 dB
* ``0x02 << 4`` -- 010b - 18 dB, it seems 010b is a duplicate for 000b
* ``0x03 << 4`` -- 011b - 23 dB, it seems 011b is a duplicate for 001b
* ``0x04 << 4`` -- 100b - 33 dB, average, and typical default
* ``0x05 << 4`` -- 101b - 38 dB
* ``0x06 << 4`` -- 110b - 43 dB
* ``0x07 << 4`` -- 111b - 48 dB, maximum
* ``0x00 << 4`` -- 000b - 18 dB, minimum, convenience for RxGain_18dB
* ``0x04 << 4`` -- 100b - 33 dB, average, convenience for RxGain_33dB
* ``0x07 << 4`` -- 111b - 48 dB, maximum, convenience for RxGain_48dB
:return:
"""
# Above table from https://github.com/miguelbalboa/rfid/blob/master/src/MFRC522.h
# See also 9.3.3.6 / table 98 of the datasheet (http://www.nxp.com/documents/data_sheet/MFRC522.pdf)
self._cflags(0x26, 0x07 << 4)
self._sflags(0x26, gain & (0x07 << 4))
@yuri4029
Copy link

yuri4029 commented Aug 22, 2022

Hi idriszmy, thank you so much for your effort when made this.
About code, on file code.py, line 68
if rfid_data == "cc40b773":
simpleio.tone(buzzer, NOTE_C5, 0.08)
simpleio.tone(buzzer, NOTE_G5, 0.08)

I dont get "cc40b773", what is mean ?

@srerickson
Copy link

Thank you for this code @idriszmy! Would you mind adding licensing information in the file headers? Otherwise, it's not clear if others have permission to use this. Thanks!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment