news 2026/9/1 7:34:33

正点原子Mini STM32F103RCT6驱动RC522读卡程序详解

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
正点原子Mini STM32F103RCT6驱动RC522读卡程序详解

简介:这套RC522读卡程序专为正点原子Mini开发板设计,主控芯片是STM32F103RCT6,代码改写自野火Mini工程。程序通过SPI2接口与MFRC522模块通信,利用串口1把读卡结果和调试信息发送到终端,适合正在学习STM32、SPI总线、串口通信以及RFID应用的开发者参考,稍作修改也可适配其他SPI接口的RFID读卡芯片。压缩包共153个文件,约2.91MB,包含完整工程源码、编译中间文件、Keil工程配置、可烧录的HEX文件以及链接映射文件等,目录结构清晰,整个工程采用标准外设库编写,代码结构整齐,可以直接编译下载。目前已有1782人学习。借助这套程序,读者可以快速搭建RC522读写环境,理解SPI时序和串口输出方法,还能参考其中定时器、LCD、Flash等外设驱动,方便把RC522模块移植到其他STM32型号上,为门禁、电子支付等非接触场景提供实用基础,同时适合入门学习与二次开发。 做嵌入式这些年,开发板换了不少,但正点原子Mini(STM32F103RCT6)这块小板子一直留在我工作台角落。原因很简单:芯片资源够用,例程齐全,跑个RC522这种13.56MHz射频读卡模块非常合适。项目标题说的“正点原子Mini(STM32F103RCT6)Rc522程序”,本质上就是一套让MCU通过SPI总线驱动RC522,实现IC卡读卡、防冲突、选卡、读写扇区数据的裸机程序。这篇文章我把硬件接线、底层驱动、核心代码、调试心得全部拆开讲,适合正在学STM32外设驱动、或者准备做门禁/考勤/校园卡读卡项目的朋友直接抄作业。

1. 这个项目的本质:一块板子加一个射频模块的通路搭建

1.1 STM32F103RCT6和RC522分别在干什么

很多新手拿到“RC522程序”第一反应是:能不能直接复制到自己的板子上?这就得先搞明白这套系统里两个主角的分工。

STM32F103RCT6是意法半导体旗下的Cortex-M3内核芯片,主频72MHz,片上Flash 256KB,SRAM 48KB。在正点原子Mini板上,它负责运行逻辑:初始化SPI外设、控制GPIO拉高拉低、解析RC522返回的数据、把卡号打印到串口或者显示在屏幕上。RC522则是恩智浦的MFRC522射频读写芯片,工作频率13.56MHz,支持ISO14443A协议,常见的Mifare S50、S70卡都能读。它负责“无线电”这一层:发射射频场、调制解调卡片返回的信号、完成CRC校验等底层活儿。

简单说,MCU是大脑,RC522是耳朵和嘴巴。程序里最核心的工程问题,就是让这两个芯片用同一种语言(SPI协议)说话。

1.2 这套程序能做什么,谁适合参考

完成这个项目后,你可以实现以下功能:

  • 读出一张Mifare卡的4字节序列号(UID),通过串口打印出来
  • 选卡后对指定扇区进行密钥验证,验证通过后读写块数据
  • 把卡号显示在OLED屏或者LCD屏上,扩展成简易门禁系统
  • 把读到的卡号与上位机交互,做考勤记录、会员管理等应用

适合参考的人群很明确:正在学STM32 SPI通信的初学者,做过基础流水灯想进阶的新手,以及需要快速在主控里集成RFID读卡功能的开发者。RC522模块价格便宜,几块钱一个,比买整套RFID开发板划算得多。

2. 硬件准备与接线:动手前先答对三道题

2.1 物料清单和模块选型建议

我的建议配置如下:

  • 正点原子Mini开发板(STM32F103RCT6核心板)
  • RC522模块(带天线一体板,最常见那种蓝色PCB)
  • 一张Mifare S50卡,或者普通IC卡、门禁卡
  • 杜邦线若干,母对母、母对公都备一点
  • USB转TTL串口模块(如果板载没有USB串口)

选RC522模块时注意看天线大小,我试过几种,那种矩形三圈天线的模块读卡距离大概能到3~5cm,圆形小天线模块只有2cm左右,差别不小。如果要做门禁项目,建议选大面积天线的模块,读卡体验会好很多。

2.2 RC522与正点原子Mini的引脚对照表

