RFID / NFC برد Esp32 میکروپایتون Micropython

پروژه راه‌اندازی ماژول RC522 RFID با میکروپایتون در برد ESP32

نوشته شده توسط CiferTech

در پروژه RFID میکروپایتون با استفاده از ماژول RC522 و به کمک میکروپایتون قصد خواندن و نوشتن مقادیر در تگ های RFID را داریم، در این پروژه از برد ESP32 و میکروپایتون برای راه‌اندازی و کد نویسی ماژول RC522 استفاده خواهیم کرد. در این پروژه هردو سناریو برای خواندن و همچنین نوشتن مقادیر مربوط در تگ های RFID بر پایه میکروپایتون را بررسی خواهیم کرد. در این پروژه برای کدنویسی از نرم‌افزار upycraft استفاده خواهیم کرد. در ادامه این آموزش با مرجع تخصصی آردوینو به زبان فارسی، دیجی اسپارک همراه باشید.

پروژه RFID با میکروپایتون و ESP32 - دیجی اسپارک

 


ماژول RC522


به لطف تکنولوژی Radio Frequency IDentification یا RFID در طول روز تنها با حمل یک کارت کوچک، قادر به پرداخت هزینه حمل نقل عمومی و تایید هویت در مکان های محتلف هستیم و این تنها دو نمونه از کاربرد های این تکنولوژی جذاب است، ماژول RC522 یک انتخاب خوب برای پروژه های این چنینی به حساب می آید. کم مصرف، کم هزینه، رابط کاربری آسان و بسیار محبوب بین علاقه مندان است. ماژول  RC522 مبتنی بر MFRC522 IC از NXP یکی از ارزان ترین گزینه ها برای پروژه های بر پایه RFID است، که معمولاً با تگ RFID با حافظه ۱KB ارائه می شود. و از همه مهم تر، می تواند بر روی این تگ ها بنویسد، بنابراین می توانید نوعی پیام مخفی خود را در آن ذخیره کنید.

ماژول RC522 RFID با میکروپایتون - دیجی اسپارک

 

ماژول RC522 برای خواندن تگ های RFID اقدم به ایجاد یک میدان الکترومغناطیسی ۱۳٫۵۶MHz می کند که از آن برای برقراری ارتباط با تگ های RFID استفاده می کند. این تگ دارای استاندارد ISO 14443A هستند. RC522 می تواند با یک میکروکنترلر از طریق رابط سریال ۴ پین سریال (SPI) با حداکثر سرعت داده ۱۰Mbps اقدام به برقراری ارتباط کند. همچنین این ارتباطات از طریق پروتکل های I2C و UART نیز امکان پذیر می باشد. ولتاژ کاری ماژول از ۲٫۵ تا ۳٫۳ ولت است، اما خبر خوب این است که پایه های منطقی، ۵ ولت را تحمل می کنند، بنابراین ما می توانیم بدون استفاده از مبدل سطح منطقی، آن را به راحتی به یک Arduino یا هر میکروکنترلر با ولتاژ ۵ ولت متصل کنیم.

 


تراشه ESP32


ESP32 می تواند به عنوان یک سیستم کامل مستقل یا به عنوان یک دستگاه MCU عمل کند و بار اضافی ارتباطات را در پردازنده اصلی برنامه کاهش دهد. ESP32 می تواند با سیستم های دیگر ارتباط برقرار کند تا از طریق SPI عملکرد Wi-Fi و بلوتوث را ارائه دهد. ESP32 با سوئیچ های آنتن داخلی، RF balun، تقویت کننده قدرت، تقویت کننده دریافت، فیلترها و ماژول های مدیریت توان یکپارچه شده است. ESP32 با حداقل الزامات برد مدار چاپی (PCB) ، عملکرد و تطبیق پذیری بی نظیری را به برنامه های شما اضافه می کند. برد ESP32 نسل پیشرفته ESP8266 است. یکی از تفاوت‌های آن بلوتوث داخلی‌اش می‌باشد. همچنین دارای هسته وایفای ۲,۴ گیگا هرتزی و بلوتوث داخلی تولید شده با تکنولوژی ۴۰ نانومتری شرکت TSMC می‌باشد. این ماژول دارای بهترین پرفورمنس در مصرف انرژی می‌باشد یعنی با کمترین مصرف انرژی بهترین نتیجه را برای ما به همراه دارد. اگر بخواهیم دقیق‌تر به این برد نگاه کنیم باید بگوییم که این یک chip است که پلتفرم NodeMCU در اون پیاده سازی شده که به این نوع چیپ ها System on a chip microcontrollers هم گفته می‌شود.

 


