如何通过ESP32准确测量NFC标签在RC522阅读器上的停留时长
问题:ESP32 + RC522 无法正确测量NFC标签停留时长
我用ESP32搭配RC522阅读器,想测量NFC标签的停留时长,使用MFRC522库操作模块。接线无误,能正常读取标签信息,但时长测量始终不符合预期。
原代码:
#include <SPI.h> #include <MFRC522.h> #define SS_PIN 5 // ESP32 pin GPIO5 #define RST_PIN 27 // ESP32 pin GPIO27 MFRC522 rfid(SS_PIN, RST_PIN); unsigned long timeStart = 0; unsigned long timeEnd = 0; bool tagPresent = false; void setup() { Serial.begin(9600); SPI.begin(); // init SPI bus rfid.PCD_Init(); // init MFRC522 Serial.println("Use an RFID tag"); } void loop() { if (rfid.PICC_IsNewCardPresent() && rfid.PICC_ReadCardSerial()) { if (!tagPresent) { // if tagPresent = false, then the tag has just "arrived" tagPresent = true; timeStart = millis(); } // Removing the next 2 function calls doesn't solve the problem but // it seems to halve the time read in the duration variable rfid.PICC_HaltA(); rfid.PCD_StopCrypto1(); } else { if (tagPresent) { //at some point there was a tag, but it's gone now Serial.print("\n"); timeEnd = millis(); unsigned long duration = timeEnd - timeStart; Serial.print("Tag NFC stayed for "); Serial.print(duration); Serial.println(" ms"); // noted the last tag's time, reset tagPresent = false; } } }
原输出:
Tag NFC stayed for 51 ms Tag NFC stayed for 51 ms Tag NFC stayed for 51 ms Tag NFC stayed for 51 ms ...
当前问题:标签刚放上阅读器就立刻输出时长,即使一直停留也不再输出;拿起再放下会重复输出短时长。期望标签停留10秒后移除时,能输出Tag NFC stayed for 10000 ms这样的正确结果。
解决方案
问题出在两个关键点:
PICC_IsNewCardPresent()仅检测首次出现的新卡片,后续循环不会再识别到同一卡片;PICC_HaltA()会强制卡片进入休眠状态,导致阅读器下一次循环就检测不到卡片,直接触发时长计算。
修改后的代码:
#include <SPI.h> #include <MFRC522.h> #define SS_PIN 5 // ESP32 pin GPIO5 #define RST_PIN 27 // ESP32 pin GPIO27 MFRC522 rfid(SS_PIN, RST_PIN); MFRC522::Uid currentUid; // 可选:用于识别特定标签 unsigned long timeStart = 0; bool tagPresent = false; void setup() { Serial.begin(9600); SPI.begin(); rfid.PCD_Init(); Serial.println("Place RFID tag on reader..."); } void loop() { // 持续检测是否有卡片在场 bool cardDetected = rfid.PICC_IsCardPresent(); if (cardDetected) { if (!tagPresent) { // 卡片刚放置,记录开始时间 tagPresent = true; timeStart = millis(); // 可选:读取当前卡片UID,用于限定特定标签 if (rfid.PICC_ReadCardSerial()) { currentUid = rfid.uid; rfid.PCD_StopCrypto1(); // 结束加密会话,不要让卡片休眠 } Serial.println("Tag detected"); } } else { if (tagPresent) { // 卡片被移除,计算并输出停留时长 unsigned long duration = millis() - timeStart; Serial.print("Tag stayed for "); Serial.print(duration); Serial.println(" ms"); tagPresent = false; } } // 延迟降低循环频率,提升稳定性 delay(50); }
关键修改说明:
- 替换检测函数:用
PICC_IsCardPresent()替代原检测逻辑,该函数会持续判断当前是否有卡片在阅读器感应范围内,而非仅检测新卡片; - 移除
PICC_HaltA():这个函数会让卡片进入休眠,导致阅读器立刻"丢失"卡片,直接触发错误的时长计算; - 添加循环延迟:
delay(50)减少SPI通信频率,避免资源过度占用,同时让检测状态更稳定; - 可选特定标签支持:如果需要只统计某张标签的停留时长,可以在卡片放置时读取UID,后续对比UID再执行计时逻辑。
修改后,卡片放置时启动计时,移除时输出准确的总停留时长,完全符合预期需求。
内容的提问来源于stack exchange,提问作者Arzo
相关产品推荐
相关产品推荐