正点原子Mini板上的SPI2接口在PB13、PB14、PB15这三个引脚,这个是硬件固定的,不能随便改。RC522的SDA是SPI片选信号,我用软件方式控制,接到PB12上。RST复位引脚接到PB0。IRQ中断引脚不接,程序里使用轮询方式读取数据,这样省一个GPIO。

RC522引脚正点原子Mini引脚说明
SDAPB12SPI片选,软件控制,低电平有效
SCKPB13SPI2时钟线
MOSIPB15SPI2主机发送数据线
MISOPB14SPI2主机接收数据线
IRQ不接中断引脚,轮询模式无需连接
RSTPB0复位引脚,低电平复位
GNDGND共地
VCC3.3V模块供电,注意不能接5V

2.3 供电、电平、线序的三个坑

三个坑每一个都可能让你白折腾两小时。

第一,供电电压。RC522模块标注是3.3V供电,但很多模块板上已经集成稳压电路,接5V也能工作。问题是正点原子Mini板上的IO电平是3.3V,如果模块用5V供电,SPI总线上的高电平就会变成5V,MCU引脚虽然一般有容忍能力,但长期使用不推荐。稳妥做法是统一用3.3V给模块供电。

第二,共地。很多人只接VCC、SCK、MOSI、MISO、SDA,不接GND,导致SPI通信电平没有参考点,时好时坏。这个问题排查起来非常隐蔽,串口偶尔能打印出卡号,偶尔又全零,十有八九就是没共地。

第三,SDA的片选极性。RC522的SDA低电平有效,但某些资料图里画的是高电平选中,照抄就完蛋。在初始化流程里必须确保片选在没有数据通信时保持高电平。

3. RC522的读卡原理与SPI的调参逻辑

3.1 MFRC522芯片在RFID链路里的位置

不用把射频规则背得滚瓜烂熟,你只需要理解这层关系:MFRC522负责和物理世界打交道,它内部有发送器、接收器、模拟前端、数字基带、寄存器组。MCU通过SPI往MFRC522的寄存器里写命令和参数,MFRC522再把命令调制到13.56MHz载波上发送给无源IC卡。

卡本身没有电池,它靠线圈感应取电,所以读卡距离近是物理特性决定的,一般不超过10cm。卡返回数据时通过负载调制方式改变天线端阻抗,MFRC522检测到这些微小变化后解码,把数据放到FIFO缓冲区里,MCU再读取出来。

一句话总结:MCU发的不是射频命令,而是寄存器操作;MFRC522才是真正和卡对话的人。

3.2 SPI四参数怎么定:模式、速率、位序、片选

SPI通信有四件事必须确认,缺一不可:

  • 时钟极性和相位(CPOL、CPHA),决定数据在时钟上升沿还是下降沿采样
  • 数据位宽,一般8位
  • 时钟速率,决定SPI总线频率
  • 片选信号,决定从机何时被激活

MFRC522默认支持SPI模式0(CPOL=0,CPHA=0),数据在时钟上升沿采样,下降沿改变。标准外设库初始化SPI2时,把SPI_CPOL_LowSPI_CPHA_1Edge填进去,这就是模式0。位序必须是MSB先行,即最高位先发。

速率这块要特别说明一下。STM32F103的SPI2挂在APB1总线上,频率36MHz。RC522最高支持10MHz的SPI时钟,理论上可以配到9MHz(分频4)。但我实测下来,用杜邦线连接时,超过4MHz很容易出现偶发读取错误,特别是线长超过10cm后。程序里我使用8分频,SPI时钟大概4.5MHz,实际操作稳定可靠。

3.3 寻卡到读写扇区的完整时序

完整读一段扇区数据的时序大概是这样的:

  1. PcdRequest寻卡:发送PICC_REQALL命令寻找视野内的卡片,卡返回ATQA类型码
  2. PcdAnticoll防冲突:如果多张卡同时在场,读出其中一张的4字节序列号(UID)
  3. PcdSelect选卡:用UID选中这张卡
  4. PcdAuthState验证密钥:使用A/B密钥验证目标扇区
  5. PcdRead/PcdWrite读写:对指定块进行数据读写

每步都要检查返回值是否为MI_OK,任何一个环节失败都不能继续往下走。这个顺序是MFRC522固件规定的,不能跳步,比如你不选卡直接读扇区,返回值必然是错误。

4. 程序框架与关键代码解读

4.1 工程结构:在正点原子库函数模板里加文件

正点原子Mini的例程模板默认带了sys.cdelay.cusart.c这些基础文件,我建议直接基于“库函数版本”的工程模板来做,不要从零写启动文件。

