در پروژه RFID میکروپایتون با استفاده از ماژول RC522 و به کمک میکروپایتون قصد خواندن و نوشتن مقادیر در تگ های RFID را داریم، در این پروژه از برد ESP32 و میکروپایتون برای راهاندازی و کد نویسی ماژول RC522 استفاده خواهیم کرد. در این پروژه هردو سناریو برای خواندن و همچنین نوشتن مقادیر مربوط در تگ های RFID بر پایه میکروپایتون را بررسی خواهیم کرد. در این پروژه برای کدنویسی از نرمافزار upycraft استفاده خواهیم کرد. در ادامه این آموزش با مرجع تخصصی آردوینو به زبان فارسی، دیجی اسپارک همراه باشید.
ماژول RC522
به لطف تکنولوژی Radio Frequency IDentification یا RFID در طول روز تنها با حمل یک کارت کوچک، قادر به پرداخت هزینه حمل نقل عمومی و تایید هویت در مکان های محتلف هستیم و این تنها دو نمونه از کاربرد های این تکنولوژی جذاب است، ماژول RC522 یک انتخاب خوب برای پروژه های این چنینی به حساب می آید. کم مصرف، کم هزینه، رابط کاربری آسان و بسیار محبوب بین علاقه مندان است. ماژول RC522 مبتنی بر MFRC522 IC از NXP یکی از ارزان ترین گزینه ها برای پروژه های بر پایه RFID است، که معمولاً با تگ RFID با حافظه ۱KB ارائه می شود. و از همه مهم تر، می تواند بر روی این تگ ها بنویسد، بنابراین می توانید نوعی پیام مخفی خود را در آن ذخیره کنید.
ماژول 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 هم گفته میشود.
شرح پروژه RC522
در پروژه RFID میکروپایتون با استفاده از دو فایل کد یعنی کتابخانه ماژول RC522 و کدی برای سناریو اصلی اقدام به راهاندازی این سنسور به منظور خواندن مقادیر تگ های RFID خواهیم کرد، در ادامه این آموزش نحوه کار با ماژول RC522 را با استفاده از برنامه نویسی میکروپایتون یاد خواهید گرفت و قادر خواهید بود با تغییر کد های این پروژه و افزودن موارد دلخواه به عنوان ویژگی های اضافه پروژه خود را پیش ببرید.
شماتیک پروژه RFID میکروپایتون
کد های پروژه 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)
نتیجه نهایی
در نهایت پس از آپلود کد های این پروژه RFID میکروپایتون و برقراری اتصالات، در صورتی که تمام مراحل به درستی امجام شده باشد. قادر خواهید بود در نرمافزار upycraft در ترمینال این نرمافزار خواهید دید پس از هربار نزدیک کردن تگ rfid نزدیک ماژول rc522 شناسه uid تگ برای شما نمایش داده میشود، با استفاده از این شناسه و افزودن به کد های این پروژه قادر خواهید بود تا سییستم تایید هویت مبتنی بر ماژول rc522 و تگ های rfid بسازید.
کلام آخر با سایفر
چنانچه در مراحل راه اندازی و انجام این پروژه با مشکل مواجه شدید، بدون هیچ نگرانی در انتهای همین پست، به صورت ثبت نظر سوالتان را مطرح کنید. من در سریعترین زمان ممکن پاسخ رفع مشکل شما را خواهم داد. همچنین اگر ایرادی در کدها و یا مراحل اجرایی وجود دارند میتوانید از همین طریق اطلاع رسانی کنید.
در پایان نظرات و پیشنهادات خود را با ما درمیان بگذارید و با اشتراک گذاری این آموزش در شبکه های اجتماعی , از وبسایت دیجی اسپارک حمایت کنید.
سلام خسته نباشید کدوم پایه هارو متصل کردید؟ زیاد واضح نیست عکس ، اگه میشه یک راهنمایی بکنید که کدوم پایه هارو به RFID متصل کنیم برای این کدی که نوشتید
ممنون
با سلام
در بخش شماتیک پروژه RFID میکروپایتون به صورت متنی توضیح داده شده است. طبق توضیحات اقدام کنید.