قطعات مورد نیاز


برد ESp32

ماژول RC522

 


شرح پروژه RC522


در پروژه RFID میکروپایتون با استفاده از دو فایل کد یعنی کتابخانه ماژول RC522 و کدی برای سناریو اصلی اقدام به راه‌اندازی این سنسور به منظور خواندن مقادیر تگ های RFID خواهیم کرد، در ادامه این آموزش نحوه کار با ماژول RC522 را با استفاده از برنامه نویسی میکروپایتون یاد خواهید گرفت و قادر خواهید بود با تغییر کد های این پروژه و افزودن موارد دلخواه به عنوان ویژگی های اضافه پروژه خود را پیش ببرید.

 

شرح پروژه RC522 با میکروپایتون - دیجی اسپارک

 


شماتیک پروژه RFID میکروپایتون


در شماتیک پروژه RFID میکروپایتون پین VCC را به پایه ESP32 3.3V متصل می‌کنیم. پین RST به پین GPIO4. پین GND به پین GND. پین IRQ بدون اتصال رها شده است. پین MISO به پین GPIO 19. پین MOSI به پین GPIO 23. پین SCK به پین GPIO 18. و در آخر، پین SDA به پین GPIO 5 متصل خواهد شد. همچنین می‌توانید از شماتیک زیر برای برقراری اتصالات استفاده کنید.

 


کد های پروژه RFID میکروپایتون


کد های پروژه RFID میکروپایتون از دوبخش تشکیل شده‌اند، مانند پروژه های قبلی میکروپایتون بیس با ESP32 ابتدا کتابخانه مورد نظر برای راه‌اندازی سنسور یا ماژول مورد استفاده را اضافه می‌کنیم که در این پروژه مورد مدنظر ما ماژول RC522 است. کد زیر را با نام mfrc522.py در نرم‌افزار upycraft ایجاد و ذخیره کنید، و در ادامه کد را در برد ESP32 آپلود کنید.

from machine import Pin, SPI
from os import uname

emptyRecv = b""

