我第一次拿到PN532模块的时候,面对板子上那两排排针其实是有点懵的。这颗工作在13.56MHz频段的NFC芯片,读写IC卡、模拟卡片、点对点通信都能干,但它同时甩给你I2C、SPI、HSU三套主机接口,等于逼着你在三种总线协议里先做个选择。我当时想的是“随便接一种能跑就行”,结果I2C接不上查了半天,SPI跑通之后又发现DMA和片选一堆讲究,最后把三种接口全部调通,才真正理解了为什么NXP把三条总线都留在芯片上。这篇就把PN532的多协议通信实战经验从头到尾捋一遍,从原理到接线、从时序到踩坑,尽量一次讲透,给正在做NFC相关项目的朋友一个参考。
1. 为什么PN532值得折腾:三套接口对应三种取舍
1.1 PN532到底是什么芯片
PN532是NXP出品的一颗NFC前端芯片,内部集成了13.56MHz的射频模拟前端和协议处理固件。它支持ISO/IEC 14443A/B、MIFARE Classic、FeliCa这些主流卡片协议,也支持NFCIP-1模式,也就是两台NFC设备之间可以点对点交换数据。你拿它做门禁卡读取器、开发板上的NFC扩展模块、甚至是简单的支付终端原型,都没有问题。
这颗芯片之所以在爱好者圈子里流行,除了功能齐全之外,更重要的原因是它把主机通信接口做得非常开放。芯片对外提供I2C、SPI、HSU三种接口,主机MCU可以根据自己的外设资源任选一种来实现控制。这放在很多同类芯片上是不可想象的,多数NFC芯片要么只给I2C,要么只给SPI,能同时给你三条路走的确实不多。
但接口多也带来了选择困难症。我在网上看到很多帖子问“PN532用哪种接口好”,评论区往往各执一词。有人坚持I2C,理由是省引脚、接线少;有人推荐SPI,理由是速度快、不用上拉电阻;还有人推荐HSU,理由是最接近串口、调试方便。这些说法都对,但都只看到了一个侧面。真正决定用哪种接口的,是你的主控资源、通信频率要求和排错成本。
1.2 三套接口的原理差异
这三套接口的本质差异,可以从物理层和协议层两个维度来看。
I2C是两线制总线,SCL提供时钟,SDA传数据,所有从设备靠地址区分,典型速率是100kHz和400kHz。它的特点是引脚少、支持多设备挂载,但因为是开漏结构,必须接上拉电阻,而且半双工通信意味着读写不能同时进行。
SPI是四线制总线,SCK、MOSI、MISO、CS各司其职。SCK提供时钟,MOSI从主机发数据到从机,MISO从从机发回主机,CS负责片选。它没有地址概念,靠硬件电平选通设备,支持全双工,速率可以做到几MHz甚至更高。缺点是每增加一个设备就要多占一个片选引脚,四线起跳。
HSU的全称是High Speed UART,本质上就是一路串口。物理层和普通UART完全一样,TX、RX两根线,异步通信,不需要时钟线,默认波特率115200。它的协议层由PN532固件自己定义,有固定的帧格式,不是随便往里丢数据就能用。
我习惯用一个类比来记忆:I2C像公共走廊,大家都从走廊过,房间门上贴门牌号(地址);SPI像专属电梯,主机按按钮选中哪个从机(片选),电梯就只服务它;HSU像打电话,拨通之前先要有一套“喂喂,听得见吗”的握手和帧同步机制。三种方式都能到达目的地,但成本、速度、适用场景完全不同。
1.3 选型决策
在开始连线之前,我的建议是先做下面这几件事,能省掉后面大量的返工。
先看主控有什么外设。如果你的MCU正好有硬件I2C外设,引脚又紧张,那就优先用I2C;如果主控是STM32这类外设丰富的芯片,SPI口空闲很多,那就用SPI,传输速度快、时序可控性更好;如果主控没有专门的总线外设、只想用普通GPIO模拟,那HSU是最容易上手的,因为串口几乎是标配。
再看你的应用场景。如果只是读个卡号、做门禁,I2C完全够用,400kbps的速率对卡片操作来说绰绰有余。如果要做点对点大数据交换,或者想在最短时间内完成一轮轮询,那SPI的高速率优势就体现出来了。HSU最适合的场景是主控板和PN532分开放置、中间用杜邦线或者接插件连接的情况,串口抗干扰能力相对好,而且逻辑分析仪随便一接就能看数据。
最后看调试工具。I2C和SPI的时序用逻辑分析仪非常直观,但前提是你手里有;如果只有USB转串口模块,那HSU几乎是唯一选择,直接把TX、RX接到转串口模块上就能看数据包。这些因素加起来,其实已经帮你圈定了方向。
2. I2C实战:从外部上拉到时序分析的完整链路
2.1 接线与模式选择
I2C模式下,PN532需要接的引脚是VCC、GND、SCL、SDA,另外强烈建议把IRQ引脚接到MCU的一个输入引脚上。很多模块把IRQ引出但没人用,这个引脚在后面讲帧读取策略的时候非常关键。
接线本身不复杂,但有一个非常容易被忽略的点:PN532的接口模式不是软件配置的,而是靠两个引脚在复位释放时的电平状态决定的。不同厂家的模块对这两个引脚的默认处理不一样,有的模块已经通过跳线帽固定为I2C模式,有的则需要你自己接。所以拿到模块第一步是看丝印或者原理图,确认模块上I2C、SPI、HSU模式对应的引脚接法,再决定怎么接线。
连好之后先不要急着发数据,拿万用表量一下SCL和SDA的对地电压。I2C总线空闲时SCL和SDA应该都被上拉电阻拉到高电平,通常是3.3V或者5V,取决于模块出厂时的上拉配置。如果量到0V,先检查电源和地,不要直接怀疑芯片坏了。
PN532的I2C从机地址是0x24(7位地址)。在总线上实际传输的地址字节,左移一位再拼上读写标志位:写操作是0x48,读操作是0x49。如果你的模块上有地址选择引脚或者跳线,手册里通常会给出可选地址,默认值就是0x24。
2.2 为什么I2C要求开漏输出加外部上拉
网上搜I2C相关的问题,“i2c为什么用开漏输出加外部上拉电阻”这个疑问出现频率极高。这个问题的答案直接决定了你的硬件设计是否可靠。
I2C协议规定设备SDA和SCL引脚必须是开漏结构,意思是引脚内部只有下拉能力,没有上拉能力。引脚想输出低电平时,内部晶体管导通,把总线拉低;想输出高电平时,晶体管关断,引脚呈现高阻态,此时总线上没有驱动源,必须依靠外部上拉电阻把电平拉高。
为什么偏偏用开漏结构?因为这样可以防止两个设备同时驱动总线导致短路。如果用推挽输出,一个设备输出高、另一个设备输出低,电流会直接从电源流到地,轻则信号错乱,重则烧毁引脚。开漏结构下,任何时刻只有“拉低”一种主动行为,总线空闲电平由电阻决定,多个设备并在一起也不会打架。
这也就解释了很多人的困惑:为什么PN532接到STM32上,明明引脚配置成开漏输出了还是通信失败?大概率是总线外部根本没有上拉电阻,或者模块出厂时只针对3.3V做了上拉,而你用5V电源供电。
2.3 上拉电阻怎么算,为什么“电阻小了不通信”
I2C上拉电阻的取值不是拍脑袋定的,有两个边界要同时满足。
第一个边界是最小电阻值,由灌电流限制决定。I2C设备输出低电平时,会有一个最大灌电流限制,常见标准是3mA。电源电压3.3V,低电平阈值VOL最大0.4V,那么电阻上的压降至少是3.3减0.4等于2.9V,电阻最小值大约是2.9V除以3mA,约等于966欧姆。也就是说,上拉电阻小于1k左右,设备拉低总线时电流会超过规格,导致VOL抬升,从机可能识别不到有效的低电平。
第二个边界是最大电阻值,由总线电容和上升时间决定。I2C标准规定了不同速率模式下的最大上升时间,100kHz标准模式是1000ns,400kHz快速模式是300ns。上升时间近似等于0.8473乘以RC,其中R就是上拉电阻,C是总线寄生电容。总线电容一般估算为100pF到400pF,如果取200pF,快速模式下允许的最大电阻约为300ns除以0.8473再除以200pF,算下来约1.77k。电阻取到4.7k在400kHz下已经接近临界,如果你还挂了多个设备,总线电容变大,4.7k就可能不够用。
网上那句“上拉电阻小了不通信”的现象,本质是违反了最小值边界。实测中我用过500欧姆的上拉电阻,现象很典型:读SCL/SDA波形能看到明显的台阶,低电平只能拉到0.8V左右,跟电源轨之间没有明显区分,MCU判断逻辑电平的时候时好时坏。而电阻取到33k以上时,波形上升沿变得非常平缓,在400kHz下一帧数据都传不完,SCL的上升沿已经超过一个位时间了。
所以我的建议很直接:3.3V供电、单从机、总线不长的情况下,用2.2k到4.7k都是安全的,优先用4.7k;总线长了或者挂了多个设备,换成2.2k更稳;如果你不确定总线电容,用4.7k起步,遇到波形上升沿过缓再降到2.2k。
2.4 逻辑分析仪看I2C时序
接线和上拉电阻都没问题之后,下一步就是验证时序。强烈建议把手里的逻辑分析仪挂到SCL和SDA上,抓一次完整通信过程。别嫌麻烦,这一步能帮你省下后面至少半天排错时间。
I2C一帧通信的波形特征是这样的:空闲时SCL和SDA都是高电平;主机想发起通信时,先在SCL保持高电平的状态下把SDA从高拉低,这个下降沿就是起始条件;然后SCL开始出八个时钟脉冲,SDA在这八个时钟内逐个送出地址字节,先发最高位,最低位是读写标志;第九个时钟脉冲是应答位,从机如果收到了正确的地址,会在这时候把SDA拉低,也就是ACK;之后继续按同样的节奏传输数据字节;最后通信结束时,主机在SCL保持高电平的状态下把SDA从低拉高,这个上升沿就是停止条件。
你抓到的地址字节如果写操作是0x48、读操作是0x49,那就说明地址匹配正确。后面跟的ACK信号也是关键,如果地址发出去之后第九个时钟上SDA一直是高,那就是从机没有应答,问题多半出在接线、上拉电阻或者PN532的模式引脚配置上。
数据部分看的时候有个小技巧:把逻辑分析仪的通道映射配成I2C协议解码,工具会自动解析出地址和每个字节的数值,不需要肉眼看波形数位。但在没有自动解码的低端逻辑分析仪上,数位也没那么难,八个时钟一组,数完时钟数数据就完了。
2.5 I2C总线的复位办法
I2C虽然简单,但有一个别的问题:一旦SCL或SDA卡在低电平,整个总线就瘫了。这种卡死往往发生在通信中途被MCU复位打断的场景。PN532作为从机可能还在等待后续字节,你这边程序已经重启,I2C外设重新初始化之后认为总线空闲,但实际上SDA被从机拉住了。
处理办法有两个。最简单的就是给PN532断电重新上电,但如果你不希望每次卡死都断电重启,可以尝试软件复位总线:用GPIO模拟,把SCL翻转九次以上,同时观察SDA,如果SDA在某一次SCL上升沿之后释放了,说明从机已经退出异常状态。这个操作的原理是,I2C从机在收到第九个时钟后如果没有ACK,会放弃当前传输并释放总线。我把这个流程封装成一个函数,在每次初始化I2C之前先跑一遍,实测能解决大部分卡死问题。
3. SPI实战:时钟、片选与DMA效率
3.1 PN532的SPI模式接线与要点
SPI模式下PN532的用法跟I2C有显着不同。首先,物理层从两根线变成四根线,SCK接主机的SPI时钟,MOSI接主机发送,MISO接主机接收,另外还需要一根CS线,通常接MCU任意一个GPIO,软件控制拉低拉高。
需要特别注意的是,PN532的SPI时序要求主机在CS拉低之后,先发送状态读取命令或者写命令,芯片会通过MISO返回状态字节。如果状态字节是0x01,表示芯片空闲、可以接收新命令;如果是0x00或者别的值,说明芯片还在忙。有些库会自动处理这个状态字节,但如果你是自己写驱动,不要忽略这一步,直接发完命令就读响应,很容易读到空数据或者错位数据。
关于SPI速率,PN532的数据手册没有像I2C那样给出特别高的极限,实际经验是SCK频率不要超过几MHz量级。我用STM32F103时,SPI1挂在APB2上,72MHz主频,分频到16得到4.5MHz,实测稳定;再往上提到9MHz也能跑,但杜邦线一长就容易出随机错误。如果你的PN532模块和MCU之间走线超过十厘米,建议把速率压到2MHz以内。
3.2 CPOL和CPHA:为什么从模式0开始调
SPI虽然叫标准总线,但并没有统一规定时钟极性和相位,不同芯片要求不一样,这就是教科书里反复强调的CPOL和CPHA。CPOL决定空闲时SCK是高还是低,CPHA决定数据在SCK的哪个边沿被采样。组合起来有四种模式,型号从0到3。
PN532的SPI接口按照数据手册要求工作在模式0,也就是CPOL为0、SCK空闲低电平,CPHA为0、数据在SCK第一个边沿(上升沿)采样。这也正好是STM32的CubeMX里SPI初始化默认弹出的模式0。所以很多例程直接照抄默认配置就能跑通。
但这也带来一个隐患:如果你是从别的项目里复制来的SPI初始化代码,而那个项目用的是SPI Flash,很可能配置成了模式3,CPOL为1、CPHA为1。模式3和模式0在波形上看上去很像,但数据采样边沿差了一个相位,结果就是PN532完全无响应,或者返回全零。遇到这种情况不要怀疑芯片,先用逻辑分析仪看SCK空闲电平,是低就是模式0,是高就是模式3。
3.3 硬件片选与软件片选的实战取舍
“spi硬件片选与软件片选”这个话题在STM32社区里讨论度一直很高,PN532上也能体现得淋漓尽致。
硬件片选是指由SPI外设自动控制NSS引脚,主机开始传输时自动拉低,传输结束后自动拉高。好处是CPU不用管,DMA传输时尤其方便。但在PN532这种需要“先发命令、等待芯片空闲、再读响应”的交互场景里,硬件片选的自动化反而成了麻烦。PN532的命令帧和响应帧之间有一段不确定的等待时间,期间CS必须保持低电平还是可以拉高,不同固件版本行为不完全一致。如果让硬件自动控制CS,传输完命令帧就立刻拉高,可能导致芯片认为本次通信被中断。
软件片选则是把CS接到普通GPIO上,自己决定什么时候拉低、什么时候拉高。这样最灵活,我可以等IRQ引脚变低、确认PN532有响应数据之后,再拉低CS去读。虽然多写了几行代码,但通信边界完全可控,排错也直观。我在所有STM32工程里都用了软件片选,CubeMX里把NSS配置为Disable,然后自己定义一个GPIO做CS脚。
3.4 STM32F103配合CubeMX配置SPI DMA读取
如果你的主控是STM32F103,想用DMA方式跟PN532通信,配置步骤比单纯轮询多一点,但效果是CPU占用率低很多,特别适合后续还要跑协议栈或者LCD显示的场景。
CubeMX里的关键配置大致是这样:SPI1使能,Mode设为Full-Duplex Master,硬件NSS关掉,数据大小8位,时钟分频看情况,模式0,然后到DMA配置页面给SPI1_RX和SPI1_TX分别添加DMA请求。GPIO部分,SCK、MOSI、MISO复用为SPI功能,CS设为推挽输出,初始电平置高。
初始化完成之后,读PN532固件版本的命令帧是固定的一个序列,完整命令是:00 00 FF 02 FE D4 02 2A。这段命令的含义这张表可以对应起来:
| 字节 | 值 | 说明 |
|---|---|---|
| 起始头 | 00 00 FF | PN532帧起始标志 |
| LEN | 02 | 后面PDU和校验总共2个字节 |
| LCS | FE | 0x100减去LEN得到的校验值 |
| TFI | D4 | 主机发往PN532的方向标识 |
| 命令 | 02 | GetFirmwareVersion |
| DCS | 2A | 0x100减去TFI加命令的和 |
发送的时候,先把CS拉低,然后用DMA把这段8个字节发出去。PN532收到命令后会拉低IRQ引脚,这时候再拉低CS,用DMA接收响应帧。响应帧的格式跟命令帧类似,TFI变成D5,命令号变成03,后面跟着固件版本信息。
这一步很容易踩的坑是DMA接收长度。PN532的响应帧长度不是固定的,如果盲设一个很大长度去收,DMA会一直占着总线,后续通信全部卡住。我的做法是先启动SPI的DMA接收,同时开串口或者定时器中断,收到一个字节就计数,超过帧长就手动停掉DMA并处理已收到数据。
3.5 DMA收数据不完整的问题
用DMA方式读PN532还有一个常见现象:命令发出去了,IRQ也拉低了,但DMA收上来的数据只有前几个字节,后面的全是0xFF或者直接缺尾帧。这个问题根源在于SPI的半双工交互流程。PN532在CS拉低之后,不会立刻把整个响应帧推出来,它要先发送一个状态字节0x01表示就绪,然后才从帧头开始发数据。如果你的接收缓冲区是从响应帧的第一个字节开始算的,状态字节会被当成帧头缓存进缓冲区,后面的数据全部错位。
我解决这个问题的思路是分两段收:第一次读一个字节,确认是0x01状态字节,丢弃;第二次再从帧头开始接收剩余数据。或者更省事一点,在CS拉低之后先读一次,把状态字节吃掉,再启动DMA接收整帧。这里没有标准答案,哪种方式能跟你的DMA配置对齐就用哪种,关键是心里清楚PN532有一个状态字节的时隙。
4. HSU接口:被低估的串口通信方案
4.1 HSU不是普通UART,帧格式说了算
HSU虽然物理层是UART,但它并不是你往串口里发什么它就转发什么。PN532在HSU模式下运行的是自己的一套协议帧,和I2C/SPI模式下使用的帧结构是一样的,只是传输载体从总线变成了串口。
这意味着你依然需要按照PN532的帧格式来构造数据。以GetFirmwareVersion为例,HSU模式下发送的字节序列跟SPI模式完全一样,都是00 00 FF 02 FE D4 02 2A。你不用关心波特率冲突、数据位校验位这些串口细节,因为PN532默认就是8个数据位、无校验、1个停止位,波特率115200。
这种设计的优点很直观:不管底层是什么接口,对上层协议栈来说都是同一种帧结构。你写一套帧解析逻辑,就能同时兼容三种接口,这在产品设计时省了很大力气。
4.2 波特率与帧对齐
HSU模式下的经典问题不是速度,而是找帧头。串口是字节流,没有起始条件和停止条件的概念,主机什么时候发、PN532什么时候回,都靠字节之间的空隙来判断。PN532的帧以00 00 FF开头,但三个字节的00 00在正常数据里也可能出现,所以不能看到00 00 FF就立刻认为一定是帧头。
实践中我的做法是维护一个环形缓冲区,串口接收中断把每个字节压进缓冲区,主循环里扫描FF之后紧跟的长度和校验字节。只有LCS校验、DCS校验全部通过,才认为这是一帧完整数据。这个方法适用于所有串口协议解析,不只是PN532。
还有一个细节是超时。串口没有时钟线,主机无法知道从机什么时候把整帧发完。我的策略是每收到一个字节就重置一个软定时器,超过10毫秒没有新字节进来,就认为当前帧接收完毕,开始校验解析。PN532的响应通常在几毫秒内就能发完,10毫秒的超时比较安全。
4.3 HSU的适用场景
HSU最大的价值在工程上。很多项目的主控板本身没有空闲的I2C和SPI口,但几乎所有MCU都有UART。这时候用HSU接口,你只需要占用一个串口,省下的引脚可以拿去接别的传感器。HSU接线只有TX、RX、GND三根,距离可以拉得比I2C和SPI都长,杜邦线接到排母上也不容易出时序问题。
缺点也很明显,115200波特率换算下来每秒才约11.5KB,跟SPI的几MHz完全不是一个级别。另外HSU没有硬件流控,如果PN532连续返回大块数据,MCU处理不及时就会丢字节。所以HSU适合的是读卡、写卡这种单次交互数据量小的场景,不适合大量数据吞吐。
5. 三种接口都会踩的坑:手册里没写透的细节
5.1 接口模式不是热切换的
前面提到PN532的I2C、SPI、HSU模式靠引脚在复位时的电平决定。这句话延伸出一个实操教训:接口模式不是软件寄存器配置,也不是热切换的,想换接口必须断电重新上电,让芯片重新采样模式引脚。
我第一次测试的时候就犯了这个错。程序里先按SPI模式初始化跑通了,然后想在同一个工程里切到I2C调试,只是改了外设初始化和接线,没有断电,结果I2C怎么都扫不到设备地址。后来把模块电源彻底断掉再上电,地址才扫出来。引脚电平变了但芯片仍然按旧模式运行,这个问题不看手册很难想到。
所以如果你手里有模块是用排针引出PD0、PD1的,调试时尽量通过拔跳线帽或者重新上电来切换模式。如果你的模块已经把模式固定死在硬件上,那只能自己飞线或者换模块。
5.2 IRQ引脚的正确使用方式
PN532的IRQ引脚在三种接口模式下都能用,默认状态是高电平,芯片有数据要返回时拉低。这个引脚的核心价值是让主机知道“现在可以读响应了”,而不是让主机无脑等固定延时。
轮询方式下,IRQ可以简化成普通GPIO读取,检测到低电平就去读数据。中断方式下,IRQ接外部中断输入,下降沿触发,中断服务函数里置一个标志位,主循环里处理后续读取。用中断的好处是CPU不用一直盯着引脚,但要注意中断服务函数里不要做耗时操作,只置标志位就够了。
如果你在STM32上跑了FreeRTOS,SPI或者串口中断里最好不要直接调用任务级别的API来唤醒任务。RTOS对中断优先级有严格要求,高于可管理中断优先级的中断不能调用这些API,否则会触发断言。我的做法是把PN532的IRQ中断优先级配置成低于可管理中断优先级的数值,这样在中断里就能安全地使用从ISR后缀的API来通知任务。这个细节如果不注意,系统在低负载时看着一切正常,一旦通信频繁就会出现偶发死机。
5.3 帧超时与状态机紊乱
读PN532时最容易遇到的现象是偶发读超时,然后后续所有通信全部乱掉。这个问题的本质是状态机没有复位。第一帧超时了,但PN532内部可能已经把上一帧处理了一半,你再发下一帧时,它还在等上一帧的剩余字节,于是新命令和旧状态混在一起,返回的数据全是乱的。
处理这个问题的标准姿势是给每次通信设置超时,超时后执行一个复位序列。对I2C是前面提到的SCL九脉冲释放总线,对SPI是重新拉高CS再拉低,对HSU是清空串口接收缓冲区再加软复位。执行完复位之后再重新初始化PN532,这样状态机才能回到一个确定的起点。
我刚开始写驱动的时候偷懒,每帧之间只做了很小的延时,结果在连续读卡100次左右必然出现一次死锁。后来改成每帧都有明确超时,超时就走复位分支,连续跑了一整天都没有再复现过。
5.4 电源与PCB布线的隐性影响
PN532的工作电流在射频发射阶段会明显升高,天线驱动瞬间的电流波动可能达到几十毫安量级。如果你用了一颗LDO给MCU和PN532同时供电,射频发射时LDO输出被拉低,MCU的ADC参考或者SPI电平就可能出现抖动,表现为通信偶发错误。
我遇到过一种很难查的现象:I2C读卡大部分时间正常,但每次读卡号时偶尔会返回校验错。用示波器量VCC才发现,天线发射时VCC上有大约300mV的跌落。后来在PN532电源脚旁边加了一个100uF电解电容和一个0.1uF高频电容,问题立刻消失。如果你用的是模块而不是自己画的板子,模块上通常已经处理好了,但你要是飞线供电,线径和电容千万不要省。
6. 实测对比与选型建议
6.1 三种接口实测表现对比
我把同一片PN532在三种接口下分别跑了读卡和读写MIFARE块数据的测试,工程都在STM32F103上,接的是同一块模块,测量结果供参考:
| 维度 | I2C | SPI | HSU |
|---|---|---|---|
| 接线数量 | SCL、SDA、IRQ、电源 | SCK、MOSI、MISO、CS、电源 | TX、RX、电源 |
| 物理速率 | 400kbps | 4.5MHz | 115200bps |
| 代码难度 | 中,上拉和时序要理解 | 中,片选和状态字节要处理 | 低,像调串口一样 |
| 抗干扰能力 | 一般,总线电容敏感 | 好,但长线下需降速 | 较好,适合长线 |
| 典型场景 | 引脚紧张、多设备总线 | 性能要求高、大数据交换 | 已有串口资源、快速集成 |
实际读卡操作的耗时差异没有理论上那么大。读一张MIFARE Classic卡号,一次InListPassiveTarget加一次读块,I2C模式下大约耗时12毫秒,SPI模式大约9毫秒,HSU模式大约15毫秒。瓶颈在PN532的射频轮询周期上,总线速度只占了一小部分。所以如果你只是做读卡器,I2C的性能完全不会成为瓶颈。
6.2 场景化推荐
综合上面这些对比,我给不同项目朋友的建议是这样的:
做STM32或者ESP32开发板扩展,首选I2C,理由是引脚占用少,而且这类开发板一般都有硬件I2C外设,软件库也很成熟。做产品原型验证,SPI是更稳的选择,通信边界可控、时序直观,调试起来心里有底。做纯串口集成的项目,或者主控芯片只有UART可用,那就直接上HSU,别犹豫,稳定性和代码量都比自己模拟时序舒服。
如果你问我个人偏好,我倾向SPI。不是因为它在数据上快多少,而是SPI的物理层是全双工,时钟由主机完全控制,出错时用逻辑分析仪看波形最容易定位问题。I2C有时候遇到上拉不匹配、地址冲突之类的问题,排查链路会长一点。
6.3 最后的经验分享
最后分享一个对我帮助很大的小习惯:不管用哪种接口,先把GetFirmwareVersion这个命令跑通,再去做读卡功能。这条命令不带任何射频操作,纯粹验证主机和PN532之间的物理链路和帧格式是否正确。如果固件版本读不出来,后面读卡出问题也分不清是通信问题还是射频问题;固件版本能读出来,说明总线已经通了,后面就只需要关注应用层的协议交互。
PN532这颗芯片看着小巧,实际内容不少,但只要你把三种接口都亲手调一遍,对I2C、SPI、UART这三种总线的理解都会上一个台阶。后面再遇到别的I2C传感器、SPI Flash、串口GPS模块,你会觉得底气足很多。这些排错思路和协议分析方法,才是折腾这颗芯片最大的收获。