Raspberry Pi Pico

Raspberry Pi Pico and RFID based Door Lock Control System

Raspberry Pi Pico and RFID:


Raspberry Pi Pico and RFID based Door Lock Control System– In this tutorial, you will learn how to control an electronic door lock using Raspberry Pi Pico, a one-channel relay module, a 5v buzzer, and an MFRC522 RFID Reader module.

Just similar to an Arduino, ESP32, ESP8266, and STM32, Raspberry Pi Pico is also a controller board based on the RP2040 microcontroller, through the programming of which, you can control almost anything. And apart from this, you can also monitor different types of analog and digital sensors as well. In case you are using a Raspberry Pi Pico for the first time, I would definitely recommend you to read my “Getting started tutorial on Raspberry Pi Pico”. In this article, I have explained and attempted to shed light on almost everything in the article that a beginner must be acquainted with. In this getting started tutorial, I did 10 different beginners level projects.

I am sure almost 99.9% of people must be aware of the door locks, while, the remaining 0.1% are those people, who unluckily reside in such regions, where, I am afraid, people do not even know what actually the doors are?

Raspberry Pi Pico and RFID

Anyway, here is an ordinary door lock, which you can easily open or close with the help of a key.

Raspberry Pi Pico and RFID

Whereas, this is an Elock or Electronic Door lock, which you can simply control electronically. I am not using this electronic lock for the first time. I have used it on many occasions during my different projects. Most recently, I used the same particular electronic door lock with an ESP32 camera module, I have also used the same exact electronic door lock with the ESP8266 Wifi module. And, of course, needless to say, I have also used it with the Arduino.

Anyways, before I share with you the circuit diagram and code, first let’s watch the Raspberry Pi Pico and RFID based Door lock control system in action.

Altium Designer + Altium 365 + Octopart:

Arduino LoRa Free SMS

Altium 365 lets you hold the fastest design reviews ever. Share your designs from anywhere and with anyone with a single click. it’s easy, leave a comment tagging your teammate and they’ll instantly receive an email with a link to the design. Anyone you invite can open the design using a web browser. Using the browser interface, you’re able to comment, markup, cross probe, inspect, and more. Comments are attached directly to the project, making them viewable within Altium designer as well as through the browser interface. Design, share, and manufacture, all in the same space with nothing extra to install or configure. Connect to the platform directly from Altium Designer without changing how you already design electronics. Altium 365 requires no additional licenses and comes included with your subscription plan.

Get real-time component insights as you design with Octopart built into Altium 365. Octopart is the fastest search engine for electronic parts and gives you the most up-to-date part data like specs, datasheets, cad models, and how much the part costs at different amounts etc. Right in the design environment so you can focus on your designs. Start with Altium Designer and Activate Altium 365. Search for electronic parts on Octopart.

Raspberry Pi Pico and RFID

I have already powered up the entire system. Right now I have one RFID card and two RFID key chains. One of these key chains is authorized which I can use to open the electronic door lock, while the other one is unauthorized. When the unauthorized RFID card or keychain is used the buzzer is immediately turned ON.

Anyways, right now you can see, that when no authorized RFID card is used the Electronic door lock remains closed. Whereas when the authorized RFID card is used, the electronic door lock is opened.

Raspberry Pi Pico and RFID

You have obviously watched my video tutorial given at the end of this article, how easily we can control an electronic door lock using the Raspberry Pi Pico and RFID module. I am sure by now you might have got an idea of how does this system works. So, without any further delay, let’s get started!!!

Amazon Links:

Raspberry Pi Pico

12V Electronic Door Lock

5V Buzzer

MFRC522 RFID Module

12V One Channel Relay Module

Other Tools and Components:

Top Arduino Sensors:

Super Starter kit for Beginners

Digital Oscilloscopes

Variable Supply

Digital Multimeter

Soldering iron kits

PCB small portable drill machines

*Please Note: These are affiliate links. I may make a commission if you buy the components through these links. I would appreciate your support in this way!

Raspberry Pi Pico and RFID, Circuit Diagram:

Raspberry Pi Pico and RFID

The SDA, SCK, MOSI, MISO, and RST pins of the MFRC522 RFID reader module are connected with the Raspberry Pi Pico GPIO pins 5, 6, 7, 4, and 3 respectively. And obviously the 3.3V and GND pins of the RFID module are connected with the Raspberry Pi Pico 3.3V and GND pins.

A one-channel relay module is controlled using the GP28 pin on the Raspberry Pi Pico. This is an SPDT-type relay. SPDT stands for single pole and double throw. The 12V wire to the Electronic door lock goes through this relay.

The 5V buzzer is controlled using the GP27 pin on the Raspberry Pi Pico. The 2n2222 NPN transistor and 10K resistor makes the driver circuit which is used to control the buzzer.

Raspberry Pi Pico and RFID, Python Programming:

Connect Raspberry Pi Pico with the Laptop.

Copy the code given below.

Mfrc522.py Code:

from machine import Pin, SPI
from os import uname