class MFRC522:

    GAIN_REG = 0x26
    MAX_GAIN = 0x07

    OK = 0
    NOTAGERR = 1
    ERR = 2

    REQIDL = 0x26
    REQALL = 0x52
    AUTHENT1A = 0x60
    AUTHENT1B = 0x61

    def __init__(self, spi=None, gpioRst=None, gpioCs=None):

        if gpioRst is not None:
            self.rst = Pin(gpioRst, Pin.OUT)
        else:
            self.rst = None
        assert(gpioCs is not None, "Needs gpioCs") # TODO fails without cableSelect
        if gpioCs is not None:
            self.cs = Pin(gpioCs, Pin.OUT)
        else:
            self.cs = None

        # TODO CH rationalise which of these are referenced, which can be identical
        self.regBuf = bytearray(4)
        self.blockWriteBuf = bytearray(18)
        self.authBuf = bytearray(12)
        self.wregBuf = bytearray(2)
        self.rregBuf = bytearray(1)
        self.recvBuf = bytearray(16)
        self.recvMv = memoryview(self.recvBuf)

        if self.rst is not None:
            self.rst.value(0)
        if self.cs is not None:
            self.cs.value(1)

        if spi is not None:
            self.spi = spi
        else:
            sck = Pin(14, Pin.OUT)
            mosi = Pin(13, Pin.OUT)
            miso = Pin(12, Pin.IN)
            if uname()[0] == 'WiPy':
                self.spi = SPI(0)
                self.spi.init(SPI.MASTER, baudrate=1000000, pins=(sck, mosi, miso))
            elif uname()[0] == 'esp8266': # TODO update to match https://github.com/cefn/avatap/blob/master/python/host/cockle.py #prepareHost()
                self.spi = SPI(baudrate=100000, polarity=0, phase=0, sck=sck, mosi=mosi, miso=miso)
                self.spi.init()
            else:
                raise RuntimeError("Unsupported platform")

        if self.rst is not None:
            self.rst.value(1)
        self.init()

    def _wreg(self, reg, val):
        if self.cs is not None:
            self.cs.value(0)
        buf = self.wregBuf
        buf[0]=0xff & ((reg << 1) & 0x7e)
        buf[1]=0xff & val
        self.spi.write(buf)
        if self.cs is not None:
            self.cs.value(1)

    def _rreg(self, reg):
        if self.cs is not None:
            self.cs.value(0)
        buf = self.rregBuf
        buf[0]=0xff & (((reg << 1) & 0x7e) | 0x80)
        self.spi.write(buf)
        val = self.spi.read(1)
        if self.cs is not None:
            self.cs.value(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, into=None):

        recv = emptyRecv
        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)):
                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

                    if into is None:
                        recv = self.recvBuf
                    else:
                        recv = into
                    pos = 0
                    while pos < n:
                        recv[pos] = self._rreg(0x09)
                        pos += 1
                    if into is None:
                        recv = self.recvMv[:n]
                    else:
                        recv = into

            else:
                stat = self.ERR

        return stat, recv, bits

    def _assign_crc(self, data, count):

        self._cflags(0x05, 0x04)
        self._sflags(0x0A, 0x80)

        dataPos = 0
        while dataPos < count:
            self._wreg(0x09, data[dataPos])
            dataPos += 1

        self._wreg(0x01, 0x03)

        i = 0xFF
        while True:
            n = self._rreg(0x05)
            i -= 1
            if not ((i != 0) and not (n & 0x04)):
                break

        data[count] = self._rreg(0x22)
        data[count + 1] = 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.set_gain(self.MAX_GAIN)
        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

        # CH Note bytearray allocation here
        return stat, bytearray(recv)

    def select_tag(self, ser):
        # TODO CH normalise all list manipulation to bytearray, avoid below allocation
        buf = bytearray(9)
        buf[0] = 0x93
        buf[1] = 0x70
        buf[2:7] = ser
        self._assign_crc(buf, 7)
        (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):
        # TODO CH void ser[:4] implicit list allocation
        buf = self.authBuf
        buf[0]=mode # A or B
        buf[1]=addr # block
        buf[2:8]=sect # key bytes
        buf[8:12]=ser[:4] # 4 bytes of id
        return self._tocard(0x0E, buf)[0]

    # TODO this may well need to be implemented for vault to properly back out from a card session
    # TODO how, why, when is 'HaltA' needed? see https://github.com/cefn/micropython-mfrc522/issues/1
    def halt_a(self):
        pass

    def stop_crypto1(self):
        self._cflags(0x08, 0x08)

    def set_gain(self, gain):
        assert gain <= self.MAX_GAIN
        # clear bits
        self._cflags(self.GAIN_REG, 0x07<< 4)
        # set bits according to gain
        self._sflags(self.GAIN_REG, gain << 4)

    def read(self, addr, into = None):
        buf = self.regBuf
        buf[0]=0x30
        buf[1]=addr
        self._assign_crc(buf, 2)
        (stat, recv, _) = self._tocard(0x0C, buf, into=into)
        # TODO this logic probably wrong (should be 'into is None'?)
        if into is None: # superstitiously avoid returning read buffer memoryview
            # CH Note bytearray allocation here
            recv = bytearray(recv)
        return recv if stat == self.OK else None

    def write(self, addr, data):
        buf = self.regBuf
        buf[0] = 0xA0
        buf[1] = addr
        self._assign_crc(buf, 2)
        (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 = self.blockWriteBuf

            i = 0
            while i < 16:
                buf[i] = data[i]  # TODO CH eliminate this, accelerate it?
                i += 1

            self._assign_crc(buf, 16)
            (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

 

در ادامه نوبت به کد اصلی پروژه RFID میکروپایتون می‌رسد، کد بالا به تنهایی برای ما کار مفیدی انجام نمی‌دهد و نیاز به یک برنامه جداگانه برای استفاده از قابلیت هایی دارد که در اختیار ما قرار می‌دهد، کد پایین را با نام rc522.py در نرم‌افزار upycraft ذخیره کنید و سپس هردو کد را در برد ESP32 خود آپلود کنید. نکته: در نرم‌افزار upycraft به منظور آپلود هر کد در صفحه های جداگانه نیاز دارید تا هر کد را بصورت جداگانه آپلود کنید.

from mfrc522 import MFRC522
from machine import Pin
from machine import SPI

spi = SPI(2, baudrate=2500000, polarity=0, phase=0)

spi.init()
rdr = MFRC522(spi=spi, gpioRst=4, gpioCs=5)
print("Place card")

while True:
    
    (stat, tag_type) = rdr.request(rdr.REQIDL)
    if stat == rdr.OK:
        (stat, raw_uid) = rdr.anticoll()
        if stat == rdr.OK:
            card_id = "uid: 0x%02x%02x%02x%02x" % (raw_uid[0], raw_uid[1], raw_uid[2], raw_uid[3])
            print(card_id)

 

کد نویسی میکروپایتون در برد ESP32 پروژه RFID - دیجی اسپارک

 


نتیجه نهایی


در نهایت پس از آپلود کد های این پروژه RFID میکروپایتون و برقراری اتصالات، در صورتی که تمام مراحل به درستی امجام شده باشد. قادر خواهید بود در نرم‌افزار upycraft در ترمینال این نر‌م‌افزار خواهید دید پس از هربار نزدیک کردن تگ rfid نزدیک ماژول rc522 شناسه uid تگ برای شما نمایش داده می‌شود، با استفاده از این شناسه و افزودن به کد های این پروژه قادر خواهید بود تا سییستم تایید هویت مبتنی بر ماژول rc522  و تگ های rfid بسازید.

پروژه RFID میکروپایتون micropython - دیجی اسپارک

 


کلام آخر با سایفر


پروژه های مثل این پروژه مبتنی ماژول های مختلف در سال گذشته همواره با زبان c/c++ در بستر آردوینو یا برد ESP و از این دست نوشته می‌شدند، اما میکروپایتون به دلیل سرعت و قابلیت های این چنینی که دارد به برنامه نویس در ساخت پروژه مختلف و خلاقانه تر کمک می‌کند. برای دانستن بیشتر در مورد میکروپایتون در برد های ESP32 آموزش های پایه و پروژه های مبتنی میکروپایتون را در سایت مشاهده کنید.

چنانچه در مراحل راه اندازی و انجام این پروژه با مشکل مواجه شدید، بدون هیچ نگرانی در انتهای همین پست، به صورت ثبت نظر سوالتان را مطرح کنید. من در سریع‌ترین زمان ممکن پاسخ رفع مشکل شما را خواهم داد. همچنین اگر ایرادی در کدها و یا مراحل اجرایی وجود دارند می‌توانید از همین طریق اطلاع رسانی کنید.

 

در پایان نظرات و پیشنهادات خود را با ما درمیان بگذارید و با اشتراک گذاری این آموزش در شبکه های اجتماعی , از وبسایت دیجی اسپارک حمایت کنید.

درباره نویسنده

CiferTech

تبادل نظر و رفع عیب با ثبت دیدگاه

۲ دیدگاه

  • سلام خسته نباشید کدوم پایه هارو متصل کردید؟ زیاد واضح نیست عکس ، اگه میشه یک راهنمایی بکنید که کدوم پایه هارو به RFID متصل کنیم برای این کدی که نوشتید
    ممنون