ARTICLE DETAIL

资讯详情

深耕网站建设、视觉设计与SEO优化的一线实战洞察。

PN532 NFC模块实战:从硬件连接到读写卡片的完整指南

PN532 NFC模块实战:从硬件连接到读写卡片的完整指南 1. 从拆快递到点亮模块PN532 上手前必须想清楚的几件事PN532 这块板子在 NFC 和 RFID 圈子里算是“老熟人”了。无论是做门禁卡读写、公交卡数据解析、还是给树莓派加一个刷卡登录的功能很多人第一个想到的就是它。原因很直接它同时支持 13.56MHz 下的 ISO14443A/B、Felica、ISO15693 等多种协议既能读卡也能写卡还能模拟成卡被别的读卡器识别价格又足够便宜。但真正拿到手之后你会发现事情没那么简单——光是“怎么连”这一步就能卡住不少人。我见过太多人模块买回来杜邦线一插代码一跑串口打印全是乱码或者干脆没反应。然后就开始怀疑模块坏了、怀疑代码有问题、怀疑自己买到了假货。实际上PN532 的硬件连接有几个非常具体的“坑点”比如拨码开关的位置、接口模式的选择、电平匹配的问题任何一个没处理好都会导致通信失败。这篇内容就是把这些东西一次性讲透从硬件连接到数据读写再到实际调试中会遇到的各种意外情况全部按实战顺序展开。适合谁来读如果你手里正好有一块 PN532不管是红板、蓝板还是那种带亚克力外壳的版本只要你想把它跑起来、读出数据、写出数据这篇内容都能直接用。如果你还没买看完之后你也会清楚该选哪个版本、该配什么配件。我会尽量用“说人话”的方式把原理讲清楚同时给出可以直接抄的接线表和代码片段。2. 接口模式与拨码开关PN532 通信失败的头号原因2.1 三种接口模式到底怎么选PN532 模块通常支持三种通信接口UART串口、I2C、SPI。这三种接口不是随便选的而是由模块上的拨码开关或者跳线帽决定的。很多模块出厂默认是 UART 模式但有些卖家发出来的板子可能被设置成了 I2C 或 SPI你如果不检查就直接按 UART 接线那肯定通不了。先说一下这三种接口各自的特点方便你根据自己的主控板来选接口模式占用引脚数通信速度适用场景注意事项UART2TX/RX中等Arduino、ESP32、树莓派最简单推荐新手首选I2C2SDA/SCL较慢引脚紧张的项目需要上拉电阻地址固定为0x24SPI4SCK/MISO/MOSI/SS最快高速读写场景接线最多但时序最稳定我个人的建议是如果你用的是 Arduino 或者 ESP32优先选 UART 模式。原因很简单UART 的接线最少调试最直观出问题了也最容易排查。I2C 虽然引脚少但 PN532 的 I2C 实现有时候会有时序问题尤其是在长导线或者没有上拉电阻的情况下很容易出现通信不稳定。SPI 速度最快但接线复杂适合对读写速度有要求的场景比如批量读取大量卡片。2.2 拨码开关的“隐藏逻辑”这是最容易踩坑的地方。PN532 模块上通常有一个两位的拨码开关或者是一组跳线焊盘。不同的模块厂商拨码开关的定义可能不一样但大多数遵循这样的规律UART 模式拨码开关通常设置为0 0或者1 0具体看模块丝印I2C 模式拨码开关通常设置为1 0或者0 1SPI 模式拨码开关通常设置为0 1或者1 1问题在于很多模块的丝印标注非常模糊甚至有的模块根本没有丝印。我遇到过一块红板拨码开关旁边只写了“1”和“2”没有任何模式说明。这种情况下你只能靠试。但试也是有方法的先查模块型号找到对应的原理图或者数据手册确认拨码开关和接口模式的对应关系。如果实在找不到就按最常见的定义来试试的时候注意观察模块上的 LED 指示灯——UART 模式下如果接线正确模块上的 LED 会有规律地闪烁如果没反应大概率是模式不对。还有一个细节有些模块的拨码开关是“拨上去”和“拨下去”两种状态但丝印上的“ON”和“OFF”可能和你想的相反。我建议你用万用表测一下拨码开关的通断状态确认它到底是在哪个位置。这个步骤花不了两分钟但能省掉你后面几个小时的折腾。2.3 电平匹配3.3V 和 5V 的“生死线”PN532 芯片本身是3.3V 供电的这一点非常重要。虽然很多模块板上带了电平转换芯片支持 5V 的 logic level但并不是所有模块都有这个设计。如果你直接把 5V 的 TX 接到 PN532 的 RX 上而模块又没有电平转换那芯片很可能直接烧掉。怎么判断你的模块有没有电平转换看模块上有没有一个AMS1117或者类似的稳压芯片以及有没有TXS0108E之类的电平转换芯片。如果有那你可以放心用 5V 的逻辑电平如果没有那就必须用 3.3V 的逻辑电平或者自己加一个电平转换模块。我自己的做法是不管模块有没有电平转换我都用 3.3V 的逻辑电平。因为 3.3V 对 PN532 来说是安全的而且大多数现代主控板ESP32、树莓派、STM32都是 3.3V 逻辑直接连就行。只有用 Arduino Uno 这种 5V 逻辑板的时候才需要特别注意。如果你用的是 Uno我建议你在 TX 和 RX 之间各串一个 1kΩ 的电阻做一个简单的分压虽然不太规范但应急够用了。3. 接线实战UART、I2C、SPI 三种模式的完整接线表3.1 UART 模式接线最简单也最容易出错UART 模式是新手最常用的但“最简单”往往意味着“最容易忽略细节”。先看接线表PN532 引脚主控板引脚说明VCC3.3V供电不要接 5V除非确认有电平转换GNDGND共地必须接TXDRX模块发送主控接收RXDTX模块接收主控发送这里有一个非常经典的错误TX 和 RX 接反了。很多人会下意识地把 TX 接 TXRX 接 RX结果就是完全没反应。记住一个原则模块的 TX 要接到主控的 RX模块的 RX 要接到主控的 TX。如果你用的是软串口比如 Arduino 上的SoftwareSerial那就要在代码里指定哪个引脚是 RX哪个是 TX然后按上面的规则接线。还有一个细节PN532 的 UART 波特率通常是 115200但有些模块出厂设置可能是 9600。如果你用 115200 通不了试试 9600。我遇到过一块模块卖家发出来的时候波特率被改成了 9600我按 115200 调了半天没反应后来改成 9600 就通了。这个坑不常见但遇到了就很浪费时间。3.2 I2C 模式接线上拉电阻不能省I2C 模式的接线也不复杂PN532 引脚主控板引脚说明VCC3.3V供电GNDGND共地SDASDA数据线SCLSCL时钟线但 I2C 有一个硬性要求SDA 和 SCL 必须接上拉电阻通常是 4.7kΩ 到 10kΩ。有些模块板上已经自带了上拉电阻你直接连就行但有些模块没有这时候你就必须自己加。怎么判断看模块上 SDA 和 SCL 附近有没有贴片电阻如果有通常就是上拉电阻。如果没有那就自己加两个 4.7kΩ 的电阻一端接 SDA/SCL另一端接 3.3V。I2C 模式下PN532 的默认地址是0x24。如果你用 I2C 扫描工具扫不到这个地址先检查上拉电阻再检查拨码开关最后检查供电。我遇到过一种情况模块供电正常拨码开关也对但就是扫不到地址后来发现是 SDA 和 SCL 接反了。I2C 的 SDA 和 SCL 接反了不会烧芯片但通信肯定失败而且这种错误很隐蔽因为线序看起来“差不多”。3.3 SPI 模式接线引脚最多但最稳定SPI 模式的接线最复杂但如果你需要高速读写这是最好的选择PN532 引脚主控板引脚说明VCC3.3V供电GNDGND共地SCKSCK时钟MISOMISO主入从出MOSIMOSI主出从入SS任意 GPIO片选低电平有效SPI 模式的好处是时序稳定不容易受干扰。但缺点是占用引脚多而且不同的主控板 SPI 引脚定义不一样接线的时候要查清楚。比如 ESP32 的默认 SPI 引脚是 GPIO18SCK、GPIO19MISO、GPIO23MOSI、GPIO5SS但你可以重映射到其他引脚。树莓派的 SPI 引脚是固定的GPIO11SCK、GPIO9MISO、GPIO10MOSI、GPIO8CE0。SPI 模式下还有一个容易忽略的点SS 片选引脚必须接而且要在代码里正确配置。有些人只接了 SCK、MISO、MOSI没接 SS结果就是通信完全没反应。SS 引脚的作用是告诉 PN532“现在轮到你了”不接的话PN532 根本不知道什么时候该响应。4. 驱动库选择与代码实战从读取 UID 到写入数据块4.1 驱动库的选择Adafruit 还是 SeeedPN532 的驱动库主要有两个流派Adafruit PN532 库和Seeed Studio PN532 库。两个库都能用但各有特点。Adafruit 的库优点是文档全、示例多、社区活跃遇到问题容易找到答案。缺点是代码结构稍微复杂一点而且默认只支持 I2C 和 SPIUART 模式需要额外配置。Seeed 的库优点是 UART 支持好代码简洁适合快速上手。缺点是文档相对少一些遇到冷门问题可能找不到参考。我个人的建议是如果你用 UART 模式优先用 Seeed 的库如果你用 I2C 或 SPI优先用 Adafruit 的库。当然这不是绝对的你也可以两个都试试看哪个更顺手。安装库的方式很简单Arduino IDE 里通过库管理器搜索“PN532”就能找到。如果你用 PlatformIO直接在platformio.ini里加依赖就行lib_deps adafruit/Adafruit PN532^1.3.0 ; 或者 seeed-studio/PN532^1.0.04.2 UART 模式读取卡片 UID 的完整代码下面是一段基于 Seeed 库的 UART 模式读卡代码我实测过可以直接用#include Wire.h #include PN532_HSU.h #include PN532.h // 软串口RX2, TX3 PN532_HSU pn532hsu(Serial1); PN532 nfc(pn532hsu); void setup() { Serial.begin(115200); Serial1.begin(115200); // PN532 的波特率 nfc.begin(); uint32_t versiondata nfc.getFirmwareVersion(); if (!versiondata) { Serial.println(未找到 PN532 模块检查接线和拨码开关); while (1); } Serial.print(找到 PN532固件版本); Serial.println(versiondata, HEX); nfc.SAMConfig(); // 配置为读卡模式 Serial.println(等待卡片靠近...); } void loop() { uint8_t uid[7]; uint8_t uidLength; bool success nfc.readPassiveTargetID( PN532_MIFARE_ISO14443A, uid, uidLength, 100 ); if (success) { Serial.print(读到卡片UID 长度); Serial.println(uidLength); Serial.print(UID); for (uint8_t i 0; i uidLength; i) { if (uid[i] 0x10) Serial.print(0); Serial.print(uid[i], HEX); } Serial.println(); delay(1000); } }这段代码的关键点有几个第一Serial1是硬件串口如果你用的是 Arduino Uno没有Serial1那就得用SoftwareSerial模拟一个。第二nfc.SAMConfig()是必须调用的它的作用是把 PN532 配置成读卡模式不调用的话读不到卡。第三readPassiveTargetID的最后一个参数是超时时间单位是毫秒设成 100 就行设太长会拖慢循环速度。4.3 读取 Mifare Classic 数据块密钥验证是第一步读到了 UID 只是第一步真正有用的是卡片里的数据块。Mifare Classic 卡片比如常见的 M1 卡有 16 个扇区每个扇区 4 个块每个块 16 字节。但你不能直接读必须先通过密钥验证。Mifare Classic 的密钥分 A 密钥和 B 密钥每个扇区都有独立的密钥。出厂默认密钥通常是FFFFFFFFFFFF但很多门禁卡会改掉这个密钥。如果你不知道密钥就读不了数据。下面是一段读取数据块的代码示例#include Wire.h #include PN532_HSU.h #include PN532.h PN532_HSU pn532hsu(Serial1); PN532 nfc(pn532hsu); // 默认密钥 uint8_t keyA[6] {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}; void setup() { Serial.begin(115200); Serial1.begin(115200); nfc.begin(); uint32_t versiondata nfc.getFirmwareVersion(); if (!versiondata) { Serial.println(未找到 PN532); while (1); } nfc.SAMConfig(); } void loop() { uint8_t uid[7]; uint8_t uidLength; if (nfc.readPassiveTargetID(PN532_MIFARE_ISO14443A, uid, uidLength, 100)) { Serial.println(卡片已检测到); // 验证第 1 扇区的 A 密钥 if (nfc.mifareclassic_AuthenticateBlock(uid, uidLength, 4, 0, keyA)) { Serial.println(密钥验证成功); uint8_t data[16]; if (nfc.mifareclassic_ReadDataBlock(4, data)) { Serial.print(块 4 数据); for (int i 0; i 16; i) { if (data[i] 0x10) Serial.print(0); Serial.print(data[i], HEX); Serial.print( ); } Serial.println(); } else { Serial.println(读取数据块失败); } } else { Serial.println(密钥验证失败); } delay(2000); } }这里有几个关键点mifareclassic_AuthenticateBlock的第三个参数是块号第 1 扇区的第一个块是块 4块 0-3 是第 0 扇区。第四个参数是密钥类型0 表示 A 密钥1 表示 B 密钥。验证通过之后才能调用mifareclassic_ReadDataBlock读取数据。4.4 写入数据块不是所有块都能写写入数据块和读取类似也需要先验证密钥然后调用mifareclassic_WriteDataBlock。但要注意不是所有块都能写。每个扇区的最后一个块块 3、7、11、15是“尾块”里面存放的是密钥和访问控制位写这个块需要非常小心写错了卡片就可能被锁死。我建议你在写数据之前先用读取代码把整个卡片的数据读出来确认哪些块是可写的、哪些块是只读的。一般来说块 0 是厂商块只读尾块是控制块谨慎写中间的块通常可读写。写入代码示例uint8_t newData[16] { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10 }; if (nfc.mifareclassic_AuthenticateBlock(uid, uidLength, 4, 0, keyA)) { if (nfc.mifareclassic_WriteDataBlock(4, newData)) { Serial.println(写入成功); } else { Serial.println(写入失败); } }写入失败的原因通常有几个密钥不对、块不可写、卡片被锁、或者卡片类型不支持。如果你反复写入失败先换一张卡试试确认是卡片的问题还是模块的问题。5. 调试过程中那些“看起来像坏了”的典型现象5.1 串口打印乱码波特率还是电平问题串口打印乱码是最常见的现象之一。原因通常有两个波特率不匹配或者电平不匹配。波特率不匹配很好理解PN532 的波特率可能是 115200也可能是 9600你代码里设的是 115200但模块实际是 9600那打印出来就是乱码。解决办法很简单把代码里的波特率改成 9600 试试或者反过来。电平不匹配就麻烦一点。如果你的主控是 5V 逻辑PN532 是 3.3V 逻辑而且模块没有电平转换那通信就会不稳定表现为乱码、丢包、或者完全没反应。这种情况下你需要加一个电平转换模块或者把主控换成 3.3V 逻辑的。还有一个容易被忽略的点GND 没接。UART 通信需要共地如果 GND 没接信号就没有参考电平通信肯定失败。我遇到过有人只接了 TX、RX、VCC没接 GND然后问我为什么没反应。这种情况接上 GND 就好了。5.2 读到卡片但 UID 全是 0天线问题如果你能读到卡片但 UID 全是 0或者读到的数据明显不对那大概率是天线问题。PN532 模块的天线是 PCB 走线做的如果天线周围有金属物体或者天线被遮挡就会影响读卡效果。我遇到过一种情况模块放在金属桌面上读卡距离从 5cm 降到了 1cm而且读到的 UID 偶尔会出错。后来把模块拿起来远离金属就恢复正常了。所以调试的时候尽量让模块远离金属物体尤其是大面积的金属比如电脑机箱、金属桌面、铝制外壳。另外天线的匹配电容也可能有问题。有些廉价模块的天线匹配电容焊接不良导致读卡距离短或者读不到卡。如果你怀疑是这个问题可以试着轻轻按压天线附近的电容看看读卡效果有没有变化。如果有变化那可能就是虚焊需要补焊。5.3 模块发热严重供电电压过高PN532 正常工作时会有轻微发热但如果你感觉模块明显发烫那就要检查供电电压了。PN532 的供电电压是 3.3V绝对不能接 5V。虽然有些模块标称支持 5V但那是指逻辑电平支持 5V供电还是 3.3V。如果你把 VCC 接到 5V芯片会过热甚至烧毁。我建议你在接线之前先用万用表测一下主控板的 3.3V 输出是否稳定。有些主控板的 3.3V 输出纹波很大或者电压偏高比如 3.6V长期使用也会影响 PN532 的寿命。如果条件允许可以用一个独立的 3.3V 稳压模块给 PN532 供电这样最稳定。5.4 读卡距离短天线调谐与干扰读卡距离短是另一个常见问题。PN532 的标称读卡距离是 5-7cm但实际使用中很多模块只能读到 2-3cm。原因可能有几个天线调谐不准、周围有干扰源、卡片类型不匹配。天线调谐是一个比较专业的话题简单来说PN532 的天线是一个 LC 谐振电路谐振频率需要匹配到 13.56MHz。如果匹配电容的值不对谐振频率偏移读卡距离就会缩短。有些模块出厂时调谐就不太好你可以通过更换匹配电容来改善但这需要一定的射频知识和焊接技巧。对于普通用户来说更实际的做法是尽量让卡片和天线平行不要倾斜远离干扰源比如手机、WiFi 路由器、开关电源不要在天线附近放金属物体。这些措施能明显改善读卡效果。6. 进阶话题从读写卡片到理解 NFC 与 RFID 的边界6.1 RFID 和 NFC 到底有什么区别很多人把 RFID 和 NFC 混为一谈其实它们有关系但不是一回事。RFID 是一个大范畴包括低频125kHz、高频13.56MHz、超高频860-960MHz等多种频段。NFC 是 RFID 的一个子集特指 13.56MHz 频段下的一套通信协议而且 NFC 还包含了卡模拟、点对点通信等更复杂的功能。PN532 支持的是 13.56MHz 下的 RFID 协议也就是 NFC 的基础部分。它能读 Mifare Classic、Mifare Ultralight、NTAG 系列等卡片也能模拟成这些卡片。但它不支持低频 RFID比如 125kHz 的 EM4100 卡也不支持超高频 RFID。所以如果你要读 125kHz 的卡PN532 是做不到的需要换别的模块。6.2 关于“复制加密门禁卡”这件事网上有很多关于“用 PN532 复制门禁卡”的教程但实际情况比想象中复杂。首先不是所有门禁卡都能复制。Mifare Classic 卡如果密钥被改过你需要先破解密钥而破解密钥需要用到字典攻击或者暴力破解这个过程可能很慢而且不一定成功。其次有些卡片有防复制机制比如 Mifare Plus、DESFire 等这些卡片用了更复杂的加密算法PN532 读不了也复制不了。另外从合规角度来说复制别人的门禁卡可能涉及法律问题。我建议你只在自己拥有的卡片上做实验比如自己的门禁卡、自己的公交卡不要尝试复制别人的卡。这一点很重要不要因为技术好奇而惹上麻烦。6.3 PN532 的卡模拟功能能做什么不能做什么PN532 支持卡模拟Card Emulation模式也就是说它可以模拟成一张卡片被别的读卡器识别。这个功能在实际中有很多用途比如模拟一张门禁卡来开门、模拟一张公交卡来乘车。但卡模拟有几个限制第一PN532 只能模拟 Mifare Classic 或 Type 2 Tag 等简单卡片不能模拟 DESFire 这种复杂卡片。第二模拟的 UID 是固定的不能随意修改除非你修改固件。第三卡模拟的稳定性不如真实卡片有时候读卡器会识别失败。如果你要玩卡模拟我建议你先从模拟一张 Mifare Ultralight 开始这个最简单代码也容易找。等熟悉了之后再尝试模拟 Mifare Classic。7. 一些让我少走弯路的实操习惯调试 PN532 的过程中我慢慢养成了一些习惯这些习惯帮我省了不少时间。第一个习惯是每次接线之前先用万用表测一遍。测什么测 VCC 和 GND 有没有短路测 TX 和 RX 有没有接反测拨码开关的状态对不对。这个步骤花不了一分钟但能避免很多低级错误。第二个习惯是先跑通读 UID再折腾读写数据。读 UID 是最基础的功能如果连 UID 都读不到那后面的读写数据肯定也做不了。读 UID 通了之后再一步步加功能这样出问题了也容易定位。第三个习惯是保留一份“已知可用”的接线和代码。每次调通一个配置我就把接线图和代码保存下来下次遇到类似的项目直接复制粘贴省得重新调。PN532 的配置组合很多UART、I2C、SPI 各有各的接线方式保存一份可用的配置能省很多事。第四个习惯是不要迷信“默认设置”。PN532 的默认波特率、默认密钥、默认拨码开关位置都可能因为模块批次不同而不同。拿到新模块先确认这些默认值再开始写代码。我遇到过一块模块默认波特率是 9600但我按 115200 调了半天后来改成 9600 就通了。这个坑不常见但遇到了就很浪费时间。最后一个习惯是多准备几张不同类型的卡片。Mifare Classic、Mifare Ultralight、NTAG213、NTAG215这些卡片 PN532 都支持但读写方式略有不同。多准备几张方便测试不同场景。比如Mifare Classic 有扇区和密钥的概念NTAG 系列则是按页读写没有密钥验证。了解这些差异能帮你更好地理解 PN532 的工作方式。
返回列表