如何在RFID 522卡上永久存储余额?ESP32复位后余额保留方案
解决方案:将余额永久存储在RFID卡的扇区中
核心逻辑
MIFARE Classic系列卡(如1K/4K)包含可自定义读写的用户扇区,我们需要把余额数据写入卡的指定扇区块中,而非仅存在ESP32的RAM里。每次刷卡时先读取卡上存储的余额,累加后再写回卡内,这样ESP32复位后,再次刷卡仍能读取到之前的累计余额。
具体实现步骤
1. 选定存储区域
以MIFARE Classic 1K卡为例,选择**扇区1的块1(地址0x05)**存储余额(扇区0的块0是厂商信息块,不可写入)。默认情况下,多数卡的扇区密钥为FFFFFFFFFFFF,可直接用此密钥验证读写权限。
2. 编写余额读写函数
读取余额函数
// 从指定块读取余额,返回余额数值(单位:美元),读取失败返回-1 int readBalance(byte blockAddr, byte* authKey) { int balance = 0; byte dataBuffer[18]; byte dataSize = sizeof(dataBuffer); // 验证扇区密钥(扇区1的密钥块地址是0x07) if (!mfrc522.PCD_Authenticate(PICC_CMD_MF_AUTH_KEY_A, 0x07, authKey, &mfrc522.uid)) { Serial.println("密钥验证失败"); mfrc522.PCD_StopCrypto1(); return -1; } // 读取目标块数据 if (mfrc522.MIFARE_Read(blockAddr, dataBuffer, &dataSize)) { // 将4字节数据拼接为整数(大端模式) balance = (dataBuffer[0] << 24) | (dataBuffer[1] << 16) | (dataBuffer[2] << 8) | dataBuffer[3]; } else { Serial.println("余额读取失败"); balance = -1; } mfrc522.PCD_StopCrypto1(); return balance; }
写入余额函数
// 将余额写入指定块,写入成功返回true,失败返回false bool writeBalance(byte blockAddr, byte* authKey, int balance) { byte dataBuffer[16]; // MIFARE单块固定为16字节 memset(dataBuffer, 0, 16); // 初始化缓冲区 // 将整数余额拆分为4字节(大端模式) dataBuffer[0] = (balance >> 24) & 0xFF; dataBuffer[1] = (balance >> 16) & 0xFF; dataBuffer[2] = (balance >> 8) & 0xFF; dataBuffer[3] = balance & 0xFF; // 验证扇区密钥 if (!mfrc522.PCD_Authenticate(PICC_CMD_MF_AUTH_KEY_A, 0x07, authKey, &mfrc522.uid)) { Serial.println("密钥验证失败"); mfrc522.PCD_StopCrypto1(); return false; } // 写入数据到目标块 bool writeSuccess = mfrc522.MIFARE_Write(blockAddr, dataBuffer, 16); if (!writeSuccess) { Serial.println("余额写入失败"); } mfrc522.PCD_StopCrypto1(); return writeSuccess; }
3. 修改主刷卡逻辑
替换原有仅在RAM中累加余额的代码,改为读写卡内数据:
byte defaultAuthKey[] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}; // 默认卡密钥 int currentBalance; void loop() { if (mfrc522.PICC_IsNewCardPresent() && mfrc522.PICC_ReadCardSerial()) { // 读取卡内存储的余额 currentBalance = readBalance(0x05, defaultAuthKey); // 若为新卡或读取失败,初始化余额为100美元 if (currentBalance == -1) { currentBalance = 100; writeBalance(0x05, defaultAuthKey, currentBalance); Serial.print("新卡初始化余额:"); Serial.println(currentBalance); } else { // 累加100美元后写回卡内 currentBalance += 100; if (writeBalance(0x05, defaultAuthKey, currentBalance)) { Serial.print("余额更新为:"); Serial.println(currentBalance); } } mfrc522.PICC_HaltA(); mfrc522.PCD_StopCrypto1(); } }
4. 关键注意事项
- 密钥匹配:如果卡的扇区密钥不是默认值,需先用RFID工具读取或修改对应扇区的密钥,确保验证时使用正确密钥。
- 数据稳定性:示例用整数存储余额,若需精确到分,可将单位改为分(如100美元存为10000),避免浮点运算误差。
- 扇区权限:确保所选扇区的访问控制位允许读写,部分卡的扇区默认是只读,需用工具调整访问控制配置。
内容的提问来源于stack exchange,提问作者Benjamin Veras
相关产品推荐
相关产品推荐