class MFRC522:

    DEBUG = False
    OK = 0
    NOTAGERR = 1
    ERR = 2

    REQIDL = 0x26
    REQALL = 0x52
    AUTHENT1A = 0x60
    AUTHENT1B = 0x61
    PICC_ANTICOLL1 = 0x93
    PICC_ANTICOLL2 = 0x95
    PICC_ANTICOLL3 = 0x97

    def __init__(self, sck, mosi, miso, rst, cs,baudrate=1000000,spi_id=0):

        self.sck = Pin(sck, Pin.OUT)
        self.mosi = Pin(mosi, Pin.OUT)
        self.miso = Pin(miso)
        self.rst = Pin(rst, Pin.OUT)
        self.cs = Pin(cs, Pin.OUT)

        board = uname()[0]

        if board == 'WiPy' or board == 'LoPy' or board == 'FiPy':
            self.spi = SPI(0)
            self.spi.init(SPI.MASTER, baudrate=1000000, pins=(self.sck, self.mosi, self.miso))
        elif (board == 'esp8266') or (board == 'esp32'):
            self.spi = SPI(baudrate=100000, polarity=0, phase=0, sck=self.sck, mosi=self.mosi, miso=self.miso)
        elif board == 'rp2':
            self.spi = SPI(spi_id,baudrate=baudrate,sck=self.sck, mosi= self.mosi, miso= self.miso)
            raise RuntimeError("Unsupported platform")


    def _wreg(self, reg, val):

        self.spi.write(b'%c' % int(0xff & ((reg << 1) & 0x7e)))
        self.spi.write(b'%c' % int(0xff & val))

    def _rreg(self, reg):

        self.spi.write(b'%c' % int(0xff & (((reg << 1) & 0x7e) | 0x80)))
        val = self.spi.read(1)

        return val[0]

    def _sflags(self, reg, mask):
        self._wreg(reg, self._rreg(reg) | mask)

    def _cflags(self, reg, mask):
        self._wreg(reg, self._rreg(reg) & (~mask))

    def _tocard(self, cmd, send):

        recv = []
        bits = irq_en = wait_irq = n = 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)):

        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
                        bits = n * 8

                    if n == 0:
                        n = 1
                    elif n > 16:
                        n = 16

                    for _ in range(n):
                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)):

        return [self._rreg(0x22), self._rreg(0x21)]

    def init(self):

        self._wreg(0x2A, 0x8D)
        self._wreg(0x2B, 0x3E)
        self._wreg(0x2D, 30)
        self._wreg(0x2C, 0)
        self._wreg(0x15, 0x40)
        self._wreg(0x11, 0x3D)

    def reset(self):
        self._wreg(0x01, 0x0F)

    def antenna_on(self, on=True):

        if on and ~(self._rreg(0x14) & 0x03):
            self._sflags(0x14, 0x03)
            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,anticolN):

        ser_chk = 0
        ser = [anticolN, 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
                stat = self.ERR

        return stat, recv

    def PcdSelect(self, serNum,anticolN):
        backData = []
        buf = []
        #i = 0
        for i in serNum:
        #while i<5:
        #    buf.append(serNum[i])
        #    i = i + 1
        pOut = self._crc(buf)
        (status, backData, backLen) = self._tocard( 0x0C, buf)
        if (status == self.OK) and (backLen == 0x18):
            return  1
            return 0
    def SelectTag(self, uid):
        byte5 = 0
        #(status,puid)= self.anticoll(self.PICC_ANTICOLL1)
        for i in uid:
            byte5 = byte5 ^ i
        puid = uid + [byte5]
        if self.PcdSelect(puid,self.PICC_ANTICOLL1) == 0:
            return (self.ERR,[])
        return (self.OK , uid)
    def tohexstring(self,v):
        for i in v:
            if i != v[0]:
                s = s+ ", "
            s=s+ "0x{:02X}".format(i)
        s= s+ "]"
        return s
    def SelectTagSN(self):
        (status,uid)= self.anticoll(self.PICC_ANTICOLL1)
        #print("Select Tag 1:",self.tohexstring(uid))
        if status != self.OK:
            return  (self.ERR,[])
        if self.DEBUG:   print("anticol(1) {}".format(uid))
        if self.PcdSelect(uid,self.PICC_ANTICOLL1) == 0:
            return (self.ERR,[])
        if self.DEBUG:   print("pcdSelect(1) {}".format(uid))
        #check if first byte is 0x88
        if uid[0] == 0x88 :
            #ok we have another type of card
            #print("Select Tag 2:",self.tohexstring(uid))
            if status != self.OK:
                return (self.ERR,[])
            if self.DEBUG: print("Anticol(2) {}".format(uid))
            rtn =  self.PcdSelect(uid,self.PICC_ANTICOLL2)
            if self.DEBUG: print("pcdSelect(2) return={} uid={}".format(rtn,uid))
            if rtn == 0:
                return (self.ERR,[])
            if self.DEBUG: print("PcdSelect2() {}".format(uid))
            #now check again if uid[0] is 0x88
            if uid[0] == 0x88 :
                (status , uid) = self.anticoll(self.PICC_ANTICOLL3)
                #print("Select Tag 3:",self.tohexstring(uid))
                if status != self.OK:
                    return (self.ERR,[])
                if self.DEBUG: print("Anticol(3) {}".format(uid))
                if self.MFRC522_PcdSelect(uid,self.PICC_ANTICOLL3) == 0:
                    return (self.ERR,[])
                if self.DEBUG: print("PcdSelect(3) {}".format(uid))
        # if we are here than the uid is ok
        # let's remove the last BYTE whic is the XOR sum
        return (self.OK , valid_uid[:len(valid_uid)-1])
        #return (self.OK , valid_uid)

    def auth(self, mode, addr, sect, ser):
        return self._tocard(0x0E, [mode, addr] + sect + ser[:4])[0]
    def authKeys(self,uid,addr,keyA=None, keyB=None):
        status = self.ERR
        if keyA is not None:
            status = self.auth(self.AUTHENT1A, addr, keyA, uid)
        elif keyB is not None:
            status = self.auth(self.AUTHENT1B, addr, keyB, uid)
        return status

    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 stat, recv

    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
            buf = []
            for i in range(16):
            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 writeSectorBlock(self,uid, sector, block, data, keyA=None, keyB = None):
        absoluteBlock =  sector * 4 + (block % 4)
        if absoluteBlock > 63 :
            return self.ERR
        if len(data) != 16:
            return self.ERR
        if self.authKeys(uid,absoluteBlock,keyA,keyB) != self.ERR :
            return self.write(absoluteBlock, data)
        return self.ERR

    def readSectorBlock(self,uid ,sector, block, keyA=None, keyB = None):
        absoluteBlock =  sector * 4 + (block % 4)
        if absoluteBlock > 63 :
            return self.ERR, None
        if self.authKeys(uid,absoluteBlock,keyA,keyB) != self.ERR :
            return self.read(absoluteBlock)
        return self.ERR, None

    def MFRC522_DumpClassic1K(self,uid, Start=0, End=64, keyA=None, keyB=None):
        for absoluteBlock in range(Start,End):
            status = self.authKeys(uid,absoluteBlock,keyA,keyB)
            # Check if authenticated
            print("{:02d} S{:02d} B{:1d}: ".format(absoluteBlock, absoluteBlock//4 , absoluteBlock % 4),end="")
            if status == self.OK:                    
                status, block = self.read(absoluteBlock)
                if status == self.ERR:
                    for value in block:
                        print("{:02X} ".format(value),end="")
                    print("  ",end="")
                    for value in block:
                        if (value > 0x20) and (value < 0x7f):
        if status == self.ERR:
            print("Authentication error")
            return self.ERR
        return self.OK

So, after copying the above code. Open the Thonny IDE and click on the new file. And paste this code. Save this code in the Raspberry Pi Pico with the name mfrc522.py.

Now, copy the code given below.

main.py code:

from mfrc522 import MFRC522 
import utime
from machine import Pin

lock =Pin(28,Pin.OUT)
buzzer = Pin(27, Pin.OUT)

def uidToString(uid):
    mystring = ""
    for i in uid:
        mystring = "%02X" % i + mystring
    return mystring
rc522 = MFRC522(spi_id=0,sck=6,miso=4,mosi=7,cs=5,rst=3)

print("Place the card")

while True:

    (stat, tag_type) = rc522.request(rc522.REQALL)

    if stat == rc522.OK:
        (status, raw_uid) = rc522.SelectTagSN()
        if stat == rc522.OK:
            rfid_data = "{:02x}{:02x}{:02x}{:02x}".format(raw_uid[0], raw_uid[1], raw_uid[2], raw_uid[3])
            print("Card detected! UID: {}".format(rfid_data))
            if rfid_data == "c645224b":
            elif rfid_data == "4247b01e":


After you have copied the code, again go to the Thonny IDE and again click on the new file and paste this code. This time save this code in Raspberry Pi Pico with the name main.py

Now, finally you can click on the play button. You will be prompted, to place the card as you can see in the image given below. Swipe the RFID cards, tags, or key chains to find the UIDs.

My UIDs are:




Raspberry Pi Pico and RFID

You can see in the main.py code, I have used the same IDs to control the electronic door lock. You can find the identification numbers of your RFID cards using the same method and then update the main.py code accordingly. If you face any issues then watch my video tutorial given below.

Watch Video Tutorial:


Engr Fahad

My name is Shahzada Fahad and I am an Electrical Engineer. I have been doing Job in UAE as a site engineer in an Electrical Construction Company. Currently, I am running my own YouTube channel "Electronic Clinic", and managing this Website. My Hobbies are * Watching Movies * Music * Martial Arts * Photography * Travelling * Make Sketches and so on...


  1. Hello Shahzada,
    1st: “very good job, thank you-!-”
    But when i place the chip too fast on the field. then break the program with a failure-message at line 31
    I fix this little bug in line 29: if stat == rc522.OK: —> if stat == rc522.OK and status == 0:
    …still have fun 🙂

Leave a Reply

Your email address will not be published. Required fields are marked *

Back to top button