Arduino新手求助:PN532无法验证NFC卡块,未知验证块
嘿,我刚入门Arduino玩NFC的时候也踩过一模一样的坑!让我来帮你一步步解决~
解决PN532库authenticateBlock()卡壳及块验证信息缺失问题
一、先明确你的两个核心痛点
- authenticateBlock()卡壳:MIFARE卡的验证依赖密钥和块权限,新手容易在密钥匹配、块选择上出错
- 看不到验证的块号:默认示例代码没加调试日志,咱们自己补就行
二、一步步排查解决
1. 先补上块验证的日志,明确卡在哪一步
你现在的输出看不到具体验证哪个块,咱们给代码加个打印,把要验证的块号明确输出。找到调用authenticateBlock()的地方,改成这样:
// 你示例里要写的是块0x08,先定义块号变量 uint8_t targetBlock = 0x08; // 打印当前要验证的块号 Serial.print("正在尝试验证块: 0x"); Serial.println(targetBlock, HEX); // 调用验证函数,同时保存结果 bool authResult = nfc.authenticateBlock( nfc.uid, nfc.uidLength, targetBlock, 0, // 0代表用A密钥,1代表用B密钥 (uint8_t[]) {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF} // 通用默认密钥 ); // 打印验证结果 if (!authResult) { Serial.print("块0x"); Serial.print(targetBlock, HEX); Serial.println(" 验证失败!"); return; }
这样你就能在串口输出里直接看到是哪个块验证失败,不用再瞎猜了。
2. 解决authenticateBlock()失败的核心原因
MIFARE 1K卡的验证逻辑有几个新手容易踩的坑,逐个排查:
- 默认密钥不一定通用:虽然大部分新卡用
0xFF 0xFF 0xFF 0xFF 0xFF 0xFF,但有些厂商的卡会用0xA0 0xA1 0xA2 0xA3 0xA4 0xA5,两种都试试 - 别碰只读/控制块:你代码注释里提到块0是只读的,绝对不能写!另外每个扇区的最后一个块(比如0x03、0x07、0x0B)是扇区控制块,存密钥和权限,写错了卡直接报废,新手就老老实实写0x08、0x09这类普通数据块
- 密钥类型搞反了:authenticateBlock的第4个参数是密钥类型,0是A密钥,1是B密钥,两种都尝试一遍
- UID读取是否正确:从你的输出看
Read card #3122678656是UID的十进制,你可以转成十六进制和卡的物理UID对比,避免UID传递错误
3. 调试版完整代码参考
把上面的修改整合到代码里,你可以直接用这个版本调试:
#include <PN532.h> #include <PN532_SPI.h> // 根据你的接线选择通信方式,这里用SPI示例 PN532_SPI pn532spi(SPI, 10); PN532 nfc(pn532spi); void setup(void) { Serial.begin(115200); while (!Serial) {} // 等待串口连接 nfc.begin(); uint32_t version = nfc.getFirmwareVersion(); if (!version) { Serial.println("找不到PN532模块!检查接线"); while (1); } Serial.print("PN532固件版本: "); Serial.print((version >> 24) & 0xFF, HEX); Serial.print('.'); Serial.println((version >> 16) & 0xFF, HEX); nfc.setPassiveActivationRetries(0xFF); nfc.SAMConfig(); } void loop(void) { uint8_t success; uint8_t uid[7] = {0}; uint8_t uidLen; Serial.println("\n等待NFC卡靠近..."); success = nfc.readPassiveTargetID(PN532_MIFARE_ISO14443A, uid, &uidLen, 2000); if (success) { Serial.println("找到1张卡"); Serial.print("Sens Response: 0x"); Serial.println(nfc.getSensResp(), HEX); Serial.print("Sel Response: "); for (uint8_t i=0; i<uidLen; i++) { Serial.print("0x"); Serial.print(uid[i], HEX); Serial.print(" "); } Serial.println(); uint32_t cardId = ((uint32_t)uid[0]<<24)|((uint32_t)uid[1]<<16)|((uint32_t)uid[2]<<8)|uid[3]; Serial.print("读取卡ID: #"); Serial.println(cardId); // 要写入的目标块(选普通数据块0x08) uint8_t targetBlock = 0x08; // 准备16字节的写入数据(MIFARE块固定大小) uint8_t writeData[] = {0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08, 0x09,0x0A,0x0B,0x0C,0x0D,0x0E,0x0F,0x10}; // 第一步:验证块 Serial.print("正在尝试验证块: 0x"); Serial.println(targetBlock, HEX); bool authOk = nfc.authenticateBlock(uid, uidLen, targetBlock, 0, (uint8_t[]) {0xFF,0xFF,0xFF,0xFF,0xFF,0xFF}); if (!authOk) { Serial.println("A密钥验证失败,尝试B密钥..."); authOk = nfc.authenticateBlock(uid, uidLen, targetBlock, 1, (uint8_t[]) {0xFF,0xFF,0xFF,0xFF,0xFF,0xFF}); if (!authOk) { Serial.println("B密钥也失败!试试默认密钥0xA0A1A2A3A4A5"); return; } } // 第二步:写入数据 Serial.println("验证成功,开始写入..."); success = nfc.writeMemoryBlock(targetBlock, writeData); if (success) { Serial.print("块0x"); Serial.print(targetBlock, HEX); Serial.println(" 写入成功!"); // 读取回来验证 uint8_t readBack[16]; success = nfc.readMemoryBlock(targetBlock, readBack); if (success) { Serial.print("读取写入的数据: "); for (uint8_t i=0; i<16; i++) { Serial.print("0x"); Serial.print(readBack[i], HEX); Serial.print(" "); } Serial.println(); } } else { Serial.println("写入失败!检查块是否为只读或权限设置"); } nfc.stopCrypto(); // 停止加密 } delay(1000); }
三、新手额外注意事项
- 串口波特率要匹配:确保串口监视器的波特率和代码里的
Serial.begin(115200)一致 - 接线要牢固:PN532模块的通信引脚(SPI/I2C)接触不良会导致各种奇怪问题
- 别乱改控制块:每个扇区的最后一个块是控制块,用来存密钥和权限,新手绝对别碰,写错直接锁卡
内容的提问来源于stack exchange,提问作者user8468734
相关产品推荐
相关产品推荐

