2026/10/8 23:24:20

ESP32与RC522入门指南:从零搭建RFID刷卡门禁系统

ESP32与RC522入门指南:从零搭建RFID刷卡门禁系统 1. 为什么零基础首选RFID-RC522组合一套不到十块钱的“刷卡”启蒙课我最早接触ESP32的时候周围十个人里有八个都在做LED灯和温湿度传感器。不是说那些不好而是玩到后面你会发现按钮、屏幕、灯带这类外设调通之后总觉得缺了点“交互感”。直到有一天朋友扔给我一块RC522模块说让我做个刷卡开门的小东西我才意识到让ESP32“认识”一张卡片这件事带来的满足感是点灯完全给不了的。RFIDRadio Frequency Identification无线射频识别这个技术名字听起来高深放在生活里其实到处都是。小区单元门的门禁卡、公司的考勤卡、校园卡、图书馆的自助借还书机全是它的应用场景。坐地铁刷的交通卡用ISO/IEC 14443协议RC522模块支持的就是这个协议的衍生兼容型号这意味着你手里那堆M1卡、S50卡都可以拿来跟ESP32玩。这套组合对零基础友好的核心原因有三个模块便宜且皮实RC522成品模块大量产市面上到处能买到坏了不心疼随便折腾。库支持极其成熟MFRC522读卡芯片是恩智浦的老牌芯片Arduino生态里有个传播量极大的MFRC522库示例代码开箱即用基本不需要自己啃寄存器手册。反馈效果好刷卡、亮灯、蜂鸣器响、串口打印卡号这一套交互流程做完你会有“我真的做了一个门禁系统”的真实感这种正反馈对零基础学习者来说非常宝贵。这篇文章适合完全没碰过ESP32的纯新手也适合看完各种教程但始终卡在“读不到卡”的倒霉蛋。我会把从硬件选型、环境配置、接线、代码到故障排查的完整闭环讲清楚所有内容基于我实际跑过几十遍的Arduino开发路线每个坑都有具体的解决办法。2. 硬件清单与选型避坑不只是买一块板子那么简单2.1 主控板选择ESP32开发板怎么挑ESP32的型号非常杂经典款ESP32、ESP32-S3、ESP32-C3、ESP32-C6。对于做RFID刷卡这种基础项目经典款ESP32芯片型号ESP32或ESP32-WROOM-32就足够用了理由是它的资料最多、例程最全遇到问题你能搜到的踩坑记录也最丰富。市面上常见的板子有NodeMCU-32S、ESP32 DevKitC、ESP32-S3 Super Mini等它们引脚布局略有不同但核心芯片一致。我这里以经典ESP32 DevKitC和NodeMCU-32S为例它们的引脚定义基本兼容。几个选板注意点尽量选择有板载USB转串口芯片的版本常见的是CP2102或CH340。系统装不上驱动的先用鲁大师或设备管理器看看USB设备里有没有出现带感叹号的未知设备那多半是驱动问题。CH340需要手动装驱动CP2102一般Windows10以上能自动识别。买的时候看清引脚是否引出排针。有的板子是半孔邮票封装没有排针零基础焊接容易翻车。别在淘宝上买太便宜的无牌ESP32模块有些劣质模块用的Flash芯片是杂牌烧录到一半会随机失败排查起来非常折磨人。2.2 RFID读卡模块RC522的封装差异与细节RC522模块的供应商很多硬件上一般有铝丝邦定的小板子、邮票孔半圆焊盘、以及带排针的成品模块这三种。零基础建议直接买带排针的成品模块引脚标识一般长这样SDA、SCK、MOSI、MISO、IRQ、GND、RST、VCC。排针版本的好处是可以直接插杜邦线不用焊接而且板上已经帮你布好了天线匹配电路。你唯一要留意的是模块背面那个小电阻R部分模块通过它做天线电流调节一般情况下不需要动它。另一个容易忽略的是卡的种类。RC522支持ISO/IEC 14443A协议的M1类卡S50、S70如果家里只有门禁用的ID卡EM4100等低频卡RC522是读不到的。低频125kHz的卡需要配RDM6300模块这里不展开但如果你刷卡一直没反应先查一查卡是不是14443A协议。2.3 基础材料清单物料建议型号/规格数量备注主控板ESP32 DevKitC / NodeMCU-32S1也可以换ESP32-S3接线逻辑一致RFID读卡模块MFRC522RC5221买成品模块带排针IC卡M1白卡/M1钥匙扣卡1-3注意协议是14443A杜邦线公对母、母对母均可若干长度尽量短干扰小面包板标准830孔1可选走线方便蜂鸣器3.3V有源蜂鸣器1可选刷卡提示LED红色/绿色各一各1可选刷卡反馈全套下来成本大约几十块钱而且大部分是长期可复用的基础物料。如果你已经有了ESP32和面包板那你要额外掏的钱基本就只是一个RC522模块和几张白卡不到十几块。3. 开发环境从零到通Arduino IDE与PlatformIO一次讲清3.1 Arduino IDE安装与ESP32离线包配置RFID刷卡项目本身不需要复杂的工程结构用Arduino IDE就够了。但很多人在第一步就被卡住Arduino IDE里搜不到ESP32开发板原因是ESP32不在默认的开发板管理器列表里。你需要在“文件→首选项→附加开发板管理器网址”中添加如下地址https://espressif.github.io/arduino-esp32/package_esp32_index.json添加之后到“工具→开发板→开发板管理器”搜索“esp32”找到“esp32 by Espressif Systems”点安装。这里必须提醒国内网络直接下载ESP32离线包经常失败下载到一半报错是常态。我遇到过无数次“开发板管理器下载失败”“网络错误”其中很多是你已经有加速工具也不好解决的某些下载源在国内响应很慢。如果反复失败建议用以下替代方案用浏览器直接打开上面的JSON地址找到下载列表里对应版本的esp32-2.0.x.zip文件链接用浏览器或下载工具下载。下载完成后把它手动放到Arduino IDE的tools目录下Windows一般在文档/Arduino外的一个独立目录具体看你安装方式再重启IDE。网上存在整合好的“Arduino IDE ESP32离线包”下载解压后覆盖到对应目录即可。这个办法省时省力但要注意包版本和IDE版本匹配否则工具链编译会报错。如果你用的是PlatformIO实际上对下载速度的容忍度更低。PlatformIO基于Python包管理器ESP32平台文件也需要联网拉取国内经常卡在platformio/espressif32安装阶段。解决思路类似借助离线包手动安装或者先安装一次完整的PlatformIO Core再处理平台文件。3.2 安装MFRC522库库的安装非常简单在Arduino IDE的“库管理器”里搜索“MFRC522”第一个就是MFRC522 by GithubCommunity过去叫Miguel Balboa。点安装默认装最新版即可。如果你用的示例代码是老博客里那种#include MFRC522.h写法新旧库兼容性大体没问题。装完之后打开“文件→示例→MFRC522→ReadAndPrint”后面我们基于这个例子展开。3.3 开发板选择与烧录设置拿到ESP32板子在“工具→开发板→开发板管理器”中选择经典ESP32选择“ESP32 Dev Module”NodeMCU-32S同样选“ESP32 Dev Module”因为它的引脚兼容经典DevKitESP32-S3 Super Mini选“ESP32S3 Dev Module”注意Flash大小选8MB如果是8MB版本USB CDC选启用烧录之前有三件事必须检查端口选择在“工具→端口”里选中你的板子对应的COM口。如果看不到端口先检查USB线是不是只有充电功能的数据线很多“不给反馈”的问题其实是数据线不合格。开发板参数默认我一般不改除非你明确知道板载Flash是8MB还是16MB。选错之后编译烧录能通过但有可能烧完无法启动。按住BOOT键某些ESP32板子在串口烧录时必须按住BOOT键插USB或者烧录时按住不放。新版ESP32的USB CDC可以用原生USB口但如果你的板子是老式UART转接方案按BOOT是常规操作。具体型号已刷固件的板子否则自动烧录遇到“同步失败”或“等待下载”时先试BOOT键。烧录成功后串口监视器右下角波特率我习惯设置为115200有的板子默认9600打印乱码就先查波特率。4. 接线实操SPI四线说透了你就不会再虚焊4.1 RC522与ESP32的标准SPI接线RC522模块内部芯片支持SPI和I2C两种接口绝大多数模块默认工作在SPI模式由模块上的三个选择位确定。成品模块一般不让你改所以我们直接用SPI。ESP32的Arduino内核提供两个SPI通道VSPI和HSPI默认的SPI对象对应VSPI引脚如下ESP32引脚DevKit/NodeMCU-32S功能接RC5225SCK时钟SCK23MOSI主出从入MOSI19MISO主入从出MISO18SS片选CSN/SDASDA21RST复位RST3.3VVCCVCCGNDGNDGND不接IRQIRQ暂时悬空这是最常用的默认配置MFRC522库的示例代码ReadAndPrint也恰好用这一组引脚你把ESP32引脚写进去后就能直接跑。注意示例代码里用的是SS_PIN 5还是SS_PIN 10之类取决于你抄的教程版本。如果某篇博客用10那个是针对NodeMCUESP8266的软串口映射不能直接套到ESP32上。一定按你板子的真实SPI引脚来。4.2 供电逻辑5V还是3.3V搞错了会烧模块RC522芯片工作电压是3.3V但很多RC522模块板上带了电平转换电路因此有些卖家会告诉你“可以直接接5V”。这个说法有隐患如果你的RC522模块是带三极管电平转换的大板子接5V是可以工作的但长期运行模块发热明显。如果模块是纯3.3V小模块板子上没有明显电平转换IC你接5V大概率当场冒烟或者永久损伤。我的建议统一接3.3V。ESP32的GPIO也是3.3V逻辑这样最安全不需要考虑电平匹配。事实上MFRC522的SPI接口过压能力较低5V直接灌入会有风险。还要注意RC522的天线驱动电流较大接在同一面包板电源轨上时如果电源走线质量差可能出现读卡距离缩水的问题。ESP32的USB供电一般能提供500mA带RC522和蜂鸣器绰绰有余但面包板电源轨的劣质接插件会导致接触电阻升高换一根质量好的杜邦线就能解决。4.3 蜂鸣器和LED怎么接刷卡反馈是个很重要的体验细节。我通常给蜂鸣器接IO25、LED接IO26中间连一个220欧姆电阻到GND蜂鸣器同样串一个限流电阻有源蜂鸣器3.3V驱动时最好串100欧姆左右。这样代码里控制这两个引脚高低电平就能实现“刷到卡→滴滴绿灯闪”的效果。要是你的蜂鸣器是无源蜂鸣器那需要PWM特定频率才能响新手建议直接买有源蜂鸣器随便给高电平就发声省心。5. 代码走读从初始化到读卡号的完整链路5.1 完整示例代码可直接烧录下面这段代码是我在官方示例基础上精简并加了中文注释的版本直接覆盖MFRC522的读取流程。需要先确保你已经装好了MFRC522库。#include SPI.h #include MFRC522.h // 引脚定义ESP32 DevKit/NodeMCU-32S #define RST_PIN 21 #define SS_PIN 18 MFRC522 mfrc522(SS_PIN, RST_PIN); // 创建读卡器对象 // 刷卡成功后的提示灯和蜂鸣器 #define BUZZER_PIN 25 #define LED_PIN 26 void setup() { Serial.begin(115200); while (!Serial); // 等待串口就绪 SPI.begin(); // 初始化SPI总线 mfrc522.PCD_Init(); // 初始化RC522芯片 delay(10); mfrc522.PCD_DumpVersionToSerial(); // 打印固件版本正常能看到 0x922.0等 pinMode(BUZZER_PIN, OUTPUT); pinMode(LED_PIN, OUTPUT); Serial.println(把卡片放到读卡器上方...); } void loop() { // 每次循环先检查有没有新卡进入感应区 if (!mfrc522.PICC_IsNewCardPresent()) { delay(50); return; } // 选中这张卡得到它的UID唯一标识 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); if (i ! mfrc522.uid.size - 1) { Serial.print( ); } } Serial.println(); // 提示音和亮灯 digitalWrite(LED_PIN, HIGH); digitalWrite(BUZZER_PIN, HIGH); delay(200); digitalWrite(LED_PIN, LOW); digitalWrite(BUZZER_PIN, LOW); // 停止与当前卡的会话等待下一张 mfrc522.PICC_HaltA(); delay(1000); }5.2 代码里的关键原理这部分看懂了以后玩任何读卡器都不慌这一段值得多说几句因为MFRC522库把底层寄存器操作封装得很好很多人用起来反而不知道为什么“卡号从这里来”。掌握它你以后换STM32、树莓派或者其他读卡模块时思路是通的。第一步是SPI.begin()。RC522通过SPI协议和主控通信SPI有四个引脚SCK是时钟线主机和从机都靠这个时钟同步数据MOSI是主机到从机的数据线MISO是从机到主机的数据线SS是从机片选信号拉低代表主机选中了这一个从机设备。ESP32就是SPI主机RC522是从机数据按字节来回交换。第二步是PCD_Init()。PCD是“Proximity Coupling Device”的缩写也就是读卡器端。它做的事情包括复位RC522芯片、设置发送/接收缓冲区、设置天线增益、激活天线。校准天线是一个细节读卡距离不够时很多时候就是初始化后天线驱动电流偏低可以通过MFRC522的PCD_SetAntennaGain()函数调整寄存器值来加大天线功率。第三步是PICC_IsNewCardPresent()和PICC_ReadCardSerial()。PICCProximity Integrated Circuit Card指的是卡片端。卡片靠近天线时天线的电磁场会为卡片内的芯片供能卡芯片通电后开始响应读卡器的请求。IsNewCardPresent本质上是读RC522的寄存器看有没有检测到新的卡应答信号。紧接着ReadCardSerial会让读卡器发送防碰撞指令如果感应区内有多张卡它会先根据卡号逐位仲裁最终选中一张把它的UID取回来。UID就是卡的全局唯一ID出厂时已经固化在卡内。M1卡的UID一般4字节也有7字节的我们打印的就是这个值。UID对门禁来说就是“身份”你后续要做考勤、权限管理都是基于这个UID做比对。5.3 串口监视器看不到调试信息的自检流程烧录完打开串口监视器如果大片空白或者乱码优先顺序排查波特率是否设置了115200Arduino IDE右下角修改波特率。板子复位后串口监视器会不会打印Boot信息如果连Boot信息都没有说明串口硬件连接或驱动有问题。如果能看到“把卡片放到读卡器上方...”但没有固件版本号大概率是SPI接线错误。重查SDA/SCK/MOSI/MISO四条线是否接对特别是SDA别接到RC522模块的电源引脚上去。如果固件版本打印出来了但放卡没反应检查卡片协议是不是14443A以及卡片是否接触到天线感应范围贴近模块线圈上方不要隔着金属覆盖物。6. 不响应的真正原因仔细排查比换模块重要得多6.1 “模块识别不了卡”的常见故障树作为一个踩坑无数的人我可以负责任地说RC522读不到卡绝大多数时候模块是好的问题出在以下几类按概率从高到低排列故障现象最可能原因解决办法初始化打印版本号失败SPI接线错位、SDA/SCK接反用万用表蜂鸣档测连通性重插杜邦线版本号正常但读不到卡卡片不是14443A协议比如是ID低频卡换M1卡测试版本号正常且能读卡但刚刷完就没反应卡停留在感应区时间过长卡片进入休眠代码加PICC_HaltA后再放卡或手动拿开再放能读卡但卡号随机跳变供电不稳、天线接触不良检查电源轨和杜邦线缩短导线长度能读卡但偶尔死机供电瞬时电流不足改用独立稳压模块供电别只用USB我这里特别强调一种很隐蔽的情况卡片放在金属面上或者手掌完全盖住天线。RC522靠电磁感应给卡片供电金属导体在感应区内会涡流损耗信号能量导致卡片“无法被唤醒”。如果你把模块贴在铁制桌面板上测试读不到卡太正常了。把模块悬空或者垫一个绝缘泡沫再测试。6.2 从寄存器层面排查PCD_DumpVersionToSerial打印0x00的含义当你看到版本号输出0x00而不是0x92时很多人直接怀疑模块坏了。但实际我见过太多案例问题在模块的RST引脚没接对。RC522的复位脚不是摆设初始化时MCU会控制这个引脚做一次硬件复位。RST悬空或者接错到GND芯片会一直处于复位状态。MOSI和MISO焊点短路或者杜邦线内部断裂。模块的SDA引脚名对应的是SPI的CS片选信号很多人以为是I2C的SDA数据线。接线时如果按字面理解接到21或其他I2C引脚上SPI自然通不了。你可以直接把RST_PIN从21改成其他IO口如16再用软件复位试试。MFRC522库支持硬件复位和软件复位两种方式如果硬件RST那条线有干扰换引脚往往立竿见影。6.3 给新手的排障实践断电重插、单独测试、替换法完整排障顺序我个人是按“看-摸-换”三步走的看串口监视器是否打印初始化信息、固件版本。如果没有任何输出回到第5.3节的串口自检。摸上电后手指轻轻触碰RC522天线线圈看读卡器是否有响应某些模块靠近金属会有天线场变化。如果模块微微发热基本可以确认供电和芯片工作正常。换换一张卡、换一根杜邦线、换一个USB口。替换法是最无脑但最有效的排查方式尤其适合零基础——一次只换一个变量才能定位真凶。7. 让刷卡事件“主动”起来外部中断实战7.1 轮询方式的局限上面示例代码是轮询模式loop循环里不停地问“有没有新卡”。对RFID读卡这种操作轮询完全够用。但如果你未来想把刷卡做成一个真正的事件触发系统——比如刷卡后执行很长的任务流程轮询就会暴露问题长时间执行其他任务时卡片感应到了但代码根本来不及读取卡已经离开了。这也是关联热搜词里“esp32外部中断实战”很重要的原因。ESP32支持GPIO外部中断你可以在IRQ引脚上做一个“卡片靠近”的通知机制。RC522模块的IRQ引脚在感应到卡片时会拉低低电平有效。我们只需要把这个引脚接在ESP32的一个支持中断的GPIO上在代码里注册一个下降沿中断服务函数设置一个标志位主循环检测到标志位后再去读卡效率会高很多逻辑也更优雅。7.2 ESP32中断代码改造示例#include SPI.h #include MFRC522.h #define RST_PIN 21 #define SS_PIN 18 #define IRQ_PIN 22 // RC522的IRQ脚接ESP32的GPIO22 MFRC522 mfrc522(SS_PIN, RST_PIN); volatile bool cardDetected false; void IRAM_ATTR onCardInterrupt() { cardDetected true; } void setup() { Serial.begin(115200); SPI.begin(); mfrc522.PCD_Init(); // RC522 IRQ配置启用“新卡到达”中断 pinMode(IRQ_PIN, INPUT_PULLUP); attachInterrupt(digitalPinToInterrupt(IRQ_PIN), onCardInterrupt, FALLING); Serial.println(中断模式启动); } void loop() { // 中断来了再执行读卡流程 if (cardDetected) { cardDetected false; if (mfrc522.PICC_IsNewCardPresent() mfrc522.PICC_ReadCardSerial()) { for (byte i 0; i mfrc522.uid.size; i) { Serial.print(mfrc522.uid.uidByte[i], HEX); } Serial.println(); mfrc522.PICC_HaltA(); } } }这里需要提醒中断服务函数里不能做耗时操作比如打印、读卡、驱动蜂鸣器。ESP32的中断服务函数被限制在IRAM中运行代码量要尽量少我们只置一个标志位实际工作交给loop完成。另外RC522模块的IRQ在复位后默认是“天线驱动开启”状态需要确保初始化时芯片的IRQ输出模式已正确配置否则可能一直触发中断。MFRC522库本身没有直接开放这一层配置如果你发现IRQ乱跳可以用mfrc522.PCD_WriteRegister手动设置寄存器但零基础阶段建议先用轮询模式跑通项目再做中断优化。7.3 中断方案的适用场景外部中断适合复用MCU做多任务不想让loop循环频繁轮询。刷卡事件需要以“低延迟”响应比如门禁锁控制系统。想学ESP32中断编程为更复杂项目打基础。轮询适合新手第一次跑通RFID流程。一个项目里只有刷卡这一件事没必要引入中断复杂度。说实话我自己做的门禁原型用的就是中断方案因为同时还要驱动OLED显示、继电器开锁、做网络事件上报。但如果你还在入门阶段先把轮询代码跑通再升级到中断你会对两者的差异有非常直观的感受。8. 把“刷卡”变成“门禁”数据校验与多卡管理8.1 把卡号变成白名单单纯打印UID只是第一步真正让ESP32“拥有刷卡能力”的是对卡号的判断。比如你已经读出了卡号A1 B2 C3 D4你希望在只有特定卡被刷时开锁。代码追加一个简单的校验byte authorizedUID[4] {0xA1, 0xB2, 0xC3, 0xD4}; bool isAuthorized(MFRC522::Uid uid) { if (uid.size ! 4) return false; for (byte i 0; i 4; i) { if (uid.uidByte[i] ! authorizedUID[i]) return false; } return true; }然后在读取到卡号后判断if (isAuthorized(mfrc522.uid)) { Serial.println(授权卡开锁); // 控制继电器或者舵机 } else { Serial.println(未授权卡报警); }这个白名单你可以存放在数组中也可以后续扩展到Preferences库写入NVS闪存、通过WiFi从云端拉取、或者在串口/小程序里动态添加。多卡管理本质上就是管理一个数组或者列表比如byte whitelist[8][4] { {0xA1, 0xB2, 0xC3, 0xD4}, {0x12, 0x34, 0x56, 0x78}, // 最多8张 };零基础阶段先把数组做起来后面再慢慢换成更复杂的存储方案。多卡管理时记得留一条“忘记自己卡号导致连锁不上”的路给系统加一个“录入模式”用串口发指令进入学习状态然后刷一张新卡自动把UID加入白名单。这套思路可以直接套用到考勤系统。热搜词里出现“C# RFID考勤系统”说明不少人在做上位机。ESP32读卡后通过串口或WiFi把UID发到PC端的C#程序C#负责和数据库交互、统计考勤记录。对零基础来说先把ESP32端“读到的卡号可靠地发给电脑”这件事做扎实后面的上位机只是流程问题。8.2 一卡一密与安全边界RC522能做的远不止读UID。M1卡S50内部有16个扇区每个扇区有独立的KEY A、KEY B和数据块。这意味着你可以在卡内存储自定义数据比如钱包余额、工号、权限等级。但这里必须提一句M1卡的安全性并没有你想的那么高。经典的M1卡加密算法已经被破解多年卡内的密文理论上可以被克隆和篡改这就是为什么很多新门禁系统开始转向CPU卡和手机NFC动态凭证。如果你用RC522做门禁建议不要只凭UID判断权限UID可以复制到空白卡俗称“复制卡”物理安全级别很低。如果只是学习和技术研究完全无所谓如果真要部署到真实场景要把安全风险考虑进去。我在做考勤项目时会把卡内写入用户ID校验位不直接暴露数据库主键并且每次读取做二次校验。这套方案不够高级但足以应对学习场景。8.3 写卡操作往M1卡里存数据除了读UID你还可以写卡。MFRC522库自带一个MFRC522_DumpInfo示例展示如何读取扇区数据。往指定扇区写数据的关键代码大致是MFRC522::MIFARE_Key key; for (byte i 0; i 6; i) key.keyByte[i] 0xFF; // 默认密钥FF MFRC522::StatusCode status mfrc522.PCD_Authenticate( MFRC522::PICC_CMD_MF_AUTH_KEY_A, trailerBlock, key, (mfrc522.uid) ); status mfrc522.MIFARE_Write(blockNumber, buffer, 16);注意写卡前必须先用密钥认证默认出厂密钥是FFFFFFFFFFFF。写卡之后可以用读卡器读回来校验数据是否一致。这个操作的实际意义是你可以给每张卡打上编号、姓名编码、有效期等信息下次刷卡时不靠UID而靠卡内数据判断身份。对零基础来说写卡是一个很好的进阶练手项目能帮你理解卡的内部存储结构但我不建议第一个项目就碰容易因为一个字节的误差卡住一整晚。9. 扩展玩法从读卡到真正的IoT门禁系统9.1 接入WiFi让刷卡记录远程可见ESP32自带WiFi和蓝牙这是它比普通Arduino强太多的地方。你可以把每一张刷卡记录通过MQTT或者HTTP请求发给服务器、小程序、或者本地已经跑起来的Nodered。我最常用的一个组合是ESP32做主控RC522读卡。刷卡后ESP32通过WiFi向本地MQTT broker比如Mosquitto发送一条包含UID和时间戳的JSON消息。服务端订阅MQTT消息存入数据库前端展示。ESP32发送MQTT数据极其简单先安装PubSubClient库然后#include WiFi.h #include PubSubClient.h const char* ssid 你的WiFi; const char* password 密码; const char* mqttServer 192.168.1.100; WiFiClient espClient; PubSubClient client(espClient); void setup() { WiFi.begin(ssid, password); while (WiFi.status() ! WL_CONNECTED) { delay(500); } client.setServer(mqttServer, 1883); } void sendLog(byte* uid, byte size) { if (!client.connected()) { client.connect(ESP32RFID); } char msg[64]; sprintf(msg, {\uid\:\); for (byte i 0; i size; i) { sprintf(msg strlen(msg), %02X, uid[i]); } strcat(msg, \}); client.publish(home/rfid/access, msg); }这一套实现之后刷卡就不仅仅是一个单机活动而是整个IoT系统的一部分。你可以在手机小程序上看到谁在几点刷了卡也可以在服务端做异常时段报警。9.2 用PlatformIO重构工程化管理与OTA升级如果你的项目规模变大比如有了Web配置界面、OTA、自定义库文件从Arduino IDE迁移到PlatformIO会很值得。PlatformIO本质上是一套基于VS Code的嵌入式开发环境它帮你管理库依赖和编译配置。在PlatformIO里新建ESP32项目时platformio.ini配置核心只需要这几行[env:esp32dev] platform espressif32 board esp32dev framework arduino lib_deps miguelbalboa/MFRC522然后把Arduino代码放到src/main.cpp中编译烧录就完成了。PlatformIO的好处是每次构建不会因为“库版本被自动更新”而出现莫名其妙的问题所有依赖都锁定在lib_deps里。另一个优点是你可以很方便地配置board_build.flash_size等参数对不同开发板做适配。这里又回到热搜词里的“platformio开发esp32项目esp32加快编译速度”。PlatformIO首次编译ESP32项目要拉取工具链非常慢。我的建议是别开着实时杀毒软件扫项目文件夹把项目的~/.platformio目录加入杀毒排除名单另外编译时不开太多VS Code插件能明显改善编译速度。9.3 MicroPython思路换一种语言玩RFID如果你对C编译不感兴趣也可以用MicroPython。ESP32刷入MicroPython固件后可以用Python代码直接调用MFRC522模块。网上有一个叫mfrc522-python的库GitHub上能找到安装方式通常是上传mfrc522.py到板子。一个最简单的MicroPython读取版本from mfrc522 import MFRC522 from machine import Pin, SPI spi SPI(2, baudrate1000000, polarity0, phase0) rdr MFRC522(spispi, gpioRst21, gpioCs18) 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: uid {} {} {} {}.format( raw_uid[0], raw_uid[1], raw_uid[2], raw_uid[3]) print(Read UID:, uid) rdr.stop_crypto1() # 在这里做判断和处理MicroPython的调试速度是真快改完就能跑尤其适合逻辑迭代。不过MicroPython生态在ESP32上的中断、底层寄存器访问、时序敏感任务上表现不如Arduino框架稳健。如果你要做高频读卡或复杂延时逻辑还是回Arduino C更稳。10. 项目中后期必须面对的稳定性问题10.1 看门狗死机后自动重启在真实运行场景中ESP32偶尔会卡死。最常见的原因是WiFi连接超时等待阻塞了loop或者电源波动导致外设无响应。解决思路是启用看门狗定时器WDT。Arduino框架下有两种方式软件看门狗esp_task_wdt_init或者简单地在loop里用millis()做超时判断。如果是WiFi卡住更要紧的是给WiFi.begin设置超时重试逻辑而不是依赖看门狗去重启。// 简易WiFi连接超时处理 int wifiAttempts 0; WiFi.begin(ssid, password); while (WiFi.status() ! WL_CONNECTED wifiAttempts 20) { delay(500); wifiAttempts; } if (WiFi.status() ! WL_CONNECTED) { Serial.println(WiFi连接失败稍后重试); }这一点非常重要很多做门禁项目的人把设备部署后过几天就发现设备“掉线了”其实就是WiFi连接状态的异常导致系统假死。10.2 数据的持久化断电后白名单不能丢默认情况下白名单存在数组里断电就清零。如果想让设备记录最新状态有两条路线使用ESP32的Preferences库对Arduino框架好用#include Preferences.h Preferences prefs; prefs.begin(rfid, false); uint8_t uid prefs.getUChar(auth0, 0); prefs.putUChar(auth0, uid);存到SD卡/TF卡模块。RC522项目和SD卡模块可以共存于同一个SPI总线上但要处理好片选引脚SD卡用CS15RC522用CS18互不干扰。通过WiFi把白名单放到云端掉电后从云端拉取。这才是真正稳定的方案。10.3 低功耗电池供电的门禁怎么省电如果你的刷卡设备要装到户外或者门边大概率不能用插电适配器。ESP32的深睡模式Deep Sleep方案很成熟平时进入深度睡眠电流可以做到几十微安。外部唤醒方式很多比如RC522的IRQ引脚可以通过EXT1唤醒ESP32。但要命的问题是RC522模块本身耗电不低模块通电时的功耗通常在几十到上百毫安深睡电路设计不好等于没省。所以低功耗方案需要给RC522单独加MOS管控制电源刷卡前才给模块上电读完之后再断电同时配合外部中断唤醒。这是另外一个深入的话题零基础可以先了解方向等基础扎实再搞。11. 五六个项目之后回头看我的几点实在经验做RFID刷卡这个项目我从“读个卡号都欣喜若狂”到后来做完整的门禁考勤系统中间踩过的坑基本都写在这篇文章里了。最后随手列几条我自己最深的体会一是先把最简单的流程完整跑通再谈优化。很多人一上来就想做“刷卡OLEDWiFi小程序”结果每个环节都在翻车最后根本不知道是哪个模块的问题。我的习惯是先只读卡号驱动亮灯再判断白名单再上OLED再连WiFi。每加一块功能都确认前面还好好的没有坏这样排障半径始终很小。二是RC522的读卡距离天生有限。它的天线是PCB蚀刻线圈有效距离大约3到6厘米。如果你的项目需要远距离感应比如停车场扣费RC522不是合适的方案去看125kHz或超高频UHF模块。三是接线永远比你想象的更关键。我见过太多“模块坏了”的冤案最终发现是杜邦线内部断了或者是面包板同一排插孔因为老化接触不良。你要养成一个好习惯模块不工作第一件事是万用表测一下引脚电压和导通性而不是立刻下单买新模块。四是记录你的卡号。做测试时打印的UID一定要截图或者抄下来存好。因为一旦你做了白名单校验忘记录入白名单的卡就会变成“打不开门的卡”而你自己又不知道哪张才是对的那画面很难看。最后再说一个实用技巧串口监视器里把波特率统一设置成115200后无论是Arduino IDE还是PlatformIO的串口监视器都要保持一致否则你看到的调试输出是乱码或者完全没有。这个细节我教过好几个人他们都在这里白白浪费过时间。RFID这个方向入门门槛低但往上走的空间其实不小——从读UID到读写扇区、从单机判断到联网考勤、从轮询到中断唤醒每一步都能学到新的东西。你拿着这篇文章跑通第一张卡之后后面想怎么玩就全凭你的想象力了。