ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

ESP32搭配MFRC522 RFID模块:从零实现刷卡读卡项目实战

ESP32搭配MFRC522 RFID模块:从零实现刷卡读卡项目实战 1. 从零上手为什么选择ESP32搭配RFID做刷卡项目很多人第一次接触物联网开发都是从一块几十块钱的ESP32开发板开始的。这块小板子集成了WiFi和蓝牙双核处理器跑起来性能绰绰有余GPIO口丰富社区生态也成熟关键是价格便宜坏了不心疼。但光有ESP32还不够它本身没有感知“卡片”的能力得给它配一个“读卡器”——这就是RFID模块登场的地方。RFID全称是Radio Frequency Identification中文叫无线射频识别。它的原理其实不复杂读卡器天线发射特定频率的电磁波当一张RFID卡片靠近时卡片内部的线圈通过电磁感应获得能量然后把存储的ID信息通过电磁波反射回去。整个过程不需要接触也不需要电池卡片可以做得像一张薄薄的塑料片。我们平时用的门禁卡、公交卡、食堂饭卡底层都是这套逻辑。那为什么选MFRC522这个模块市面上RFID模块不少但MFRC522几乎是入门者的标配。它工作在高频13.56MHz频段支持ISO 14443A协议能读写Mifare Classic系列卡片SPI接口通信Arduino和MicroPython都有现成的库。价格便宜到离谱几块钱就能买一个还附带一张白卡和一枚钥匙扣卡。对于“让ESP32拥有刷卡能力”这个目标来说MFRC522是最短路径。这个项目适合谁如果你刚学完ESP32的点灯和串口打印想找一个有实际反馈、能快速看到效果的练手项目RFID刷卡就是很好的选择。它涉及SPI通信、中断处理、卡片数据解析这几个核心知识点做完之后你对嵌入式系统的理解会上一个台阶。而且这个项目可以自然延伸到考勤系统、门禁控制、会员积分等真实场景不是那种做完就扔的玩具。我见过不少初学者卡在“读不到卡”这一步然后就放弃了。其实大部分问题都出在接线和供电上跟代码关系不大。下面我会把整个流程拆开从硬件选型到代码调试把踩过的坑都标出来。2. 硬件选型与接线别让一根杜邦线毁掉整个项目2.1 核心硬件清单与选型逻辑先列一下这个项目需要的东西都是很基础的配件硬件型号/规格数量备注主控板ESP32开发板任意型号1推荐ESP32 DevKit V1或ESP32-S3RFID模块MFRC5221注意买3.3V版本卡片Mifare Classic 1K1-2通常买模块会附赠杜邦线母对母7根建议用不同颜色区分面包板半尺寸1可选但强烈建议选ESP32而不是Arduino Uno的原因很简单ESP32原生3.3V逻辑电平跟MFRC522完美匹配。如果用Arduino Uno这种5V的板子还得加电平转换电路多一层麻烦。ESP32的SPI接口速度也够快默认时钟可以跑到几MHz读卡响应很快。MFRC522模块要注意版本。市面上有3.3V和5V两种虽然很多5V版本板载了稳压芯片但通信电平还是5V直接接ESP32会烧引脚。买的时候看清楚描述或者用万用表量一下VCC和GND之间的电压。我一般建议直接买3.3V版本省心。2.2 SPI接口的接线细节与避坑MFRC522和ESP32之间走的是SPI协议。SPI全称Serial Peripheral Interface是一种高速全双工通信总线需要四根线SCK时钟、MOSI主出从入、MISO主入从出、SS片选。再加上电源和复位一共七根线。接线表如下以ESP32 DevKit V1默认SPI引脚为例MFRC522引脚ESP32引脚说明SDA/SSGPIO5片选低电平有效SCKGPIO18时钟MOSIGPIO23主设备输出MISOGPIO19主设备输入IRQ不接中断引脚轮询模式可省略GNDGND共地RSTGPIO22复位3.3V3.3V供电这里有几个坑要重点说。第一供电必须用3.3V绝对不能接5V。有些开发板标着“5V”的引脚其实是输入输出都5V接上去模块瞬间发烫。第二GND一定要共地我见过有人只接了三根SPI线忘了接地结果读卡时好时坏查了半天。第三杜邦线不要太长超过20厘米信号质量就下降读卡距离会明显缩短。如果必须延长用屏蔽线或者降低SPI时钟频率。还有一个容易忽略的点ESP32的SPI引脚是可以重映射的。上面表格里是默认的VSPI引脚你也可以在代码里指定其他GPIO。但新手建议先用默认引脚减少变量。等跑通了再折腾引脚重映射。注意接线完成后先不要插卡上电后用万用表量一下MFRC522的VCC和GND之间是不是3.3V。确认无误再进行下一步。2.3 电源稳定性对读卡距离的影响MFRC522的读卡距离标称是3-5厘米但实际用下来很多人的模块只能读到1厘米以内甚至要贴着才能读。除了天线设计本身电源质量是最大影响因素。ESP32在WiFi工作时瞬间电流能到500mA如果USB供电不足电压会跌落MFRC522的射频部分就工作不正常。我的做法是调试阶段先关闭WiFi用USB供电就够了。如果项目最终要联网建议给ESP32单独供5V/2A的电源或者加一个大电容1000uF在3.3V和GND之间做缓冲。实测下来加电容后读卡距离能从1厘米恢复到3厘米左右。另外MFRC522模块背面有一个天线线圈那个区域不要放金属物体也不要用手直接按住否则会吸收电磁波读卡距离骤降。我一开始把模块放在金属桌面上调试怎么都读不到后来垫了一张纸就好了。3. 开发环境搭建MicroPython还是Arduino3.1 两种路线的对比与选择ESP32的开发方式很多主流的有Arduino IDE、ESP-IDF、MicroPython三种。对于RFID这个项目我推荐MicroPython或者ArduinoESP-IDF有点重了。MicroPython的优势是代码简洁交互式REPL调试方便改一行跑一行特别适合快速验证。缺点是库的成熟度不如Arduino有些底层功能要自己写。Arduino的优势是生态成熟MFRC522库经过多年迭代稳定可靠社区问题多遇到坑一搜就有答案。缺点是编译上传慢调试靠串口打印效率低一些。我的建议是如果你之前用过Python直接上MicroPython半天就能跑通。如果你完全零基础Arduino的示例代码更多跟着教程走不容易卡住。下面我两种都讲你选一条路走就行。3.2 MicroPython固件烧录与环境配置先讲MicroPython路线。第一步是给ESP32烧录固件。去MicroPython官网下载最新的ESP32固件一般是.bin文件。然后用esptool工具烧录esptool.py --chip esp32 --port /dev/ttyUSB0 erase_flash esptool.py --chip esp32 --port /dev/ttyUSB0 --baud 460800 write_flash -z 0x1000 esp32-20230426-v1.20.0.binWindows用户把/dev/ttyUSB0换成COM3之类的端口号。烧录完成后用串口工具连接波特率115200按一下ESP32的EN键应该能看到MicroPython的REPL提示符。接下来需要把MFRC522的驱动库传到ESP32上。MicroPython没有内置这个库得自己找。GitHub上有几个版本我常用的是mfrc522.py这个文件。用ampy或者Thonny IDE上传到ESP32的文件系统里。Thonny IDE对新手最友好直接打开文件点“保存到MicroPython设备”就行。上传后在REPL里输入import mfrc522不报错就说明库加载成功了。3.3 Arduino IDE环境配置与库安装Arduino路线的话先装Arduino IDE然后在“首选项”里添加ESP32的开发板管理器网址。打开“开发板管理器”搜索esp32安装最新版本。这个过程可能要下载几百MB的文件网络不好的话会很慢。有个技巧是使用离线包网上有人打包好了完整的ESP32开发板支持包解压到Arduino的hardware目录下就行省去下载时间。装好开发板支持后再装MFRC522库。在“库管理器”里搜索“MFRC522”选Miguel Balboa那个版本安装。这个库自带示例代码在“文件-示例-MFRC522”里能找到ReadNUID和DumpInfo两个例子直接拿来改就行。Arduino IDE的编译速度在Windows上确实慢尤其是第一次编译。有个办法是关闭杀毒软件的实时扫描或者把Arduino的临时目录加到白名单里。实测能快30%左右。提示无论用哪种方式上传代码前都要确认开发板型号和端口选对了。ESP32有很多变种选错了编译能过但跑不起来。4. 核心代码实现从读卡到解析卡号4.1 MicroPython版本精简驱动与读卡逻辑先看MicroPython的代码。整个逻辑分三步初始化SPI和MFRC522、轮询检测卡片、读取卡片的UID。from machine import Pin, SPI import mfrc522 import time # 初始化SPI spi SPI(2, baudrate2500000, polarity0, phase0, sckPin(18), mosiPin(23), misoPin(19)) # 初始化MFRC522 rdr mfrc522.MFRC522(spi, csPin(5), rstPin(22)) print(等待刷卡...) while True: # 检测是否有卡片靠近 stat, tag_type rdr.request(rdr.REQIDL) if stat rdr.OK: # 防冲突获取UID stat, raw_uid rdr.anticoll() if stat rdr.OK: uid 0x%02x%02x%02x%02x % (raw_uid[0], raw_uid[1], raw_uid[2], raw_uid[3]) print(读到卡片UID:, uid) time.sleep(1) # 防止重复读取 time.sleep(0.1)这段代码里request函数发送寻卡指令REQIDL表示寻找未进入休眠的卡片。anticoll是防冲突机制因为同时有多张卡在天线范围内时需要一套算法来选出其中一张。返回的raw_uid是一个5字节的列表前4个字节是卡号第5个是校验字节。baudrate2500000是SPI时钟频率2.5MHz。这个值可以调太高了通信不稳定太低了读卡慢。实测2.5MHz在大多数模块上都能稳定工作。4.2 Arduino版本使用成熟库快速实现Arduino的代码更简单因为库把细节都封装好了#include SPI.h #include MFRC522.h #define SS_PIN 5 #define RST_PIN 22 MFRC522 mfrc522(SS_PIN, RST_PIN); void setup() { Serial.begin(115200); SPI.begin(); mfrc522.PCD_Init(); Serial.println(等待刷卡...); } void loop() { if (!mfrc522.PICC_IsNewCardPresent()) { return; } if (!mfrc522.PICC_ReadCardSerial()) { return; } Serial.print(UID: ); for (byte i 0; i mfrc522.uid.size; i) { Serial.print(mfrc522.uid.uidByte[i] 0x10 ? 0 : ); Serial.print(mfrc522.uid.uidByte[i], HEX); } Serial.println(); delay(1000); }PICC_IsNewCardPresent检测新卡片PICC_ReadCardSerial读取序列号。这两个函数内部已经处理了防冲突和校验用起来很省心。uid.size通常是4但有些卡片是7字节的UID代码里用循环处理兼容性更好。4.3 卡号解析与数据格式处理读到的UID是一串十六进制字节比如0x1A2B3C4D。实际使用中我们通常需要把它转成十进制或者字符串形式方便存储和比对。MicroPython里可以用int.from_bytes转换Arduino里用strtoul或者手动拼接。这里有个细节不同卡片的UID长度可能不一样。Mifare Classic 1K通常是4字节UID但有些兼容卡是7字节。如果你的项目要兼容多种卡片代码里要判断长度不能写死4字节。另外UID只是卡片的唯一标识卡片内部还有16个扇区每个扇区有独立的密钥和存储空间。如果要读写数据还需要认证密钥。MFRC522库提供了PCD_Authenticate函数默认密钥是0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF。这个后面做门禁系统时会用到。注意读卡时如果串口打印乱码先检查波特率是不是115200。ESP32的默认串口波特率是115200但有些例程用的是9600不匹配就会乱码。5. 常见问题排查读不到卡怎么办5.1 硬件层排查供电、接线、天线读不到卡是最常见的问题我把它分成硬件和软件两层来排查。硬件层先查三件事供电、接线、天线。供电用万用表量MFRC522的VCC和GND必须是稳定的3.3V。如果电压低于3.0V射频部分可能不工作。接线重点查SPI四根线有没有接反特别是MOSI和MISO接反了数据传不过来。天线部分看模块背面有没有金属物体或者手按住移开再试。还有一个隐蔽的问题有些ESP32开发板的3.3V引脚输出电流有限带不动MFRC522。可以试试从外部电源给模块单独供3.3V只把GND和信号线连到ESP32。5.2 软件层排查SPI配置与库版本软件层先确认SPI初始化的参数对不对。MicroPython里SPI(2, ...)表示用VSPI对应GPIO18/23/19。如果你用的是HSPI引脚不一样要改成SPI(1, ...)。Arduino里SPI.begin()默认用VSPI如果要改引脚得用SPI.begin(sck, miso, mosi, ss)。库版本也要注意。MFRC522的MicroPython库有好几个分支有些老版本不支持新的ESP32固件。建议用最近一年内更新过的版本。Arduino库相对稳定但也要确认装的是Miguel Balboa的版本不是其他同名库。如果以上都查了还是不行可以打开调试输出。MicroPython的mfrc522.py里有个debug变量设成True会打印详细的通信数据。Arduino库可以用mfrc522.PCD_DumpVersionToSerial()打印模块版本号确认SPI通信正常。5.3 常见问题速查表现象可能原因解决方法完全读不到卡供电不足量电压换电源加电容读卡距离短天线受干扰移开金属垫高模块串口乱码波特率不匹配改成115200偶尔读到偶尔读不到接线松动重新插拔杜邦线编译报错找不到库库未安装库管理器安装或手动导入上传失败端口被占用关闭串口监视器换端口卡片UID全为0卡片类型不支持换Mifare Classic卡ESP32反复重启电流不够换USB线或外部供电这张表是我自己踩坑总结的大部分问题都能对上。如果还是解决不了把接线拍张照发到社区通常十分钟内就有人指出问题。6. 从读卡到应用项目延伸与实战建议6.1 刷卡控制继电器门禁原型读到卡号之后最自然的延伸就是控制一个继电器模拟门禁开关。继电器模块接ESP32的一个GPIO代码里判断UID是否在白名单里是就拉高继电器一秒然后拉低。WHITELIST [0x1a2b3c4d, 0x5e6f7a8b] if uid in WHITELIST: relay.value(1) time.sleep(1) relay.value(0) print(开门) else: print(卡号未授权)这个逻辑很简单但已经是一个完整的门禁系统核心了。实际部署时白名单可以存在ESP32的Flash里断电不丢失。MicroPython可以用json模块读写文件Arduino可以用EEPROM库。6.2 联网上传刷卡记录对接物联网平台ESP32的WiFi能力在这里派上用场。每次读到卡把UID和时间戳通过HTTP或者MQTT上传到服务器就能做考勤记录或者出入统计。MicroPython的urequests库可以发HTTP请求Arduino的HTTPClient库也很方便。我试过用MQTT协议上传到公共的物联网平台延迟在几百毫秒以内稳定性不错。注意WiFi和SPI同时工作时电源要够否则WiFi一连接读卡就失灵。解决办法是给ESP32单独供5V/2A或者在代码里让WiFi和读卡分时工作。6.3 低功耗与断电运行电池供电场景如果项目要电池供电比如便携式考勤机低功耗就是关键。ESP32有深度睡眠模式电流可以降到10uA左右。但MFRC522在睡眠时也要断电否则它会持续耗电。可以用一个GPIO控制MFRC522的VCC不用时切断电源。MicroPython的machine.deepsleep()可以让ESP32进入深度睡眠定时唤醒或者用外部中断唤醒。MFRC522的IRQ引脚可以接到ESP32的RTC GPIO上有卡靠近时唤醒ESP32。这样待机电流可以做到毫安级两节AA电池能用几个月。不过要注意深度睡眠唤醒后程序从头开始跑SPI和MFRC522都要重新初始化。所以代码结构要调整把初始化放在main函数里唤醒后先初始化再读卡。6.4 我个人的实操心得最后分享几个我踩过坑之后总结的经验。第一调试阶段先跑通读卡再考虑联网。WiFi和SPI同时调出了问题很难定位是哪个环节。第二卡片不要放在手机背面手机里的金属和磁体会干扰RFID我试过把卡贴在手机上怎么都读不到拿开就好了。第三多备几张卡不同厂家的Mifare卡兼容性有差异有的卡MFRC522能读有的读不了换一张卡就能排除是不是卡片问题。还有一点MFRC522模块用久了天线线圈的焊点可能会裂表现为读卡距离越来越短。用手按一下天线区域如果距离恢复就是焊点问题补焊一下就行。这个故障很隐蔽我遇到过两次都是模块用了半年之后出现的。这个项目做完之后你对SPI通信、中断处理、卡片数据解析都有了实战经验。下一步可以试试读写卡片扇区数据或者做一张自己的“会员卡”存上余额和消费记录。RFID的世界比想象中大MFRC522只是入口。
返回列表