我的文件组织方式是:

  • 根目录下新建rc522文件夹,放入rc522.crc522.h
  • 头文件路径加入工程,确保能够#include "rc522.h"
  • usart.c里初始化好串口1,波特率115200,方便printf输出卡号

rc522.c里的函数分成两层:底层函数负责SPI读写寄存器和GPIO控制;上层命令函数负责按照协议向MFRC522发送命令并解析结果。

4.2 SPI2和GPIO初始化:引脚映射别抄错

void SPI2_Init(void) { GPIO_InitTypeDef GPIO_InitStructure; SPI_InitTypeDef SPI_InitStructure; RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE); RCC_APB1PeriphClockCmd(RCC_APB1Periph_SPI2, ENABLE); GPIO_InitStructure.GPIO_Pin = GPIO_Pin_13 | GPIO_Pin_15; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(GPIOB, &GPIO_InitStructure); GPIO_InitStructure.GPIO_Pin = GPIO_Pin_14; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; GPIO_Init(GPIOB, &GPIO_InitStructure); GPIO_SetBits(GPIOB, GPIO_Pin_12 | GPIO_Pin_13 | GPIO_Pin_14 | GPIO_Pin_15); SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex; SPI_InitStructure.SPI_Mode = SPI_Mode_Master; SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b; SPI_InitStructure.SPI_CPOL = SPI_CPOL_Low; SPI_InitStructure.SPI_CPHA = SPI_CPHA_1Edge; SPI_InitStructure.SPI_NSS = SPI_NSS_Soft; SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_8; SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB; SPI_Init(SPI2, &SPI_InitStructure); SPI_Cmd(SPI2, ENABLE); }

这段代码有几个容易踩的细节。

PB13和PB15配置为复用推挽输出,PB14配置为浮空输入。PB12是软件片选,必须配置为通用推挽输出,并且默认输出高电平。我见过有人把PB12也配成复用功能,结果SPI通信时片选被SPI硬件控制,时序完全乱套。

时钟使能上,SPI2是APB1外设,GPIOB是APB2外设,两者要分别使能。

4.3 RC522底层函数:复位、写寄存器、读寄存器

RC522的通信协议很简单:先拉低SDA,然后发送一个字节的地址加命令组合,再读写数据。

写寄存器函数:

void RC522_WriteReg(unsigned char addr, unsigned char val) { RC522_CS_LOW(); SPI2_ReadWriteByte(((addr << 1) & 0x7E)); SPI2_ReadWriteByte(val); RC522_CS_HIGH(); }

读寄存器函数:

unsigned char RC522_ReadReg(unsigned char addr) { unsigned char val; RC522_CS_LOW(); SPI2_ReadWriteByte((((addr << 1) & 0x7E) | 0x80)); val = SPI2_ReadWriteByte(0x00); RC522_CS_HIGH(); return val; }

注意地址移位和位7置位的细节。写命令时地址左移1位,最高位为0;读命令时最高位为1。这个约定看数据手册才能确定,很多人直接抄别人代码,没注意这一层。

复位函数PcdReset固定三步:先把RST引脚拉低至少10微秒,然后拉高;复位后延时10ms左右让芯片启动稳定;再调用软件复位命令写寄存器。千万别省略复位后的延时,否则可能出现第一次寻卡失败、第二次就正常的诡异现象。

4.4 上层命令:寻卡、防冲突、选卡、验证、读写

上层函数直接调RC522的寄存器,完成协议交互。

寻卡函数核心逻辑:

char PcdRequest(unsigned char req_code, unsigned char *pTagType) { unsigned char status; unsigned char TagType[2]; unsigned char buf[2]; RC522_WriteReg(RC522_REG_BIT_FRAMING, 0x07); buf[0] = req_code; status = RC522_Command(PCD_TRANSCEIVE, buf, 1, TagType, 2); if (status == MI_OK) { pTagType[0] = TagType[0]; pTagType[1] = TagType[1]; } return status; }

防冲突函数返回卡的4字节UID:

char PcdAnticoll(unsigned char *pSnr) { unsigned char status; unsigned char buf[5]; unsigned char i; RC522_WriteReg(RC522_REG_BIT_FRAMING, 0x00); buf[0] = PICC_ANTICOLL; buf[1] = 0x20; status = RC522_Command(PCD_TRANSCEIVE, buf, 2, buf, 5); if (status == MI_OK) { for (i = 0; i < 4; i++) { pSnr[i] = buf[i]; } } return status; }

