简介:面向嵌入式开发者的RC522射频模块测试程序,基于STM8S105微控制器,实现M1非接触式IC卡的ID读取,并利用UART串口将卡片信息发送至上位机,方便调试与监控。整个工程基于IAR Embedded Workbench环境构建,代码注释较为详细,并附带参考原理图,能够帮助初学者快速理解RC522与STM8S105之间的硬件连接,以及RFID寻卡、防碰撞、选卡、读卡等关键流程。资源包共120个文件,以C源文件、头文件、链接配置文件、工程文件、十六进制固件等类型为主,大小约2.04MB,同时包含多个STM8S标准外设驱动模块,覆盖定时器、串口等常用功能,整体结构清晰,便于直接导入IAR工程进行编译烧录。已有236人学习/下载,对于希望入门STM8单片机与RFID应用,或需要搭建RC522读写样例的开发者来说,是一份兼具学习参考与实战价值的实用资料。 前两天整理开发资料库,翻出一个RC522测试程序,用的芯片是STM8S105,整个工程打包成RC522测试程序-采用STM8S105.rar,放在文件夹里快两年了。这个包当初是我做门禁读头样品时留的底子,后来陆陆续续发过好几次给别人,都是刚接触RC522模块、想先把卡号读出来的开发者。今天不藏私,把里面的硬件接线、驱动逻辑、多卡识别处理和调试心得从头到尾捋一遍,有需要的可以直接拿去做参考。
1. 测试程序的功能边界:为什么用STM8S105做RC522验证
1.1 最小化验证:从读卡号到读写块
RC522是市面上最常见的13.56MHz RFID读写芯片,支持ISO14443A协议,Mifare S50、S70这类卡都能操作。STM8S105是意法半导体的8位MCU,主频不高,RAM和Flash都算不上宽裕,但跑RC522这种轻量级读写协议绰绰有余。这套测试程序解决的核心问题只有一个:让开发者在最短时间内确认“单片机能不能稳定读到卡号”。听起来很简单,但实际要做到上电就出卡号、连续读不丢、串口输出可观测,背后涉及到SPI通信、寄存器时序、防碰撞算法状态机好几个环节。
很多人喜欢直接在STM32开发板上调RC522,确实库多资料多,但8位机上如果能把底层驱动写干净,说明代码没有过度依赖高级外设库。测试程序设计上就是一个最小化验证工程:主循环不断寻卡,读到UID就通过串口打印,同时点一个LED指示。硬件链路完整跑通之后,再往上面加读块、写块、金额操作都顺理成章。
1.2 代码目录设计与模块划分
rar包里解压之后,源码结构建议保持这几块:平台初始化部分负责时钟、GPIO、UART调试口和SPI外设;RC522底层驱动负责寄存器读写、PCD命令收发、软复位和天线开关;卡片操作层负责寻卡、防碰撞、选卡、读取卡号;主循环做业务调度,也就是轮询寻卡和超时处理。这样分层的意义在于,出了问题能快速定位是芯片级还是卡片级。
我以前见过有人直接把网上STM32的RC522库整个粘到STM8工程里,结果引脚定义对不上,寄存器地址也因为芯片封装差异出现编译错误。测试程序虽然是工程压缩包,但本质上更重要的是一套驱动逻辑。把SPI读写函数抽象出来,把RC522寄存器和命令字用宏定义,后续换MCU、换板子都能少踩一半的坑。
2. 硬件连接与SPI通信原理:先让板子说话
2.1 RC522模块引脚与STM8S105的映射
RC522模块常见引脚有8个:SDA、SCK、MOSI、MISO、IRQ、RST、VCC、GND,默认工作在SPI模式。这里SDA其实承担的就是片选CS功能。STM8S105的SPI1引脚会因为封装不同有差异,我这里用过的板子是把PD2作为CS、PD3作为SCK、PD4作为MOSI、PD5作为MISO、PD6作为IRQ、PD7作为RST,VCC接3.3V,GND共地。注意不同PCB设计完全可能不一样,动手前一定要先查芯片数据手册和板子原理图,别照着我的表直接乱接。
SPI通信可以理解成一条带片选的生产线。NSS决定哪台设备在线上干活,SCK是节拍器,MOSI和MISO分别是两条方向相反的传送带。RC522作为从机,只有在CS拉低的时候才响应主机的时钟和数据。STM8S105作为主机,所有SCK、MOSI的操作都必须配合CS信号完成。
2.2 SPI模式与电平匹配的取舍
RC522的SPI支持模式0和模式3,测试程序里我用的是模式0,即CPOL=0、CPHA=0,SCK空闲时低电平,数据在第一个沿采样。对于8位MCU来说,模式0的时序最简单,逻辑分析仪抓波形也容易看懂。SPI时钟频率一开始不要贪高,我用的是系统时钟16分频,约1MHz。RC522本身支持10MHz的时钟,但杜邦线下拉个1MHz最稳,后面做产品再根据板子布线去提频。
电平问题是新手最容易忽略的。RC522模块基本都是3.3V供电和3.3V逻辑,有些STM8S105最小系统板虽然MCU是3.3V,但板上带了5V转3.3V的稳压电路,这时候如果再把5V接到RC522的VCC,模块很可能直接烧掉。反过来,如果MCU是5V供电且IO口不是容忍5V的,那RC522的3.3V引脚可能被反向灌电流。稳妥做法是确认两边都是3.3V逻辑,不给模块供电超过3.6V。
3. 核心代码逐段拆解:寻卡、防碰撞、多卡识别
3.1 硬件SPI初始化与GPIO配置
STM8S105的硬件SPI1初始化代码不长,要点在软件NSS模式。我不用硬件自动片选,而是把CS引脚当普通GPIO拉低拉高,这样切换RC522和别的SPI设备更顺手,也不会因为软件管理NSS没配置好出现时序错乱。初始化代码大概是:
void SPI1_Init(void) { SPI1_CR1 = 0x02; // 主模式,CPOL=0 SPI1_CR2 = 0x06; // 软件NSS,8位数据 SPI1_CR1 |= 0x10; // 使能SPI }这里要特别注意GPIO的模式。SCK和MOSI必须配置成推挽输出,MISO配置成上拉输入。我之前在一个板子上把MOSI接到了开漏输出的引脚,结果波形不对,读卡时好时坏,查了很久才发现是引脚复用模式的问题。测试程序里最好把每个引脚模式和复用功能写清楚,不然换一块板子就抓瞎。
3.2 RC522初始化寄存器时序
RC522初始化做过的人都知道,寄存器播放列表看着像天书,实际上就是三件事:复位芯片,配置定时器,打开天线。硬复位时RST引脚先拉低再拉高,等一段时间再写软复位命令。然后是定时器配置,TMode、TPrescaler、TReload这几个寄存器负责生成超时时间,后续发送命令如果卡没响应,不会像死循环一样卡住。
天线控制寄存器TxControlReg要写0x83,打开发射电路。很多测试程序跑不起来,最后发现是天线没开,信号根本发不出去。初始化完成后,可以读VersionReg寄存器,正常会返回0x92或0x91,这个值是很好的自检点。我习惯在测试程序里加一个版本号读取,如果读不到0x92,大概率是SPI通信或者复位时序出了问题。
3.3 读卡号主流程与多卡处理逻辑
读卡号的核心三连是寻卡、防碰撞、选卡。寻卡命令用0x52或0x26,卡片进入天线场区后会返回ATQA应答;防碰撞命令是0x93加参数,能拿到卡的4字节UID和一个校验字节;选卡成功后卡片进入Active状态,后面才能读写数据块。测试程序主循环里跑的也就是这套流程:
if (PcdRequest(0x52, atqa) == OK) { if (PcdAnticoll(uid) == OK) { PcdSelect(uid); UART_SendString("UID: "); for (i = 0; i < 4; i++) UART_SendHex(uid[i]); } else { PcdReset(); } }这个代码里最容易被忽略的是PcdReset()。实测中防碰撞失败后,RC522内部状态可能没清理干净,如果直接发下一次命令,会连续失败好几次,甚至进入假死状态。做测试程序时宁可在失败分支里多花一点时间做复位,也不要图省事跳过。
多卡识别算是RC522应用里一个被反复问的问题。两张卡同时放在天线上面的时候,RC522的防碰撞算法通过位帧检测来区分不同卡。但这不代表调用一次防碰撞就能连续把两张卡都读完。我的处理办法是:每轮检测只拿一张卡,拿到后可以对该卡执行Halt让其暂时离开场区,然后继续下一轮寻卡;或者干脆在每轮之间加20毫秒延时,让用户把卡片拿开再放新卡。测试程序里真正的目标不是做一拖多读写器,而是验证硬件在多卡场景下不崩溃,能稳定回到寻卡状态。
4. 调试现场实录:读不到卡、乱码、多卡异常的排查
4.1 三个高频问题和排查顺序
先动手调RC522的时候,遇到最多的是三种现象:第一种是串口完全没反应,寻卡永远失败;第二种是偶尔能读出卡号,但卡号里出现乱码;第三种是两张卡放在一起时,要么只能读一张,要么直接死机。遇到这些问题,我从来不去博客下面复制别人的答案,而是按这个顺序排查:先量电压,确认RC522的VCC在3.3V附近,RST引脚不是悬空状态;再看SPI波形,用逻辑分析仪抓SCK和MOSI,确认主机确实把命令发出去了;最后才怀疑卡片本身,换一张S50白卡试。
有段时间我的测试程序一直报寻卡超时,折腾半天发现是手边那张门禁卡根本不是ISO14443A协议,RC522压根不认识它。所以测试卡一定用标签初始的Mifare S50白卡,别拿电梯卡、门禁卡来试。
4.2 SPI不稳定与电源干扰的实战心得
读卡偶尔成功偶尔失败,先不要怀疑算法,多半是物理层面的干扰。杜邦线超过15厘米,SPI时钟再提到4MHz,波形就已经畸变得没法看了。把SPI分频调低,线束缩短到10厘米以内,两个地连在一起,问题马上缓解。另一个容易被忽略的是电源。RC522天线发射瞬间电流不小,如果模块供电靠的是单片机板子上的线性稳压器,电流不足时电压会跌落,卡片应答信号就会忽强忽弱。我是直接在模块VCC和GND之间并了一个10uF电解电容和一个0.1uF陶瓷电容,效果好很多。
读卡号出现乱码还有一个细节:STM8S105的SPI接收数据后,如果没及时读取,硬件会产生溢出错误,后续数据全乱。测试程序里每次SPI读写完都检查一下SPI_SR的OVR标志,被发现溢出就清理掉。这个坑在寄存器手册里写得很含蓄,但实际非常常见。
4.3 常见问题速查表
这里把我在调试过程中积累的排查经验整理成一个表格,方便直接对照处理。
| 现象 | 可能原因 | 解决办法 |
|---|---|---|
| 寻卡一直超时 | 卡片不在场区、天线未打开、卡类型不兼容 | 确认用S50白卡、读VersionReg、检查RST时序 |
| 偶尔读到卡号且乱码 | SPI速率过高、接线过长、电源纹波大 | 降低SPI分频、缩短杜邦线、模块电源并电容 |
| 两张卡同时放只能读一张 | 天线场区能量不足、防碰撞后状态未清理 | 卡片分开放置、失败后PcdReset、加延时重试 |
| 程序跑一段时间死机 | RC522内部状态错乱、SPI溢出未处理 | 失败分支做软复位、每次SPI通信后清OVR标志 |
5. 工程环境搭建与跨芯片移植
5.1 把rar里的工程跑起来
拿到RC522测试程序-采用STM8S105.rar之后,第一步不是双击工程文件,而是先确认自己的编译环境。我当时用的是IAR for STM8,也有用STVD的老项目。打开工程后,先检查芯片型号是不是自己的具体封装,比如STM8S105K6和STM8S105C6的Flash、RAM一样,但引脚映射不同,编译出来烧进去效果也会不一样。头文件路径里如果看不到stm8s.h,说明环境没有配置好。
编译通过后下载建议直接用ST-Link,便宜稳定。没有ST-Link的话,串口ISP也可以,但需要板子出厂带Bootloader。第一次跑测试程序,不要急着看读卡,先把一个GPIO翻转的例程烧进去,点上LED,确认编译器、下载器、烧录链路全通,再接RC522模块。这样可以把“环境问题”和“硬件问题”隔离开。
5.2 从STM8S105移植到STM32的底层替换
这个测试程序虽然是给STM8S105写的,但网上搜“rc522读写卡程序stm32”的人非常多,其实移植也很简单。上层的PcdRequest、PcdAnticoll、PcdSelect全部不用动,要换的只有SPI底层读写函数和引脚宏定义。只要把原来操作SPI1_DR的代码换成STM32的HAL库或标准库的SPI发送接收函数,再把CS、RST这些引脚对应到STM32的GPIO口,编译就能跑。我自己从STM8S105迁到STM32F103,只改了一个底层文件,半小时点亮串口。
移植的时候我建议把所有片选引脚、RST引脚、SPI外设都用宏定义包起来,比如:
#define RC522_CS_LOW() GPIO_ResetBits(GPIOB, GPIO_Pin_12) #define RC522_CS_HIGH() GPIO_SetBits(GPIOB, GPIO_Pin_12) #define RC522_RST_LOW() GPIO_ResetBits(GPIOB, GPIO_Pin_13) #define RC522_RST_HIGH() GPIO_SetBits(GPIOB, GPIO_Pin_13)这样后面换任何一个引脚,只改宏定义,不用动函数内部逻辑。
5.3 扩展方向与个人体会
如果你不满足于只读卡号,这个工程可以继续加东西。RC522支持对Mifare卡进行KeyA/KeyB鉴权,鉴权通过后可以读整个扇区、写数据块,甚至可以做一个简易的电子钱包逻辑。我后来把读卡号改成了中断触发,用RC522的IRQ引脚唤醒STM8S105,平时单片机睡在低功耗模式,卡片靠近才醒来处理。测试程序的轮询逻辑换成中断驱动,也只是一层壳的问题。
调试RC522这类射频模块,最忌心急。很多时候程序没问题,是天线位置压着了,或者隔壁桌开关电源在干扰。我的经验是先在干净的环境下把卡片垂直放在模块正上方,读出稳定卡号之后,再测试多卡、远近、角度这些变量。射频的东西,硬件状态对结果的影响远大于那几行代码。
顺便说一句,如果用的是那种小板载天线的一体化RC522模块,测试时千万别把它贴在金属桌面上,否则读卡距离会从五厘米直接缩水到一厘米。这个细节我吃了两次亏,提醒一下后来人。
本文还有配套的精品资源,点击获取