资讯动态

基于AT89S52与MFRC522的RFID公交刷卡系统设计

发布时间:2026/10/28 4:26:33 来源:尧图企业网站定制
简介围绕RFID公交车刷卡系统展开的电子系统设计说明书面向电子信息工程、嵌入式与交通信息化方向的课程设计学习者重点回应公交一卡通场景下的刷卡识别、显示与时钟管理需求。资源包共1个doc文件约649KB正文以设计说明、系统框图和电路流程描述为主便于按章节查阅方案选型与实现思路。文档从研究背景入手依次讨论Mifare One射频卡与AT89S52单片机的选型依据并覆盖晶振电路、提示音模块、LCD1602显示、DS1302时钟模块及系统总体方案软件部分给出初始化、射频卡与读写器通信和总流程图结构接近完整课程设计报告。已有4297人学习适合需要参考硬件组成、模块划分与软件流程的读者快速建立设计框架也可用于比对同类一卡通方案的取舍与文档组织。1. 早高峰那三秒钟这套 RFID 公交车刷卡系统要解决什么早高峰车门一开队伍从投币箱前排到后门如果每人刷卡多花两秒一趟车就少拉十几个人。这套基于 RFID 的公交车刷卡系统设计要解决的就是这三秒钟卡片贴近读头十厘米以内读卡、验卡、扣费、响一声、屏上跳出余额整个流程压在 300 ms 以内完成。方案用 AT89S52 单片机做主控配 MFRC522 射频读写芯片和 Mifare OneS50非接触卡带 LCD1602 显示、DS1302 走时和蜂鸣器提示是典型的电子系统设计题目——器件便宜、资料齐全、焊出来能真刷。它适合要交一份完整硬件加软件方案的电子信息类学生也适合想拿一套低成本读卡模块改造成门禁、考勤、食堂消费终端的从业者。2. 总体方案与器件选型四个模块如何分工完成一次刷卡一次刷卡看着简单拆开是四条并行又互相牵制的链路射频链路负责把 13.56 MHz 的能量送出去并收回卡片调制回来的数据控制链路负责跑协议状态机人机链路负责发声和显示时间链路负责给每笔交易打上时间戳。模块划分如果一开始没定清楚后面调试就会陷入「到底是卡的问题、天线的问题还是程序的问题」的黑匣子状态。我一般先把职责边界画成一张表固定下来再逐个模块选器件谁负责什么、接口是什么电平、时序由谁主导全部写死。2.1 系统功能结构框图与四个模块的职责边界按功能划分整套系统分为控制模块、发送接收数据模块、串行通信模块、显示模块。控制模块由单片机和 11.0592 MHz 晶振构成是整个系统的主时钟源和决策中心发送接收数据模块由 MFRC522、13.56 MHz 晶振、天线及匹配网络组成模拟部分驱动天线产生载波并调制发送、检测解调卡片回传信号数字部分通过串行接口与单片机交换命令和数据串行通信模块负责读卡器与上位机之间的数据回传把卡号、扣费金额、时间打包上传显示模块包括 LCD1602、DS1302 和蜂鸣器负责余额、票价、时间的呈现和刷卡成功提示。模块核心器件职责与主控接口控制模块AT89S52、11.0592 MHz 晶振、复位电路协议状态机、扣费逻辑、任务调度系统主体收发数据模块MFRC522、13.56 MHz 晶振、PCB 环形天线载波发射、卡片寻呼、防冲突、加解密通信软件模拟 SPI4 根 I/O串行通信模块AT89S52 内置 UART交易记录上传、参数下发RXD/TXD9600 bps显示模块LCD1602、DS1302、有源蜂鸣器余额与时间显示、刷卡提示音8 位并口 3 线时钟 1 根 I/O这张表的价值在于后续排故时能快速二分。卡刷不上先看是收发模块没返回卡号还是控制模块收到卡号却没走完认证还是显示模块刷新卡死把主循环堵住了。职责分清楚问题就落在一个格子里不用满板子乱猜。2.2 主控选型为什么是 AT89S52 而不是 ARM这个题目最容易出现的争论是「都什么年代了还用 51」。从工程角度讲选型不是比谁先进是比谁在这个需求下性价比最高。刷卡终端的核心负载是驱动一个 SPI 外设、跑一个几百字节的状态机、刷一块 16×2 字符屏、走一个 UART。这些活儿 AT89S52 完全扛得住而且它的开发链条成熟到什么程度——编译器、下载器、例程、调试方法全都是现成的出问题有大量前人踩过的坑可查。AT89S52 的关键参数40 引脚封装32 个双向 I/O 口片内 8 KB 可重复编程 Flash不同批次手册标注略有出入接线前按手头器件的数据手册核对一遍256 字节 RAM3 个 16 位可编程定时计数器1 个全双工串行口兼容标准 MCS-51 指令系统支持在线编程ISP可反复擦写开发成本低。相比之下 DSP 和 ARM 方案在主频、运算能力、片上外设上确实强但对这个项目来说属于过量配置价格高出一截开发环境上手周期长而且大部分算力闲置。真正需要算清楚的是 RAM。256 字节要装下LCD 显示缓冲区可选也可以直接写指令不缓存、串口收发缓冲、卡片 UID4 字节或 7 字节、密钥6 字节、MFRC522 的 FIFO 数据缓冲读块操作一次 16 字节。这些加起来不到 80 字节剩下还有余量。如果后面想加「最近 10 笔交易流水」这种功能就得压缩缓冲或者外挂 24C02这是选型时应该提前想到的扩展点。提示选 51 不代表可以省掉看门狗。刷卡机在车上是长期上电设备程序跑飞后必须能自己复位AT89S52 内置看门狗定时器初始化和喂狗要写进主循环。2.3 射频卡与读写芯片的搭配Mifare One 加 MFRC522卡片这一侧的选择理由很直接。市面上常见的有条码、磁卡、接触式 IC 卡、非接触式 IC 卡。条码和磁卡在超市、银行用得多成本低但易复制、易磨损接触式 IC 卡芯片外露插拔次数一多就接触不良早年公共电话亭那种故障率就是教训非接触式 IC 卡把芯片和线圈封装在卡片内部不怕弯折、不怕灰尘油污刷卡不用对准可靠性明显更高。最终选用 Mifare One 卡业内常称 S50、M1 卡。它的存储结构是 1 KB EEPROM分成 16 个扇区每个扇区 4 个块每块 16 字节。第 0 扇区第 0 块是厂商固化区存 uid 和厂商信息只读每个扇区的第 3 块是尾块存密钥 A6 字节、存取控制位4 字节、密钥 B6 字节其余块是数据块可以配置成普通读写块也可以配置成值块钱包。值块这个特性是公交刷卡场景的关键加减值由卡片硬件保证原子性比在单片机里做加减运算再写块安全得多。读写端选 MFRC522。它工作在 13.56 MHz支持 ISO14443A 协议正好对得上 Mifare One内部集成发送调制、接收解调、CRC 校验、加解密单片机只需要发命令和读结果不用自己啃射频时序支持 SPI、UART、I2C 三种接口供电 3.3 V。要注意 MFRC522 是 3.3 V 器件而 AT89S52 的 I/O 是 5 V直连会烧芯片这不是可选项而是必须处理的硬约束后面会专门讲接法。3. 硬件电路设计从最小系统到天线匹配硬件这一层最容易出现「原理图全对、焊出来不工作」的情况。原因往往不在逻辑而在模拟部分晶振负载电容选偏了频率就飘天线匹配没调好读距就从十厘米掉到贴着才灵电源纹波一大读卡瞬间就复位。所以这一章不只给连接方式还把每个电路的参数为什么这么取值讲清楚读者照着改的时候知道动哪个旋钮。3.1 最小系统与 11.0592 MHz 晶振的负载电容晶振接在单片机的 XTAL1、XTAL2 两个引脚之间两端各接一只无极性电容到地容量取 30 pF。这两只电容叫负载电容作用是配合晶体本身的标称负载电容让振荡电路工作在标称频率上同时影响起振速度和输出幅度。取值不是随便填的晶振规格书会标一个 CL 值常见 12 pF、20 pF实际用电容约等于 2×(CL − 杂散电容)杂散电容一般估 35 pF。取 30 pF 是这套电路里稳妥的常见值如果发现起振慢或者频率偏移大可以把这两只电容换成 22 pF 或 33 pF 对比。为什么偏偏选 11.0592 MHz 而不是更整的 12 MHz关键在串口。51 的串口波特率由定时器溢出率分频得到11.0592 MHz 这个数能被 9600、19200、57600 这些标准波特率整除误差为 0换成 12 MHz9600 的误差就到了 8% 以上通信会出现偶发乱码。做长期运行的设备这种玄学故障最难查源头就在晶振频率上。复位电路用 10 μF 电解电容配 10 kΩ 电阻的经典上电复位EA 引脚接高电平表示从片内 Flash 取指令。下面这段代码把 11.0592 MHz 换算成 1 ms 定时基准是后面所有超时判断和去抖延时的基础。#include reg52.h #define FOSC 11059200UL /* 系统晶振 11.0592 MHz */ #define T1MS (65536 - FOSC/12/1000) /* 方式1下 1ms 的初值65536-92164615 */ /* 定时器0方式116位定时1ms 中断一次作为系统软时钟 */ void Timer0_Init(void) { TMOD 0xF0; /* 保留定时器1的配置清空定时器0的4位 */ TMOD | 0x01; /* 定时器0 工作在方式116位定时器 */ TH0 T1MS 8; /* 装入初值高字节 0xFC */ TL0 T1MS 0xFF;/* 装入初值低字节 0x67 */ ET0 1; /* 允许定时器0中断 */ EA 1; /* 开总中断 */ TR0 1; /* 启动定时器0 */ }这里的 921 是 11.0592 MHz 除以 12 再除以 1000 得到的每毫秒机器周期数取整后每毫秒有约 0.1% 的误差对刷卡超时判断、LCD 延时、蜂鸣器发声时长完全够用。如果要做精确到秒的计时不能靠这个软时钟累积得交给 DS1302。这也是为什么系统里既要定时器又要时钟芯片——一个负责毫秒级的流程节奏一个负责年月日时分秒。3.2 蜂鸣器驱动电路为什么要加三极管提示音用有源蜂鸣器读写操作完成时响一声。蜂鸣器不能直接挂在 I/O 口上原因很实在单片机每个 I/O 的灌电流能力有限而蜂鸣器工作电流通常在 2030 mA 以上直驱轻则声音发闷重则长期过流把口线拉坏。所以在 P2.3 和蜂鸣器之间加一只 NPN 三极管做开关基极串 1 kΩ 限流电阻蜂鸣器回路里再串 100 Ω 限流。工作逻辑是反相的P2.3 输出高电平时三极管截止蜂鸣器回路断开不响P2.3 输出低电平时三极管导通回路闭合蜂鸣器发声。写代码的时候要记住这个极性别写成「置高发声」否则一上电就一直叫。sbit BEEP P2^3; /* 蜂鸣器控制脚低电平有效 */ /* 响 ms 毫秒调用时主循环会被阻塞所以时长控制在 50ms 内 */ void Beep(unsigned int ms) { BEEP 0; /* 三极管导通蜂鸣器发声 */ while (ms--) { Delay1ms(); /* 复用 1ms 定时基准的软件延时 */ } BEEP 1; /* 关断避免长期通电发热 */ }参数上唯一的讲究是发声时长。刷卡成功的「嘀」一般给 50 ms失败给两声短促的各 30 ms 中间隔 60 ms。时长太长会让乘客以为机器卡住了太短在嘈杂车厢里听不见。3.3 LCD1602 与 DS1302 的接口和走线LCD1602 是 16×2 的字符型液晶每行 16 个字符每个字符位由 5×7 点阵组成控制器基本都基于 HD44780 兼容芯片所以一套驱动代码可以通吃市面上大多数字符屏。接口上 RS、RW、E 三根控制线加 8 根数据线共 11 根 I/O如果 I/O 紧张可以改成 4 位模式数据线只用高 4 位代价是每次要分两次送。这套系统 I/O 够用走 8 位模式刷新更快。对比度调节端 VL 接 10 kΩ 电位器到地焊完先调这个否则最常见的问题是「屏亮了但一个字看不见」。DS1302 是低功耗带 RAM 的实时时钟芯片能对年、月、日、周、时、分、秒计时带闰年补偿工作电压 2.55.5 V通过三线CE、SCLK、I/O与单片机同步通信支持突发模式一次传多个字节。它外接 32.768 kHz 晶振和一颗纽扣电池主电源掉电后继续走时。走线上有一条硬要求32.768 kHz 晶振尽量靠近芯片引脚两根引脚走线短而等长下面不要走其他信号线否则走时会出现「一天慢几秒」的偏差。通常的做法是在晶振两端各接一只 6 pF 左右的电容到地具体看晶振规格书。3.4 天线与匹配网络13.56 MHz 载波这一段MFRC522 的能量载波由 13.56 MHz 晶振提供通过内部电路驱动 TX1、TX2 输出经 LC 低通滤波和 LC 谐振网络送到天线。天线本体是 PCB 上的一圈或几圈铜箔环形走线属于整个设计里唯一需要「调」而不是「算」的部分。匹配网络的典型结构是TX1/TX2 各串一只电阻常见 110 Ω用来抑制谐波和限流再串一只电容天线两端并一只可调电容构成谐振回路让整个回路谐振在 13.56 MHz。调的方法不复杂给系统上电用示波器探头低电容探头或者自制一个小环探头靠近天线看天线两端的电压幅度旋动可调电容找到幅度最大的那个点就是谐振点。这时候读卡距离最远。读距还跟天线面积、圈数、Q 值有关。板载天线常见做到 510 cm想更远就得加大天线面积但 Q 值太高会导致带宽变窄、对卡片频率偏差更敏感反而在批量卡上表现不稳。课程设计这个量级5 cm 左右稳定读卡就够验收了。环节器件/参数作用调试要点载波源13.56 MHz 晶振提供射频基准负载电容按晶振规格取别照抄 30 pF滤波LC 低通抑制高次谐波电感和电容按参考设计取值匹配串联电阻 可调电容阻抗匹配、谐振点调节示波器看天线幅度找最大值天线PCB 环形铜箔发射能量、接收负载调制天线正下方禁止铺铜和走线注意天线区域下方的地平面必须挖空。很多人图省事让整板铺地结果天线能量全被地平面吸走读距只剩一两厘米还以为是芯片坏了。4. 软件设计从初始化到扣费一条完整的刷卡时序软件部分的价值不在于写了多少行而在于把卡片操作拆成确定性状态机。Mifare One 的访问流程是强顺序的寻卡、防冲突、选卡、认证、读写、中止任何一步跳过或者顺序颠倒后面都拿不到正确结果。这一章按调用顺序给代码骨架同时说明每一步失败时返回什么、上层该怎么处理读者照着改就能跑起来。4.1 系统初始化与串口、中断配置初始化要按依赖顺序来先配时钟和定时器再配串口再配外部芯片最后开中断。串口是读卡器与上位机的通信端口使用前要设波特率、收发字符格式、清 FIFO串口和 MFRC522 都基于中断工作还要对中断优先级做分配避免射频通信被打断。/* 串口初始化9600 bps8 位数据1 位停止无校验11.0592MHz 下误差为 0 */ void Uart_Init(void) { SCON 0x50; /* 方式18位UART允许接收 */ TMOD 0x0F; TMOD | 0x20; /* 定时器1 方式28位自动重装做波特率发生器 */ TH1 0xFD; /* 9600bps 初值256 - 11059200/(12*32*9600) 253 */ TL1 0xFD; TR1 1; ES 1; /* 开串口中断 */ } /* 中断优先级射频通信 串口 定时器保证寻卡时序不被串口打断 */ void Int_Priority_Init(void) { IP 0x01; /* 定时器0中断设为高优先级用于超时判断 */ /* 串口与射频操作放在主循环中顺序执行避免中断嵌套导致 SPI 时序错乱 */ }这里有个设计取舍值得说明软件模拟 SPI 的时序对时间敏感如果把寻卡流程放在中断里被串口中断打断几十微秒就可能错过卡片的响应窗口。所以通常的做法是中断只做标志位和缓冲区搬运真正的卡片操作全部放在主循环里顺序执行。中断优先级配置的目的不是让流程更快而是让超时基准不被拖慢。4.2 寻卡、防冲突、选卡与三次认证的状态机这一段是整套软件的核心。Mifare One 的通讯协议和波特率是固定的卡片进入读写器操作范围后读写器按协议发起呼叫判断是不是 M1 卡多张卡同时在范围内时防冲突机制从中选一张操作未被选中的回到空闲状态等待下一次选卡这个过程会返回被选卡的序列号随后按序列号选中该卡并返回容量代码最后选定要访问的扇区用密钥对该扇区做三次相互认证认证通过后才能建立加密通道通信。换扇区就要重新认证这是很多人漏掉的一点。/* MFRC522 软件模拟 SPI 底层主机先发地址字节再连发数据 */ unsigned char RC522_ReadReg(unsigned char addr) { unsigned char dat; RC522_NSS 0; /* 片选拉低 */ RC522_WriteByte((addr 1 0x7E) | 0x80); /* 读命令最高位置1 */ dat RC522_WriteByte(0x00); /* 读回一个字节 */ RC522_NSS 1; return dat; } /* 完整寻卡流程返回 0 表示成功拿到 4 字节 UID */ unsigned char Pcd_ReadCard(unsigned char *uid) { unsigned char status; status Pcd_Request(PICC_REQIDL, CardType); /* 寻天线区内未进入休眠的卡 */ if (status ! MI_OK) return 1; /* 无卡或卡类型不符 */ status Pcd_Anticoll(uid); /* 防冲突返回序列号 */ if (status ! MI_OK) return 2; /* 多卡冲突未解决 */ status Pcd_Select(uid); /* 选卡返回容量代码 */ if (status ! MI_OK) return 3; /* 选卡失败卡可能已离开 */ return 0; } /* 三次互相认证keyType 0x60 用密钥A0x61 用密钥B */ unsigned char Pcd_Auth(unsigned char keyType, unsigned char block, unsigned char *key, unsigned char *uid) { return Pcd_AuthState(keyType, block, key, uid); /* 返回 MI_OK 才可读写 */ }三处失败返回值不同好处是排故时串口一打印就知道卡在哪一步返回 1 是根本没寻到卡先怀疑天线和卡片返回 2 是场上不止一张卡返回 3 是选卡过程中卡片被拿走了。这个错误码设计比统一返回 0/1 有用得多答辩演示时也能主动解释异常处理。4.3 值块加值与减值扣费事务怎么保证不掉钱公交场景的钱包必须用 Mifare 的值块不能当普通数据块读写。值块的 16 个字节有固定格式前 4 字节是数值小端接着 4 字节是数值按位取反再 4 字节重复数值最后 4 字节重复取反并附块地址校验。这个冗余结构的目的是让卡片自己校验数据的完整性被篡改或写坏时能识别出来。钱包操作有一套专用命令初始化钱包把指定块定义成钱包格式加值对钱包块加钱减值减钱存储把块内容存到数据寄存器传输把数据寄存器内容写回块中止让卡进入暂停状态。扣费的正确序列是认证 → 读余额 → 判断余额是否够票价 → 减值 → 传输。/* 一次完整扣费成功返回 0余额不足返回 1通信失败返回 2 */ unsigned char Wallet_Pay(unsigned char block, unsigned char *key, unsigned char *uid, unsigned short fare, unsigned short *balance) { unsigned short old; if (Pcd_Auth(0x60, block, key, uid) ! MI_OK) return 2; /* 认证失败 */ if (Pcd_ReadValue(block, old) ! MI_OK) return 2; /* 读当前余额 */ if (old fare) { /* 余额不足 */ *balance old; return 1; /* 不打孔、不扣费 */ } /* 关键减值只写入芯片内部数据寄存器掉电也不会改变卡片余额 */ if (Pcd_Decrement(block, fare) ! MI_OK) return 2; /* 传输才是真正落盘这一步之前的任何掉电都等于没扣钱 */ if (Pcd_Transfer(block) ! MI_OK) return 2; *balance old - fare; return 0; }这个「减值 传输」两步是整套扣费逻辑里最该讲清楚的地方。减值命令只是把计算结果放进读写器与卡片之间的缓冲真正写进 EEPROM 的是传输命令。如果中间掉电、卡片被拿走、通信中断余额保持原样不会出现「扣了钱没记账」或者「没扣钱却掉了余额」。反过来说如果图省事直接读块、在单片机里做减法、再写块一旦在写块的过程中断整块数据可能变成非法值卡片就废了。提示写块之前务必确认该块已被配置成值块。有些卡出厂时全扇区都是普通数据块直接对它发减值命令会返回错误这类卡要先按值块格式初始化。4.4 主流程与显示刷新节奏主循环按固定节奏轮转寻卡 → 认证 → 扣费 → 显示 → 鸣响 → 防重复刷卡 → 读时间。防重复刷卡这一步不做会很尴尬乘客把卡放在读头上没拿走一秒钟扣十次。通常的做法是缓存上一次成功的 UID同一张卡在 2 秒内不再触发扣费2 秒后再放上去才允许第二次交易。显示刷新要单独说明。LCD1602 每次写指令后需要延时等待如果把这个延时放在中断里会打乱 DS1302 的三线时序如果放在主循环里裸等又会拖慢寻卡。稳妥做法是把「余额变化」和「时间秒变化」作为刷新触发条件而不是每圈都刷时间显示只刷新秒位余额只在扣费后整行刷新。void main(void) { unsigned char uid[4], status; unsigned short balance; Mcu_Init(); /* 单片机、定时器、串口、中断初始化 */ RC522_Init(); /* 复位 MFRC522开启天线设置接收增益 */ LCD1602_Init(); /* 液晶初始化清屏设置显示模式 */ DS1302_Init(); /* 时钟芯片初始化首次上电写默认时间 */ LCD_ShowString(0, 0, Bus Card Ready ); while (1) { status Pcd_ReadCard(uid); /* 寻卡 防冲突 选卡 */ if (status 0 !Is_Same_Card_Within(uid, 2000)) { status Wallet_Pay(0x04, KEY_A, uid, FARE, balance); if (status 0) { /* 扣费成功 */ Beep(50); LCD_ShowBalance(balance); Uart_Report(uid, FARE, balance, DS1302_GetTime()); } else if (status 1) { /* 余额不足 */ Beep(30); Delay1ms(60); Beep(30); LCD_ShowString(0, 1, Low Balance ); } else { /* 通信异常 */ Beep(30); } Remember_Card(uid); /* 记录本次卡号用于防重复 */ } Refresh_Clock(); /* 秒变化时才刷新时间显示 */ } }主循环里没有任何长延时所有等待都由定时器超时兜底。这个结构的好处是即使某张卡认证失败程序也不会卡死下一轮照样能响应新卡。5. 联调避坑五个最容易翻车的地方硬件焊完、程序烧进去第一遍不通是常态。这一章列的是实际调试中出现频率最高、又最容易误判的几个问题每条按现象、原因、解决三步写。按这个顺序排查能省掉大量「换了三块板子还是不行」的时间。5.1 硬件侧读不到卡与电源跌落现象一卡贴着天线也读不到MFRC522 返回错误或全 0。原因通常是天线没谐振在 13.56 MHz。匹配电容取值不对、可调电容没调、或者天线正下方铺了地平面能量被吸走。解决办法是先断开天线用示波器看 TX1/TX2 有没有 13.56 MHz 输出有输出再接天线用环探头看天线两端幅度旋动匹配电容找最大点确认天线区域下方所有层的地和走线都挖空。另一个常被忽略的点是 13.56 MHz 晶振的负载电容直接照抄 30 pF 可能偏得厉害按晶振规格书取值。现象二换了新板子MFRC522 上电就发热或者通信全是 0xFF。原因是电平不匹配。MFRC522 是 3.3 V 器件AT89S52 的 I/O 输出接近 5 V把 5 V 直接加到 MFRC522 的输入脚上轻则通信异常重则击穿。解决办法是给 MFRC522 单独用 3.3 V 稳压如 AMS1117-3.3单片机送过去的信号线串 1 kΩ 电阻做限流分压或者用专用电平转换芯片。这是血泪经验一块芯片几块钱烧一次就是半天工期。现象三平时显示正常一刷卡 LCD 就花屏或者单片机复位。原因是读卡瞬间天线电流突变3.3 V 和 5 V 电源同时跌落。解决是在 MFRC522 电源脚旁边就近放 0.1 μF 陶瓷电容加 100 μF 电解电容天线供电和数字部分走线分开最后单点汇到电源入口如果用的是 USB 供电换一个带载能力更强的适配器。5.2 软件侧多卡冲突与扣费异常现象四两张卡一起放上去程序卡死或者读到一串乱码 UID。原因是没走完整的防冲突流程直接发了选卡命令。Mifare 的规则是必须先 Request 寻卡再 Anticollision 拿序列号再 Select 选中缺一步就会在多卡环境下拿到冲突数据。解决是严格按状态机顺序执行并且在 Anticollision 返回冲突标志时重试重试三次仍冲突就放弃本次操作提示用户只放一张卡。现象五扣了钱但余额没变或者余额变成了一个巨大的数。原因基本是把值块当普通数据块读写或者在减值之后没有执行传输也可能把普通数据块误当成钱包块。解决办法是确认目标块已初始化为值块严格使用「减值 → 传输」两步写之前先读一次余额做范围校验发现余额大于预设上限比如 1000 元就拒绝交易并报错。另外B 密钥留空或使用出厂默认密钥是很常见的漏洞课程设计也该把扇区密钥改成自定义值虽然挡不住专业攻击但至少不会被人拿手机一贴就改。现象六DS1302 走时一天慢好几秒或者断电重启后时间归零。前者的原因是 32.768 kHz 晶振走线太长、负载电容不匹配或者晶振本身精度差后者多半是备用电池没装、电池座虚焊或者 CE 使能时序太快导致写不进。解决是把晶振紧贴芯片、两根线尽量短、下面不走信号负载电容按规格书取 6 pF 左右上电后读一次时间判断是否合理年份在 20002099 之间不合理就重新写入默认时间。注意调试期建议把每次刷卡结果通过串口打印出来包含 UID、认证结果、扣费前后余额、时间。没有这行日志以上六个现象里至少四个只能靠猜。6. 验收与答辩拿什么证明这套刷卡机真的能跑课程设计最容易吃亏的环节不是做不出来是说不清楚做出来了。答辩现场如果只演示「卡一贴、响一声、屏上跳数字」评审很难判断这是真跑通了还是写死的。我的做法是提前准备一张验收表每一行都对应一个可现场复现的动作边演示边报数据。验收项测试方法合格标准读卡距离卡片从远到近缓慢靠近记录首次响应距离稳定读卡 ≥ 5 cm单次交易时间从卡片进入到蜂鸣器响串口打时间戳≤ 300 ms扣费准确性连续刷 20 次记录每次前后余额差额每次都等于票价余额不足用余额小于票价的卡刷不扣费双短鸣屏显提示多卡冲突两张卡叠放在天线上只选中一张不卡死掉电恢复扣费瞬间断电再上电余额为扣费前或扣费后不出现非法值时钟精度连续走 24 小时与标准时间对比误差 ≤ 5 s重复刷卡卡片贴住不放 10 秒只扣一次费表格里最值得在答辩时主动演示的是「掉电恢复」和「余额不足」这两行。前者能证明你理解「减值 传输」的原子性后者能证明异常分支不是空的。很多方案演示只走成功路径一问「钱不够怎么办」就答不上来这是最容易被扣分的地方。串口日志是另一件低成本高回报的事。在交易成功后把记录按固定格式打出来答辩时把串口助手窗口投到屏幕上每刷一次卡就多一行说服力比口头讲强得多。/* 交易记录上报一行一条便于串口助手直接查看和后期解析 */ void Uart_Report(unsigned char *uid, unsigned short fare, unsigned short balance, unsigned char *timestr) { Uart_SendString(UID); Uart_SendHex(uid, 4); /* 4 字节卡号十六进制 */ Uart_SendString( FARE); Uart_SendNumber(fare); /* 本次扣费金额 */ Uart_SendString( BAL); Uart_SendNumber(balance); /* 扣费后余额 */ Uart_SendString( TIME); Uart_SendString(timestr); /* 从 DS1302 读到的 yyyy-mm-dd hh:mm:ss */ Uart_SendString(\r\n); /* 回车换行串口助手按行显示 */ }输出格式定成「键值」的扁平结构好处是不用写解析器就能肉眼核对后期要导成表格也只需要按空格切分。字段顺序固定下来答辩现场刷十次卡评审一眼就能看出余额是递减的、时间是递增的、卡号是同一张。答辩陈述的节奏我一般这样安排先用一分钟讲清楚为什么用 Mifare One 加 MFRC522 这套组合重点落在「值块的加减值由卡片硬件保证扣费事务天然安全」再用两分钟讲系统框图和四个模块的职责让评审看到你是分层设计的不是把所有代码堆在 main 里最后五分钟全给演示按验收表从上到下走一遍每个动作说一句「现在验证的是哪一项」。整个过程不提「我学了很多」只报数据和结果。从那以后我每次焊完板子、烧程序之前都会先拿万用表量三样东西3.3 V 是不是真的 3.3 V、5 V 和 3.3 V 之间有没有短路、天线两端有没有对地短路。这三步花不到一分钟却能挡掉后面百分之八十的返工。希望帮到你。本文还有配套的精品资源点击获取

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