如何使用Arduino向RFID标签跨块写入长字符串
Arduino + MFRC522 向MIFARE标签写入长字符串实现
前置注意事项
操作MIFARE系列RFID标签必须避开两类特殊块,否则会直接导致标签永久锁死报废:
- 块0:厂商固化只读块,存储标签UID等出厂信息,不可写入
- 扇区尾块:每个扇区共4个块,索引为3、7、11、15…(块号对4取余等于3)的块为扇区控制块,存储读写密钥和权限配置,不可写入用户数据
实现思路
受标签硬件限制,单个数据块最多写入16字节,长字符串写入逻辑如下:
- 从指定的安全起始块(推荐从块1开始)写入
- 把长字符串按每16字节拆分一组,不足16字节的末尾用0填充补满
- 逐块写入时自动跳过扇区尾块,直到所有字符串内容写完
- 读取时按写入的块顺序逐块读取,拼接后去掉末尾填充的0即可得到原始字符串
完整可运行代码
#include <SPI.h> #include <MFRC522.h> // 硬件引脚定义 #define SS_PIN 10 #define RST_PIN 7 MFRC522 mfrc522(SS_PIN, RST_PIN); MFRC522::MIFARE_Key key; const byte START_BLOCK = 1; // 写入起始块,避开块0厂商块 const char* writeStr = "Hello my name is james and i live in NewYork"; // 待写入长字符串 byte bufferLen = 18; // 单块读取缓冲长度固定为18字节(16字节数据+2字节校验) MFRC522::StatusCode status; void setup() { Serial.begin(9600); SPI.begin(); mfrc522.PCD_Init(); Serial.println("请放置MIFARE标签到读卡区..."); // 初始化默认密钥,出厂标签密钥A默认全FF for (byte i = 0; i < 6; i++) { key.keyByte[i] = 0xFF; } } void loop() { // 检测新卡 if (!mfrc522.PICC_IsNewCardPresent()) return; if (!mfrc522.PICC_ReadCardSerial()) return; Serial.println(F("检测到标签,开始写入长字符串...")); // 写入长字符串 writeLongString(START_BLOCK, writeStr); // 读取长字符串 String readStr = readLongString(START_BLOCK, strlen(writeStr)); Serial.print("读取到的完整字符串:"); Serial.println(readStr); mfrc522.PICC_HaltA(); mfrc522.PCD_StopCrypto1(); Serial.println("操作完成,可以移走标签"); } // 单块写入函数 bool writeSingleBlock(byte blockNum, byte* data) { status = mfrc522.PCD_Authenticate(MFRC522::PICC_CMD_MF_AUTH_KEY_A, blockNum, &key, &(mfrc522.uid)); if (status != MFRC522::STATUS_OK) { Serial.print("块");Serial.print(blockNum);Serial.print("认证失败:"); Serial.println(mfrc522.GetStatusCodeName(status)); return false; } status = mfrc522.MIFARE_Write(blockNum, data, 16); if (status != MFRC522::STATUS_OK) { Serial.print("块");Serial.print(blockNum);Serial.print("写入失败:"); Serial.println(mfrc522.GetStatusCodeName(status)); return false; } Serial.print("块");Serial.print(blockNum);Serial.println("写入成功"); return true; } // 长字符串写入函数 void writeLongString(byte startBlock, const char* str) { byte currentBlock = startBlock; int strLen = strlen(str); int offset = 0; byte blockBuf[16]; while (offset < strLen) { // 跳过扇区尾块 if (currentBlock %4 ==3) { currentBlock++; continue; } // 清空块缓冲 memset(blockBuf, 0, 16); // 拷贝最多16字节数据到缓冲 int copyLen = min(16, strLen - offset); memcpy(blockBuf, str+offset, copyLen); // 写入块 writeSingleBlock(currentBlock, blockBuf); offset += copyLen; currentBlock++; } } // 单块读取函数 bool readSingleBlock(byte blockNum, byte* outBuf) { status = mfrc522.PCD_Authenticate(MFRC522::PICC_CMD_MF_AUTH_KEY_A, blockNum, &key, &(mfrc522.uid)); if (status != MFRC522::STATUS_OK) { Serial.print("块");Serial.print(blockNum);Serial.print("认证失败:"); Serial.println(mfrc522.GetStatusCodeName(status)); return false; } byte readBuf[18]; byte bufSize = 18; status = mfrc522.MIFARE_Read(blockNum, readBuf, &bufSize); if (status != MFRC522::STATUS_OK) { Serial.print("块");Serial.print(blockNum);Serial.print("读取失败:"); Serial.println(mfrc522.GetStatusCodeName(status)); return false; } // 拷贝16字节有效数据 memcpy(outBuf, readBuf, 16); return true; } // 长字符串读取函数 String readLongString(byte startBlock, int totalLen) { String result = ""; byte currentBlock = startBlock; int readOffset =0; byte blockBuf[16]; while (readOffset < totalLen) { // 跳过扇区尾块 if (currentBlock%4 ==3) { currentBlock++; continue; } if (readSingleBlock(currentBlock, blockBuf)) { int copyLen = min(16, totalLen - readOffset); for (int i=0; i<copyLen; i++) { result += (char)blockBuf[i]; } readOffset += copyLen; } else { break; } currentBlock++; } return result; }
代码说明
- 写入前自动初始化标签默认出厂密钥
FFFFFFFFFFFF,如果你的标签修改过密钥,需要替换key.keyByte数组里的值 - 单块写入、读取的核心逻辑和原有单块操作代码一致,新增了长字符串拆分、块地址校验、自动跳过特殊块的逻辑
- MIFARE 1K标签最多可存储768字节用户文本,足够存储短个人信息、网址类内容
- 如果需要写入更长内容,可以更换MIFARE 4K标签,逻辑无需修改,只要保持扇区尾块跳过规则一致即可
内容的提问来源于stack exchange,提问作者koko
相关产品推荐
相关产品推荐