这里有个经典坑:PcdAnticoll执行完后,bit framing寄存器里的值不是0,是0x80(因为有尾字节需要发送)。如果后续要做Mifare密钥验证,必须先把RC522_REG_BIT_FRAMING写回0x00,否则验证永远失败。正点原子老版例程里在PcdAuthState开头写了这行。

主循环里读卡号的逻辑:

while (1) { status = PcdRequest(PICC_REQALL, tagType); if (status == MI_OK) { status = PcdAnticoll(snr); if (status == MI_OK) { printf("Card UID: %02X %02X %02X %02X\r\n", snr[0], snr[1], snr[2], snr[3]); } delay_ms(500); } delay_ms(200); }

如果只想读卡号,到这一步就已经完成。需要读写扇区数据的,继续调PcdSelectPcdAuthState就行。

5. 把程序跑起来:实际烧录、调试和验证

5.1 首次编译烧录要改哪几个地方

拿到工程后我一般按下面的顺序检查:

  • 确认芯片型号选择的是STM32F103RC,正点原子Mini的HSE晶振是8MHz,不要刻意改
  • 宏定义里检查是否有STM32F10X_HD,RCT6属于高密度器件,漏了这个宏可能编译初始化代码选错
  • 确认串口1波特率,我习惯用115200,8位数据,1位停止位
  • 用ST-Link或者FlyMcu烧录,正点原子Mini板上预留了SWD接口,建议直接用ST-Link,烧录速度稳定

首次上电后如果串口不断打印乱码,先查波特率和串口接线是否交叉,不用先怀疑SPI。

5.2 串口打印卡号的实测记录

我实际跑起来的效果是这样:把IC卡贴近天线时,串口立刻输出一行Card UID: 0B 92 84 15,移开后程序继续循环寻卡,再次放卡又能打印。整个过程没有初始化失败的消息,没有乱码。

第一次调通这个程序的时候,我一度怀疑是不是假的读取,因为手机NFC功能读出来是同一个UID,对比完全一致。后来做按键开门实验时,我拿这张卡去刷宿舍的门禁,居然也能开,说明RC522读出来的卡号和真实门禁系统是一致的,协议层没有走偏。

5.3 顺带扩展:加一个OLED显示卡号

串口打印只能接电脑看,稍微扩展一下,把卡号显示到0.96寸OLED上,整个项目就完整多了。

OLED用I2C接口接PB6、PB7(正点原子Mini的I2C1复用),引入OLED驱动文件,把卡号格式化后显示:

char buf[20]; sprintf(buf, "UID: %02X%02X%02X%02X", snr[0], snr[1], snr[2], snr[3]); OLED_ShowString(0, 2, buf, 12);

加上OLED显示后,就可以脱离电脑独立演示,适合拿去给别人展示项目成果。这部分代码不复杂,但要注意OLED初始化功耗较低,和RC522一起用3.3V供电没问题。

6. 读卡不成功的排查顺序与避坑清单

6.1 按优先级排查:硬件→电源→时序→程序

遇到读不到卡,别急着改代码,按这个顺序排查:

现象可能原因解决办法
全无反应,模块不发热供电没接对用万用表量VCC和GND之间电压是否为3.3V
SDA拉低后电流异常供电电压过高检查是否误接5V,确认模块引脚顺序
单片机能跑但读卡失败SPI引脚映射错误重新核对PB13/14/15与RC522的SCK/MOSI/MISO对应关系
偶尔成功偶尔失败杜邦线接触不良换短杜邦线,或将模块直接插面包板
寻卡返回MI_NOTAGERR卡片类型不支持确认是ISO14443A的Mifare卡,别用身份证

我用表格整理出来后,基本上排查速度能快一倍。尤其是“模块没反应”这种,八成是供电没接好或者模块本身是坏的,没必要在代码层面深挖。

6.2 让我印象最深的三个问题

第一个问题是换了一张卡后读到的UID全是FF FF FF FF。排查发现那张卡是UID可重写卡,出厂UID区域全0xFF,需要先写入新的UID才能正常使用。这不是程序问题。

第二个问题是RC522读卡距离短到只有1cm,怎么调都不行。后来发现是天线区域粘了一层双面胶,胶贴边缘正好覆盖了天线线圈的一部分,导致射频能量被干扰。撕掉之后读卡距离立刻恢复到3cm以上。这个细节在小批量打样时很容易忽略。

第三个问题比较隐蔽。我用库函数版本例程时,加了delay_ms(500)后寻卡偶尔会卡死。查了汇编发现是SysTick中断优先级设置问题,RC522命令执行期间被打断,导致SPI时序超时。解决办法是把滴答定时器优先级调为最低,或者在寻卡期间关闭中断,任务完成后重新开启。

6.3 其他移植场景的提醒

如果把程序从正点原子Mini板移植到自己的自制板子上,有几个位置容易出错:

  • SPI外设编号:STM32F103C8T6也有SPI1和SPI2,但引脚位置不同,SPI1在PA5/PA6/PA7,移植时如果改了SPI编号,必须同步改GPIO配置
  • 片选引脚:RC522的SDA可以用任意GPIO控制,只要在宏定义里改对应的引脚号即可
  • 时钟频率:如果板子的外部晶振不是8MHz,HSE_VALUE宏要改,否则串口波特率会偏移
  • 天线匹配:自制PCB时天线的线圈参数直接决定读卡距离,这个没有捷径,只能按数据手册推荐值画板

身边有朋友在F103C8T6上直接复刻这套程序,改完SPI1后一切正常。核心逻辑没变,引脚映射改明白就行。

最后再分享一点个人经验:RC522程序调通确实不算难,但真正把它做成一个稳定的产品级功能,比想象中琐碎得多。建议在项目初期就把每次读卡的成功失败次数用串口打出来,挂机跑几个小时观察是否出现偶发失败,再配合一个简单的看门狗就能大幅度提高稳定性。如果后续要接多个RC522模块,可以考虑用单片机自带的SPI硬件NSS配合软件切换,不过目前这个方案对于大多数应用场景已经完全够用。

本文还有配套的精品资源,点击获取

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/1 7:33:48

5.2kW猛火燃气灶怎么选?嵌入式台式两用安装与验收指南

这次我们来看一个华帝渠道推荐的猛火燃气灶&#xff1a;天然燃气猛火聚能嵌入式台式两用铝炉头&#xff0c;核心卖点是 5.2kW 强效火力、铝制炉头、高效节能、安全稳定。很多人在厨房改造时最纠结的其实不是“好看不好看”&#xff0c;而是火够不够大、好不好装、能不能同时兼容…

作者头像 李华
网站建设 2026/9/1 7:32:51

大模型部署优化:从MiniMax M3与SambaNova集成看专用硬件推理实践

最近在关注大模型部署和推理优化的开发者们&#xff0c;一定注意到了MiniMax M3模型即将登陆SambaNova平台的消息。这不仅是两个顶尖技术产品的结合&#xff0c;更预示着企业级AI应用在性能、成本和易用性上可能迎来新的突破。对于正在评估或已经使用大模型进行应用开发、希望实…

作者头像 李华
网站建设 2026/9/1 7:32:45

联想校招C语言岗备考指南:从考点拆解到项目实战

“联想22校招-C”看到这个岗位的时候&#xff0c;估计不少人的第一反应是&#xff1a;总算有个不是“C/Java/Python都要会”的通用开发岗了。但等真去准备笔试面试&#xff0c;才发现这个“C”字背后的考察逻辑&#xff0c;跟大学里期末考试完全是两码事。这篇东西我就以过来人…

作者头像 李华
网站建设 2026/9/1 7:32:37

实战阶段项目:天气查询桌面应用

实战阶段项目:天气查询桌面应用 本篇是实战阶段的综合项目,我们将结合爬虫(API调用)、GUI编程、数据处理等知识,开发一个天气查询桌面应用。 一、项目需求 开发一个桌面天气查询应用,具备以下功能: 城市搜索:输入城市名查询天气 实时天气:显示温度、湿度、风力、天气…

作者头像 李华
网站建设 2026/9/1 7:31:55

STM32+HX711电子秤仿真设计:从原理到Proteus实现

简介&#xff1a;基于STM32单片机与HX711称重传感器的电子秤超重报警Proteus仿真资源包&#xff0c;面向嵌入式初学者、电子设计爱好者及课程设计开发者。压缩包内含282个文件&#xff0c;包括C/H语言源程序、Keil工程配置文件、Proteus仿真工程文件&#xff08;pdsprj&#xf…

作者头像 李华
网站建设 2026/9/1 7:30:01

从零搭建HP-Lite内网穿透服务:轻量级NAT穿透工具实战指南

在本地开发调试、远程访问NAS或部署Web服务时&#xff0c;你是否遇到过这样的困境&#xff1a;辛苦搭建的服务只能在局域网内访问&#xff0c;一旦离开公司或家庭网络&#xff0c;就无法连接。无论是给客户演示项目、远程管理设备&#xff0c;还是与团队成员共享开发中的API&am…

作者头像 李华