Arduino RC522 RFID读卡器故障:使用一段时间后无法读取标签
解决你的Arduino户外灯光系统RFID失效问题
嘿,作为刚入门编程的新手,能搭建出这套户外灯光系统已经超棒啦!咱们一步步来搞定RFID失效的问题,顺便把代码优化得更清爽~
先搞懂你疑惑的两个RFID函数
你提到的rfid.PICC_HaltA()和rfid.PCD_StopCrypto1()其实是RFID通信里至关重要的收尾操作:
rfid.PICC_HaltA():让当前被读取的RFID标签进入休眠模式,这样读卡器就不会一直和这个标签保持连接,能及时响应新的标签。rfid.PCD_StopCrypto1():终止读卡器和标签之间的加密会话,重置加密状态,确保下一次读卡时是全新的通信环境,避免残留的加密状态导致后续读卡失败。
分析RFID失效的核心原因
看你的代码,最大的问题是使用了阻塞式的delay():
- 当识别到合法标签后,你用
delay(15000)让灯亮15秒,这15秒内Arduino完全卡住,没法执行任何其他操作——包括RFID模块的状态维护、甚至没法响应新的读卡请求。长时间阻塞会让RC522模块进入异常状态,最终导致读卡功能失效,必须重启才能恢复。 - 另外,当前的UID匹配逻辑写得太繁琐,虽然功能没问题,但维护起来很麻烦,也容易出错。
解决方案:用非阻塞延时重构代码
我们把delay()换成millis()来实现非阻塞延时,这样程序在等待灯熄灭的过程中,依然能正常处理RFID读卡和门状态检测。同时优化UID匹配的逻辑:
完整修改后的代码
#include <SPI.h> #include <MFRC522.h> // 把所有合法UID放进二维数组,方便循环匹配 const byte validUIDs[6][4] = { {0xA7, 0x8C, 0x24, 0xD9}, // 黑色标签1 {0x10, 0x84, 0xD2, 0x2A}, // 黑色标签2 {0xDC, 0x46, 0xB6, 0x91}, // 黑色标签3 {0xB0, 0xE8, 0xC4, 0x2A}, // 黑色标签4 {0x9E, 0xC8, 0xEA, 0xB3}, // 红色标签1 {0xFE, 0xA5, 0xF7, 0xB3} // 红色标签2 }; const int validUIDCount = sizeof(validUIDs) / sizeof(validUIDs[0]); MFRC522 rfid(10, 9); int in1 = 7; // 灯光控制引脚 int dooropen = 8; // 霍尔传感器引脚 int doorState = 0; // 当前门状态 int tester = 0; // 门打开标记 unsigned long lastLightOnTime = 0; // 记录灯光点亮的时间 const long doorOffDelay = 6000; // 关门后灯光保持时间 const long rfidLightDelay = 15000; // RFID触发后灯光保持时间 int lightMode = 0; // 灯光模式:0=正常门控,1=RFID触发 void setup() { Serial.begin(9600); SPI.begin(); rfid.PCD_Init(); pinMode(in1, OUTPUT); pinMode(dooropen, INPUT); digitalWrite(in1, LOW); } void loop() { doorState = digitalRead(dooropen); unsigned long currentMillis = millis(); // 处理门控逻辑 if (doorState == HIGH) { // 门打开:点亮灯光,重置所有延时标记 digitalWrite(in1, HIGH); tester = 1; lightMode = 0; lastLightOnTime = currentMillis; } else { if (tester == 1) { // 门刚关上,进入关门延时模式 lightMode = 0; if (currentMillis - lastLightOnTime >= doorOffDelay) { digitalWrite(in1, LOW); tester = 0; } } else { // 门保持关闭状态,处理RFID逻辑 if (lightMode == 0) { // 只有在正常门控模式下,才检测RFID if (rfid.PICC_IsNewCardPresent() && rfid.PICC_ReadCardSerial()) { // 检查当前UID是否在合法列表中 bool isUIDValid = false; for (int i = 0; i < validUIDCount; i++) { if (memcmp(rfid.uid.uidByte, validUIDs[i], 4) == 0) { isUIDValid = true; break; } } if (isUIDValid) { // 合法标签:点亮灯光,进入RFID延时模式 digitalWrite(in1, HIGH); lightMode = 1; lastLightOnTime = currentMillis; } // 必须执行的收尾操作,确保读卡器状态正常 rfid.PICC_HaltA(); rfid.PCD_StopCrypto1(); } } else { // RFID触发后的延时逻辑 if (currentMillis - lastLightOnTime >= rfidLightDelay) { digitalWrite(in1, LOW); lightMode = 0; } } } } // 可选:定期检查读卡器状态,异常时重新初始化 if (!rfid.PCD_IsAlive()) { Serial.println("RFID模块异常,重新初始化..."); rfid.PCD_Init(); } }
代码关键改进点
- 非阻塞延时:用
millis()替代delay(),程序全程不会卡住,RFID模块能持续正常工作。 - 优化UID匹配:把所有合法UID放进二维数组,用
memcmp()循环比较,代码更简洁,后续添加新标签只需在数组里加一行即可。 - 状态管理:新增
lightMode变量区分不同的灯光触发模式,逻辑更清晰。 - 读卡器健康检查:添加
rfid.PCD_IsAlive()定期检查模块状态,异常时自动重新初始化,提升稳定性。
额外硬件建议
因为是户外使用,这些细节也能提升系统稳定性:
- 给RC522模块加防水外壳,避免雨水、湿气损坏电路。
- 检查供电:Arduino Nano如果用USB供电,户外可能电压不稳,建议用5V/1A的稳压电源供电,确保模块有足够的电力。
- 接线加固:所有接线用热缩管或者接线端子固定,避免风吹日晒导致松动接触不良。
内容的提问来源于stack exchange,提问作者user14972314




