简介:基于RFID公交车刷卡系统的完整设计说明书,面向电子信息工程专业学生、课程设计及嵌入式系统入门开发者。方案围绕城市交通拥堵与通行效率问题,采用Mifare One非接触式IC卡与AT89S52单片机为核心,覆盖晶振电路、蜂鸣器提示音、LCD1602显示、DS1302时钟等硬件模块,并给出系统初始化、射频卡读写通信及软件总流程图,可帮助读者快速搭建刷卡系统原型。资源为1个doc文档,约649KB,文档结构包括引言、系统硬件设计、软件设计与总结,共3396字,附有电路原理图和功能框图说明。已有4294人学习下载,适合用作课程设计报告模板、毕业设计初期参考资料或公交一卡通项目的技术参考。文档还在设计思路中兼顾成本、可靠性与扩展性,所提方案亦可迁移至物流管理、医疗保健、身份识别等RFID应用场景,具有较强的参考价值。
1. 一套 51 单片机 + MFRC522 的刷卡方案,为什么到现在还能打
城市公交的刷卡系统,听起来是个大工程,但拆开看内核其实就是三件事:读卡、扣费、显示。这份基于 RFID 的公交车刷卡系统毕业设计,恰好把这三件事用最经典的硬件组合完整走了一遍——AT89S52 单片机做控制、MFRC522 做射频读写、Mifare One(S50)卡做支付介质,再配上 LCD1602 显示、DS1302 时钟和蜂鸣器提示。整套方案的硬件成本压到极低,软件流程覆盖了 ISO14443 协议从防冲突到三次认证的完整链路,是典型的低成本教学原型。读完这篇拆解,你能拿到硬件选型的完整理由、每个模块的接线参数、射频通信六步流程的代码实现,以及几个只有实际焊板子才会踩到的坑。这套方案到今天仍然是入门 RFID 应用的最佳参考模板。
2. 硬件选型与电路搭建:AT89S52、MFRC522 与四个辅助模块的逐项拆解
很多人在做 RFID 方案时,第一步就卡在选型上:是用 STM32 还是 Arduino,是用 RC522 还是 PN532,是用 S50 卡还是 CPU 卡?这份设计给出的答案非常明确:AT89S52 + MFRC522 + Mifare One 卡。这个组合不是性能最优解,但在「成本、成熟度、学习曲线、资料丰富度」四个维度上达到了最好的平衡。下面把每个硬件模块的选型理由和电路参数逐一拆开讲。
2.1 射频卡选型:为什么必须是 Mifare One 而不是条码或接触式 IC 卡
接触式 IC 卡的问题在于芯片外露,插拔次数多了容易磨损、氧化甚至折断,在公交车这种高频率、高尘、温差大的环境里可靠性很差。条码卡和磁卡则需要对准扫描,读卡速度慢,而且磁条易被磁场破坏。相比之下,Mifare One 卡片把芯片和线圈整体封装在 PVC 层内,表面无触点,不怕灰尘、不怕潮湿、不怕弯折,读写时只需要靠近天线区域即可完成数据交换,读卡距离通常在 3 到 5 厘米。
从协议层面看,Mifare One 遵循 ISO14443A 标准,工作在 13.56MHz 频段,卡片内部有 1K 字节的 EEPROM,按 16 个扇区划分,每个扇区有独立的密钥,支持三次互相认证后的加密流通信。这种一卡一密、分区存储的结构,天然适合公交场景:一个扇区存余额,一个扇区存交易记录,一个扇区存卡片编号。设计里选择了 S50 卡还有一层现实原因——它是市面上货源最充足、单价最低的射频卡,实验阶段批量买十几张也不会心疼。
2.2 主控选型:AT89S52 凭什么比 DSP、ARM 更合适
AT89S52 是 ATMEL 公司生产的 8 位单片机,40 引脚 DIP 封装,内部集成了 8K 字节 Flash 程序存储器和 256 字节 RAM,3 个 16 位定时器,1 个全双工串行口,兼容标准 MCS-51 指令集。这个配置放在今天看不算豪华,但在这个刷卡系统里完全够用:读卡流程的代码量不超过 4K,剩余空间还能放显示驱动和时钟驱动。
选它的核心逻辑是性价比。DSP 和 ARM 的运算能力确实强,但公交车刷卡系统本质上是一个低速 IO 控制和串行通信任务,射频通信的底层协议已经被 MFRC522 硬件消化掉了,主控只需要通过 SPI 接口读写寄存器,数据处理量极小。AT89S52 的 12MHz 主频处理这些任务绰绰有余,而它的采购价格只有 ARM 方案的零头。另一个隐性优势是 AT89S52 支持 ISP 在线编程,不用拔芯片往编程器上插,调试阶段改一次代码烧一次,几分钟就能完成一轮迭代。
提示:如果现在重新做这个项目,STC89C52RC 是 AT89S52 的直接替代品,指令兼容、下载更方便,价格还更低。
2.3 晶振电路:11.0592MHz 和 30pF 负载电容的搭配逻辑
系统采用 11.0592MHz 晶振,这个频率不是随手选的,它有明确的计算依据。单片机串口通信需要精确的波特率,11.0592MHz 能通过分频精确产生 9600bps、19200bps、57600bps 等常用波特率,误差几乎为零。如果换成 12MHz 晶振,串口波特率会产生约 2% 的误差,短帧通信勉强能用,但连续收发多字节数据时容易丢字节。
晶振两端各接一个 30pF 的负载电容到地,这两个电容的作用是和晶振内部的等效电容构成并联谐振回路,把振荡频率校准到标称值。容量选大了,振荡幅度下降、起振变慢;容量选小了,频率偏高、稳定性变差。30pF 是针对 11.0592MHz 晶振的常规取值,焊接时电容要尽量靠近晶振引脚,走线越短越好,否则寄生电容会改变实际谐振频率。
2.4 蜂鸣器提示音模块:三极管驱动的电平逻辑
读写操作完成后需要给乘客一个声音反馈,这个模块用的是无源蜂鸣器,通过 PNP 三极管 S8550 驱动。电路逻辑很直白:单片机的 P2.3 引脚接三极管基极,当 P2.3 输出高电平时三极管截止,蜂鸣器回路开路不发声;当 P2.3 输出低电平时三极管导通,蜂鸣器得电发声。
这里有个容易忽略的细节:单片机的 IO 口最大输出电流只有几十毫安,而蜂鸣器工作电流通常在 20 到 30 毫安以上,如果直接拿 IO 口驱动蜂鸣器,会造成电压跌落甚至烧毁引脚。加一级三极管放大,实际上是把电流放大任务从单片机 IO 口转移到了三极管,让单片机只承担逻辑控制功能。蜂鸣器的发声时长由软件控制,比如读卡成功时让 P2.3 拉低 100 毫秒后恢复高电平,就能产生一声短促的提示音。
2.5 LCD1602 显示模块:16 列乘 2 行的字符显示方案
显示模块选用 LCD1602,可以显示两行、每行 16 个字符,内部控制器是 HD44780,支持 4 位或 8 位两种数据总线模式。设计中使用的是 4 线模式,只占用单片机的 6 个引脚:RS、RW、E 和 D4 到 D7 四个数据线。4 线模式比 8 线模式少用 4 个 IO 口,代价是每个字符传输需要分两次发送(先高四位后低四位),速度慢一点但完全不影响显示刷新。
LCD1602 有一个在实际调试中经常被忽视的参数——第 3 引脚 Vo 的对比度调节。这个引脚需要接一个 10K 电位器到地,通过调节电压控制屏幕显示对比度。电位器调得太低,字符几乎看不见;调得太高,屏幕会出满屏的暗方块。第一次上电如果屏幕只有背光没有字符,优先检查这个引脚。
2.6 DS1302 时钟模块:三线接口的实时时钟电路
公交刷卡需要记录交易时间,系统选用 DS1302 实时时钟芯片。DS1302 是低功耗、带 RAM 的实时时钟电路,可以对秒、分、时、日、月、周、年进行计时,内置闰年补偿,工作电压范围 2.5V 到 5.5V,用 3.6V 纽扣电池作为后备电源时,主系统断电后时钟依然走时。它与单片机之间通过三线接口通信:SCLK(串行时钟)、I/O(数据线)、CE(片选使能),一次可以传送 1 到 8 个字节的时钟数据。
接线时三根线分别接单片机三个 IO 口,读取时间的流程是:拉低 CE 启动通信,在 SCLK 上升沿逐位写入读命令字节,再在 SCLK 上升沿逐位读出时钟数据。DS1302 有一个坑是它要求 SCLK 和 I/O 线上不能有毛刺,否则数据会错位,所以代码里在切换电平后要加极短延时,然后用示波器看波形确认时序。这个芯片的 VCC1 和 VCC2 双电源设计要特别注意——主电源接 VCC2,后备电池接 VCC1,接反了系统会一直从电池取电,几个月就没电了。
2.7 系统总体架构:四个功能模块怎么连成闭环
整个系统的数据流可以这样概括:MFRC522 通过天线与射频卡进行 13.56MHz 无线通信,读取卡片数据后通过 SPI 总线传给 AT89S52;单片机完成扣费逻辑处理,把结果送到 LCD1602 显示,同时触发蜂鸣器反馈,DS1302 提供时间戳记录交易时刻。控制模块是单片机加晶振电路,射频模块是 MFRC522 加天线匹配电路,通信模块是串口加 SPI 总线,显示模块是 LCD1602 加时钟。四者各司其职,硬件上几乎没有重叠依赖,方便独立调试和故障定位。
从 PCB 布局角度说,MFRC522 的天线部分和单片机数字电路之间要留出足够的间距,天线区域下方不要铺大面积的接地铜箔,否则会吸收射频能量导致读卡距离骤降。晶振电路则要尽量靠近单片机引脚,远离天线区域,防止 13.56MHz 射频信号干扰 11.0592MHz 主时钟。
3. 射频卡与读写器通信:ISO14443 的六步认证流程与数据块操作
硬件搭好只是第一步,真正决定刷卡系统能不能稳定工作的是软件通信流程。MFRC522 本质上是一个射频模拟前端加数字协议处理芯片,它把 ISO14443A 协议的大部分底层工作都完成了,但开发者仍然需要理解通信状态机的每一步,因为出错时的排查完全依赖对协议流程的掌握。这一章把从复位应答到数据块操作的全过程拆开讲,并给出可落地的 C 代码实现。
3.1 MFRC522 内部结构与 13.56MHz 载波链路
MFRC522 分为模拟部分和数字部分。模拟部分负责驱动天线、产生 13.56MHz 的载波能量、调制发送数据、检测和解调卡片返回的信号;数字部分则通过 SPI 接口与单片机通信,内部寄存器组控制着整个收发流程的状态配置。天线电路由 LC 低通滤波器和 LC 谐振回路组成,谐振频率要精确匹配到 13.56MHz,匹配电阻和电容的取值直接影响读卡距离。
MCU 通过 SPI 接口访问 MFRC522 内部的 64 个寄存器,每个寄存器 8 位,比如 CommandReg 用来发起命令,FIFODataReg 用来读写发送接收缓冲区,BitFramingReg 用来控制帧格式。通信过程本质上是往 FIFO 里填数据、执行 Transceive 命令、然后从 FIFO 读回数据的循环。理解了这个结构,读卡流程的任何一步出问题,都知道该去查哪个寄存器。
3.2 系统初始化:从 PLL 配置到串口和中断
系统上电后的第一步是初始化。单片机的初始化包括中断向量表配置、堆栈初始化、串口初始化和 IO 口方向设置;MFRC522 的初始化则包括软件复位、SPI 通信测试、发送器配置和定时器配置。MFRC522 需要一个 27.12MHz 的晶振作为内部时钟源,通过 PLL 倍频到系统需要的频率,初始化代码中要先使能 PLL、设置分频比和倍频因子、等待 PLL 锁定,然后才能使能发送器。
串口初始化是读卡器与上位机通信的关键,波特率设置为 9600bps 到 57600bps 都可以,8 位数据位、无校验、1 位停止位是最常用的配置。注意 MFRC522 和串口都是基于 IRQ 中断工作的,需要在中断选择寄存器中把两者的中断请求分配为 IRQ 模式,否则中断号冲突会导致读卡超时。初始化的核心代码如下:
void MFRC522_Init(void) { uint8_t byte; // 软件复位,往 CommandReg 写入软复位命令 WriteRawRC(CommandReg, 0x30); DelayMs(10); // 写测试寄存器验证 SPI 通信是否正常 WriteRawRC(TModeReg, 0x8D); // TModeReg=0x8D, 定时器自动重载 WriteRawRC(TPrescalerReg, 0x3E); // 预分频器,决定定时器时钟周期 WriteRawRC(TReloadRegH, 0x00); // 定时器重载值高字节 WriteRawRC(TReloadRegL, 0x1E); // 定时器重载值低字节 WriteRawRC(TxASKReg, 0x40); // 强制 100% ASK 调制 WriteRawRC(ConfigReg, 0x80); // 开启天线后自动触发 CRC 校验 // 打开天线,AntennaOn 寄存器对应位写 1 SetBitMask(TxControlReg, 0x03); // 读版本寄存器验证芯片通信正常 byte = ReadRawRC(VersionReg); if (byte == 0x92 || byte == 0x91) { // 版本号匹配,初始化完成 } else { // SPI 通信异常或芯片焊接问题,需要检查接线 } }代码逻辑说明:MCU 通过 ReadRawRC 和 WriteRawRC 两个封装函数访问 MFRC522 的寄存器。初始化分五步走——先软复位让芯片回到已知状态,然后配置定时器参数用于通信超时控制,接着设置发送调制方式和 CRC 计算方式,再开启天线发射能量,最后读版本号做通信自检。VersionReg 读回的 0x91 或 0x92 是 MFRC522 的固定版本标识,如果读到 0x00 或 0xFF 说明 SPI 总线的 MISO/MOSI 接线有误或者芯片焊接虚焊,这是硬件故障排查的第一个检查点。
参数说明:TModeReg 的 0x8D 是定时器自动重载模式的配置值,TPrescalerReg 的 0x3E 配合 TReloadReg 的 0x001E 把通信超时时间设置在合理范围内。TxASKReg 的 0x40 表示发送时使用 100% 的 ASK 调制深度,这是 Mifare One 卡片要求的调制方式。ConfigReg 的 0x80 是打开 CRC 自动校验,这样每帧数据的校验码由芯片硬件生成,不需要单片机软件参与。
3.3 射频卡通信六步流程:复位应答、防冲突、选卡与三次认证
Mifare One 卡的通信流程严格遵循 ISO14443A 协议的六个步骤,每一步都有固定的命令字和应答格式。实际调试中最常见的错误是跳步——比如没有做防冲突就直接选卡,或者没有认证就读数据块,这些都会导致卡片无响应或通信中断。下面按顺序详细拆解每一步。
第一步是复位应答。读写器发送 26 位请求命令 REQA 或唤醒命令 WAKE-UP,卡片进入 READY 状态并返回 4 字节的 ATQA 应答,用来标识卡片类型。这一步的作用是确认卡片的协议版本和通信波特率。第二步是防冲突检测。当有多张卡片同时进入天线场区时,卡片会同时应答造成数据碰撞,防冲突机制让每张卡片返回自己的 4 字节序列号,读写器选择其中一张继续通信,其余卡片回到空闲状态等待。第三步是选卡。读写器向被选中的卡片发送 Select 命令,卡片返回完整的序列号和容量代码。第四步是三次互相认证。这是安全核心——读写器和卡片各自用密钥计算出随机数并交换,经过三轮双向验证后才建立加密信道。这一步的密钥必须与卡片的扇区密钥匹配,否则认证失败。第五步是对数据块执行操作,包括读、写、加值、减值等。第六步是 Halt 命令将卡片置于暂停状态,释放天线资源给下一张卡。
uint8_t MFRC522_Request(uint8_t reqMode, uint8_t *tagType) { uint8_t status; uint16_t backBits; // 清空 FIFO,写入请求命令字 WriteRawRC(CommandReg, 0x20); // PCD_IDLE 空闲命令 WriteRawRC(FIFODataReg, reqMode); // 写入 REQA 或 WUPA 命令字 WriteRawRC(CommandReg, 0x04); // PCD_TRANSCEIVE 发送命令 if (reqMode == 0x26) { // REQA 的帧格式为 7 位短帧 WriteRawRC(BitFramingReg, 0x07); } else { // WUPA 需要完整字节帧 WriteRawRC(BitFramingReg, 0x00); } // 等待接收完成,轮询 ComIrqReg 寄存器 status = WaitForTransceive(&backBits); if (status == MI_OK) { *tagType = ReadRawRC(FIFODataReg); // 读回 ATQA 应答字节 return MI_OK; } return status; // 返回超时或通信错误码 }逻辑说明:Request 函数实现的是复位应答步骤。先把芯片置于空闲状态,清空 FIFO 缓冲区,然后把请求命令字写入 FIFO,启动发送命令。REQA 命令(0x26)是 7 位短帧,需要在 BitFramingReg 中设置发送位数;WAKE-UP 命令(0x52)是完整字节帧。发送完成后芯片自动切换为接收模式,单片机轮询中断寄存器等待卡片应答,从 FIFO 中读回 ATQA。WaitForTransceive 函数的超时时间由前面配置的定时器控制,一般为 20 毫秒,超时未收到应答就返回通信失败。
完成复位应答后,接下来是实现防冲突和选卡逻辑:
uint8_t MFRC522_Anticollision(uint8_t *serialNum) { uint8_t i, status, checkBit; uint8_t buf[2] = {0x93, 0x20}; // anticollision 命令字和帧头 uint16_t backBits; // 清 FIFO 并写入防冲突命令 WriteRawRC(CommandReg, 0x20); WriteRawRC(FIFODataReg, buf[0]); WriteRawRC(FIFODataReg, buf[1]); WriteRawRC(CommandReg, 0x04); // 这里设置发送 16 位,接收 40 位(4 字节序列号 + 1 字节校验) WriteRawRC(BitFramingReg, 0x00); status = WaitForTransceive(&backBits); if (status != MI_OK) return status; // 从 FIFO 中读取 4 字节序列号和 1 字节 BCC 校验值 for (i = 0; i < 4; i++) { serialNum[i] = ReadRawRC(FIFODataReg); } checkBit = ReadRawRC(FIFODataReg); // BCC 校验字节 // 校验:前四字节异或结果应等于 BCC if (checkBit != (serialNum[0] ^ serialNum[1] ^ serialNum[2] ^ serialNum[3])) { return MI_ERR; // 校验失败,返回错误 } return MI_OK; }说明:防冲突命令是 0x93 开头、0x20 作为帧头,表示要求所有在场卡片返回完整的 4 字节序列号。如果只有一张卡片,返回的就是它的序列号加 BCC 校验码。校验通过后,下一步就是选卡和认证。选卡命令是 0x93 后跟序列号和 BCC,卡片返回 1 字节的 SAK 应答字节。认证命令格式是 0x60(KeyA 认证)或 0x61(KeyB 认证)、扇区号、块地址和 6 字节密钥。认证成功后,对数据块的操作就有了一张加密通道的门票,后续的读、写、加值、减值命令都在这个加密信道中传输。
3.4 数据块操作与钱包功能:从读写到加值减值的完整命令
认证完成后就可以对数据块执行操作。Mifare One 卡的 1K 存储空间按 16 个扇区划分,每扇区 4 个块,每块 16 字节。扇区的最后一个块是 Sector Trailer,存放 KeyA、访问位和 KeyB,只有当前认证密钥匹配的扇区才能操作。第 0 扇区的第 0 块是厂商数据区,存放卡片序列号,只读不可改写。
数据块的操作命令包括:读块命令 0x30 加上块地址,卡片返回 16 字节数据加 2 字节 CRC;写块命令 0xA0 加上块地址,需要先发送 16 字节数据,等卡片确认后再次发送;加值命令 0xC1 和减值命令 0xC0 用于钱包块的四字节余额加减。公交扣费场景的核心是:先读余额块,判断余额减去票价是否大于零,然后执行减值命令,把新余额写回。
uint8_t MFRC522_ReadBlock(uint8_t blockAddr, uint8_t *data) { uint8_t i, status; uint8_t buf[2]; uint16_t backBits; buf[0] = 0x30; // READ 命令字 buf[1] = blockAddr; // 目标块地址,范围 0x00-0x3F // 写入 FIFO 并发送 WriteRawRC(CommandReg, 0x20); WriteRawRC(FIFODataReg, buf[0]); WriteRawRC(FIFODataReg, buf[1]); WriteRawRC(CommandReg, 0x04); status = WaitForTransceive(&backBits); if (status != MI_OK) return status; // 读回的 16 字节数据 + 2 字节 CRC,只保存前 16 字节 for (i = 0; i < 16; i++) { data[i] = ReadRawRC(FIFODataReg); } return MI_OK; }说明:读块命令发送的是 2 字节:命令字 0x30 加块地址。芯片自动处理 CRC 生成和校验,发送后等待应答,从 FIFO 中读出的前 16 字节就是块数据。注意读回的 FIFO 数据实际是 18 字节,最后两字节是 CRC,通常直接丢弃不保存。块地址可以取 0x00 到 0x3F,但每个扇区的最后一块是密钥块,直接读会返回认证失败。如果你的读卡距离小于 3 厘米,优先检查天线谐振和滤波电容,其次再怀疑发射功率寄存器配置。
4.2 读卡偶尔失败:卡片方向感应和载波调制深度
用户刷卡时经常第一次没反应、换个角度再刷一次就成功了。原因是天线场区存在感应盲区,尤其是卡片边缘进场时。解决思路有两个层面:硬件上把天线做大做对称,让场区更均匀;软件上在超时后自动重发 Request 命令,而不是立刻提示失败。另一个影响因素是调制深度——MFRC522 发送的载波是 100% ASK 调制,如果天线品质因数过高,调制边带会被滤掉一部分,导致卡片解调失败。这个问题的典型特征是距离稍远就完全读不到,贴近了又能读。解决方法是适当减小天线匹配电容值,把 Q 值压到 35 以下。如果怀疑调制问题,用示波器探头在天线输出端看到的波形应该是干净的 13.56MHz 正弦波叠加包络,如果波形畸变严重,优先调整匹配电容,而不是改软件。
4.3 DS1302 时间乱跳:电池接反和虚焊高发区
DS1302 时间每过一段时间就跳到 2000 年或变成乱码。最常见的原因是后备电池没接或接反,主电源掉电后时钟停止运行,恢复供电后读到的还是旧数据甚至随机数。另一个高频原因是 SCLK 和 I/O 线虚焊或过长导致信号毛刺。我排查时先用万用表确认 VCC1 和 VCC2 的电压——主电源 5V 接 VCC2,电池 3.6V 接 VCC1,如果电池在 3V 以下就需要更换。代码层面要注意 DS1302 的单字节读写时序里,CE 拉高后要先发送命令字节,命令字节的 bit0 必须是 1(固定标志位),否则芯片不响应。
4.4 MFRC522 版本号读回 0x00 或 0xFF:SPI 通信链路的排查顺序
这是一个让很多人卡住的问题。VersionReg 读回 0xFF 说明 SPI 总线的 MISO 线上没有数据返回,大概率是 MOSI 和 MISO 接反,或者芯片供电不正常。读回 0x00 则说明芯片有响应但数据全零,通常是 SPI 时钟极性和相位不匹配,MFRC522 要求 CPOL=0、CPHA=0,即时钟空闲为低电平、上升沿采样。排查步骤:
① 用万用表确认 MFRC522 的 3.3V 供电引脚电压在 3.3V 正负 5% 内,电流大于 50mA。② 断开 SPI 四根线,用杜邦线直连单片机与模块,排除飞线断线。③ 示波器同时测量 SCLK 和 MOSI,确认时钟频率低于 10MHz、数据在上升沿稳定。④ 逐个读取版本号、寄存器,对比数据手册中的默认值,确认 SPI 模式正确。
这四条坑排完,系统基本就能稳定工作了。最后一步是全局检查电源——MFRC522 在发射瞬间电流会跳变到 80mA 以上,如果和单片机共用一根 USB 供电线,压降会导致单片机复位,这也是一个典型的偶发性故障来源。
5. 验证与进阶:串口日志、天线距离与移植到其它单片机的三个技巧
系统跑通之后,还有三件事值得做:验证读卡距离是否达到设计值、通过串口日志定位通信断点、把代码结构调整成可移植的模块。这三件事决定了这套方案是停留在实验室原型还是能真正用起来。
读卡距离的验证方法很直接:把卡片放在天线正上方,以 1 厘米为单位逐渐抬高,记录每个高度下连续读卡 10 次的成功率。MFRC522 的标准读卡距离是 3 到 5 厘米,低于 3 厘米说明天线匹配有问题,高于 5 厘米则要小心相邻卡片的误读。提升距离的优先级是:天线尺寸 > 匹配电容 > 发射功率寄存器。天线面积加大 20%,距离通常能提升 1 到 2 厘米;匹配电容从 47pF 换成 33pF 也能有效果,但这个调整需要每次焊完就实测,比较折腾。
串口日志是整个系统调试的「后悔药」。我在主控程序里加了一层 DEBUG 宏控制,通过串口把每次读卡的状态打印出来:初始化版本号、Request 返回码、防冲突序列号、认证结果、扣费前后的余额值。这样一旦出现异常,不用接仿真器就能快速定位是硬件还是软件问题,也更方便观察通信超时的具体环节。某公司内部技术分享里有个说法:看起来「智能」的刷卡系统,背后都是一行行串口日志堆出来的定位能力。
代码的可移植性决定这套方案能不能复用到其他场景。我在写的时候就把硬件访问层和应用层分开了——SPI 读写、GPIO 控制的底层函数放在单独的文件里,读卡流程和扣费逻辑放在业务层。底层函数只暴露 ReadRawRC、WriteRawRC 和几个 Pin 操作接口,换主控芯片时只需要重写这几个函数,上层逻辑一行不用动。比如把 AT89S52 换成 STM32F103 时,只需要把 SPI 底层换成 STM32 的硬件 SPI 驱动,MFRC522_Init、Request、Anticollision、ReadBlock 这些函数不需要改动。如果追求极致简洁,可以用软件模拟 SPI——把 SCK、MOSI、MISO 定义为普通 GPIO,用延时翻转模拟时序,这样就完全摆脱了硬件 SPI 外设差异,任何主控都能跑。
从那以后我每次做 RFID 方案的硬件测试,都会强制走一遍「测版本号、量天线波形、看串口日志」三部曲,先确认链路通,再优化参数,最后才写业务逻辑。这个习惯帮我挡掉了不少玄学问题,也希望帮到你。如果这套基于 51 单片机与 MFRC522 的刷卡方案对你刚好够用,下载这份设计文档作为参考底稿,省下的选型和踩坑时间远不止文档本身的篇幅。
本文还有配套的精品资源,点击获取