简介这份资源是面向51单片机学习者与嵌入式入门者的RFID程序完整工程包围绕阅读器端开发解决从模块驱动到应用逻辑的落地问题。内容涉及RFID模块选型如MFRC522、EM4069、SPI/I2C接口连接、ISO/IEC 14443等协议理解以及初始化、命令收发、数据解析、中断处理与错误检测等关键环节并延伸至读卡显示、数据记录、门禁控制等应用层示例适合具备C语言与基础电路知识的读者对照实践。压缩包为rar格式约15.04MB上游未提供文件总数与类型明细从描述看应包含驱动代码、主程序、示例应用、配置参数与说明文档等模块。目前已有1658人学习下载可作为搭建小型RFID系统、理解51单片机与射频模块协同工作的参考素材便于读者梳理工程结构并迁移到自己的物联网或智能设备项目中。1. 从一块读卡器板子说起这套51单片机RFID程序到底能跑出什么手里有一块RC522读卡模块、一片STC89C52或者AT89C52最小系统板再加上一张M1卡很多人第一次接线通电之后看到串口助手刷出一串UID就以为完事了。真正拿这套东西去做课程设计、门禁Demo、考勤机原型的时候才会发现难点根本不在“读出一串卡号”而在于读卡之后的整套流程寻卡、防冲突、选卡、认证、读写扇区、串口回传、LCD显示、继电器开锁每一步的时序和状态机都得对得上错一个字节就卡死在那里。这份51单片机RFID程序完整版解决的就是从裸片驱动到业务闭环这一整段把RC522的SPI时序、M1卡认证流程、串口协议和外围控制都串起来了适合正在做单片机课程设计、门禁考勤类小系统、或者想把RFID读卡模块吃透的开发者直接拿来改。它不是一个只跑通“读卡号”的Demo而是一套带完整工程结构的C51程序底层是RC522寄存器操作和SPI位操作中间层封装了寻卡、防冲突、选卡、认证、读写块这些ISO14443A协议动作上层是主循环里的业务逻辑负责把卡号比对、串口输出、显示刷新、继电器动作串起来。技术栈很朴素——Keil C51编译环境、标准8051指令集、软件模拟SPI、UART串口没有RTOS没有复杂框架全部靠主循环加状态标志推进。这种结构对新手友好对熟手也够用因为每一层都能单独替换想换成硬件SPI改底层想换成别的卡型改协议层想接上位机改串口协议层。下面按“这项目怎么组织、怎么跑起来、怎么改”一路拆下去。2. 工程结构与通信链路从RC522寄存器到主循环的完整分层2.1 目录与文件划分这套程序常见做法是按功能拆成几个.c/.h文件而不是全塞进一个main.c。典型结构如下文件职责main.c主循环、初始化、业务状态机rc522.c / rc522.hRC522寄存器读写、复位、天线配置spi.c / spi.c.h软件模拟SPI的位操作时序mfrc522_app.c寻卡、防冲突、选卡、认证、读写块uart.c串口初始化与收发lcd1602.c 或 oled.c显示驱动按实际外设选delay.c毫秒/微秒级延时config.h引脚定义、卡号白名单、功能开关这种拆法的好处是引脚和业务分离。config.h里集中定义SCK、MOSI、MISO、NSS、RST这几个引脚换板子只改这一处rc522.c只关心寄存器地址和位操作不掺业务main.c只调用“读一张卡”这个高层函数不关心SPI怎么翻电平。二次开发时最怕的就是引脚散落在各个文件里改一个脚要全局搜索这套结构避开了这个坑。2.2 软件SPI的时序实现51单片机多数型号没有硬件SPI所以这套程序用普通IO口模拟SPI。核心就是四条线时钟SCK、主出从入MOSI、主入从出MISO、片选NSS。RC522支持SPI模式0也就是空闲时时钟低电平数据在上升沿采样。下面这段是典型的位操作写法// 软件SPI写一个字节模式0空闲低电平上升沿采样 void SPI_WriteByte(unsigned char dat) { unsigned char i; for(i 0; i 8; i) { SCK 0; // 时钟拉低准备数据 if(dat 0x80) // 取最高位MSB先行 MOSI 1; else MOSI 0; dat 1; // 左移准备下一位 SCK 1; // 上升沿从机采样 } SCK 0; // 恢复空闲低电平 } // 软件SPI读一个字节同样MSB先行 unsigned char SPI_ReadByte(void) { unsigned char i, dat 0; for(i 0; i 8; i) { dat 1; SCK 1; // 上升沿后从机输出数据 if(MISO) dat | 0x01; // 采样MISO SCK 0; // 拉低准备下一位 } return dat; }这里有两个参数必须对上一是MSB先行RC522的SPI要求高位先出写反了读出来的寄存器值全是乱的二是模式0的相位关系SCK先低后高再低数据在上升沿被采样。很多新手翻车就翻在“读出来全是0xFF或者0x00”八成是SCK空闲电平或者采样沿搞反了。延时方面51的IO翻转本身有机器周期一般不需要额外加nop但如果主频很高比如11.0592MHz以上跑得比较快可以在SCK拉高后加一两个空操作保证建立时间。这套程序里delay.c提供了微秒级延时SPI里按需插入不盲目加长延时否则读一张卡会明显变慢。2.3 RC522寄存器读写与复位流程RC522的所有操作都落到寄存器上读寄存器是“地址左移一位再或0x80”写寄存器是“地址左移一位再与0x7E”。这个地址变换是协议规定的写错一位就访问到别的寄存器。典型实现// 写RC522寄存器 void RC522_WriteReg(unsigned char addr, unsigned char val) { NSS 0; // 片选拉低 SPI_WriteByte((addr 1) 0x7E); // 写地址左移一位最低位清零 SPI_WriteByte(val); // 写入数据 NSS 1; // 片选拉高 } // 读RC522寄存器 unsigned char RC522_ReadReg(unsigned char addr) { unsigned char val; NSS 0; SPI_WriteByte(((addr 1) 0x7E) | 0x80); // 读地址最高位置1 val SPI_ReadByte(); NSS 1; return val; }复位流程一般是拉低RST一段时间拉高然后写CommandReg软复位等PowerDown位清零再配置TimerReg、TxModeReg、RxModeReg、ModWidthReg这些天线相关寄存器最后打开天线。这套顺序不能乱尤其是软复位后必须等芯片内部就绪再往下走否则后面写进去的配置全丢。程序里用轮询CommandReg的PowerDown位来判断复位完成比死延时可靠。2.4 主循环里的业务状态机主循环不阻塞靠状态标志推进。常见写法是每轮先调一次寻卡有卡才进后续流程没卡就刷新显示或者等串口命令。伪代码如下void main(void) { System_Init(); // 引脚、串口、定时器、LCD初始化 RC522_Init(); // 复位并配置RC522 LCD_ShowString(0, 0, RFID Ready); while(1) { if(PcdRequest(PICC_REQIDL, cardType) MI_OK) // 寻卡 { if(PcdAnticoll(uid) MI_OK) // 防冲突拿UID { if(Check_WhiteList(uid)) // 比对白名单 { Relay_Open(); // 开锁 UART_SendCard(uid); // 串口回传 LCD_ShowString(0, 1, Access OK); } else { LCD_ShowString(0, 1, Denied); } Delay_ms(500); // 防重复读 } } } }这段逻辑的关键在最后那个延时。不加延时同一张卡会在几十毫秒内被反复读到继电器哒哒响串口刷屏。常见做法是读到卡后延时几百毫秒再继续寻卡或者用“卡离开检测”标志位只有检测到卡离开才允许下一次触发。这套程序用的是延时加状态标志的组合简单但够用。3. 跑起来接线、编译、烧录与串口验证3.1 硬件接线对照RC522是3.3V器件51单片机一般是5V系统这里有个必须注意的点RC522的电源和信号电平都是3.3V直接拿5V单片机的IO去驱动短时间可能能跑长时间有损坏风险。稳妥做法是信号线串电阻分压或者用电平转换电源单独给3.3V。接线对照如下RC522引脚51单片机引脚说明SDA(NSS)P2.0片选低有效SCKP2.1时钟MOSIP2.2主出从入MISOP2.3主入从出RSTP2.4复位低有效3.3V3.3V电源不可接5VGNDGND共地串口部分用P3.0/P3.1接USB转TTL波特率常见9600晶振11.0592MHz时误差最小。如果板上还有LCD1602数据口接P0控制脚接P2.5到P2.7具体以config.h为准。3.2 Keil工程配置与编译打开工程后先确认三件事器件型号选对STC89C52或AT89C52按实际芯片选、晶振频率填对11.0592MHz或12MHz影响延时和串口波特率、输出勾选生成HEX文件。编译前检查config.h里的引脚定义和实际接线是否一致这是最常见的“编译通过但跑不起来”的原因。编译无报错后用STC-ISP或者对应烧录工具下载HEX冷启动上电。3.3 串口验证与读卡测试上电后串口助手设9600、8位、无校验、1停止位应该能看到初始化信息。拿一张M1卡靠近天线正常会输出类似“UID: xx xx xx xx”的内容。如果没反应先看天线有没有接好RC522模块天线是PCB印刷的一般不用外接再看RC522的3.3V是否正常最后用万用表量RST脚上电后是否被拉高。读卡距离一般2到5厘米太远读不到不是程序问题是天线功率和卡类型的问题。提示第一次调试建议先把LCD和继电器相关代码注释掉只保留串口输出确认读卡链路通了再逐步加外设否则出问题时分不清是读卡失败还是显示阻塞。4. 核心代码拆解寻卡、防冲突、选卡与扇区认证4.1 寻卡与防冲突的协议动作寻卡用PcdRequest发的是REQA或者WUPA命令卡在射频场内会回ATQA。防冲突用PcdAnticoll发0x93 0x20卡回4字节UID加校验。这两步的返回值判断很关键MI_OK才继续MI_NOTAGERR说明没卡其他值说明通信出错。防冲突里有个细节多张卡同时在场时防冲突算法会逐位仲裁最终选出一张。这套程序按单卡场景实现多卡场景下需要循环调用直到没有冲突做考勤机多卡同时刷的场景要注意这一点。4.2 扇区认证与块读写M1卡分16个扇区每个扇区4个块每块16字节第3块是密钥块。读写数据前必须先认证认证命令是0x60KeyA或0x61KeyB后面跟块地址、6字节密钥、4字节卡号。认证通过才能读块。典型读块流程// 认证扇区0的块1使用KeyA默认密钥全FF unsigned char keyA[6] {0xFF,0xFF,0xFF,0xFF,0xFF,0xFF}; if(PcdAuthState(0x60, 1, keyA, uid) MI_OK) { unsigned char data[16]; if(PcdRead(1, data) MI_OK) // 读块1 { UART_SendBuffer(data, 16); // 回传16字节 } }参数说明第一个参数0x60表示KeyA认证0x61是KeyB第二个参数是绝对块号扇区0块1就是1扇区1块0是4以此类推keyA是6字节密钥出厂默认全FF实际项目里一定要改否则谁都能读uid是防冲突拿到的4字节卡号认证时必须带上。写块用PcdWrite写之前同样要认证写完建议回读校验M1卡写操作有失败概率不回读容易埋雷。4.3 卡号白名单与权限判断白名单常见做法是存成二维数组或者结构体数组每个元素4字节UID加一个权限标志。比对时逐字节比较全等才放行。更工程化的做法是把白名单放EEPROM支持串口下发增删但这套程序为了简洁用的是编译期常量数组。二次开发时如果要支持动态授权把Check_WhiteList改成从EEPROM读再加一条串口命令“ADD uid”写入就能做成简易发卡器。5. 避坑与排查读卡失败、认证不过、串口乱码的现场记录5.1 现象串口一直输出0xFF或0x00读不到卡原因多半在SPI时序或者接线。先确认NSS、SCK、MOSI、MISO四根线没有接反尤其是MOSI和MISO对调是高频错误再确认RC522供电是3.3V不是5V最后用示波器或者逻辑分析仪看SCK有没有波形。没有仪器的话写一个只读VersionReg的测试函数正常应该读到0x91或0x92读不到就说明SPI链路没通跟卡没关系。5.2 现象能寻到卡但认证总是失败认证失败先看密钥。出厂卡默认KeyA是六个0xFF但有些卡被改过密钥拿默认密钥当然过不了。其次看块地址认证的块号必须是绝对块号不是扇区内偏移扇区1块0要写4不是0。最后看UID认证时带的UID必须是防冲突拿到的4字节顺序不能反。这三条对不上认证必挂。5.3 现象继电器反复吸合串口刷屏原因是主循环里没有做读卡去抖。同一张卡在射频场内会持续被寻到每轮循环都触发一次业务。解决办法是读到卡后延时300到500毫秒或者记录上一次UID相同UID在设定时间内不重复处理。更严谨的做法是检测卡离开连续若干次寻不到卡再重置标志这样连刷同一张卡也不会重复触发。5.4 现象串口输出乱码先查波特率和晶振是否匹配。11.0592MHz配9600是标准组合12MHz配9600会有误差容易乱码。再查串口初始化里TMOD、TH1、TL1、SCON的配置TH1和TL1要按晶振和波特率算不能照抄。最后确认USB转TTL的TX/RX和单片机的RX/TX是交叉接的TX接TX是接不通的。5.5 现象程序跑一段时间后死机51单片机RAM很小常见原因是数组越界或者递归调用。检查串口接收缓冲区有没有做长度限制检查LCD显示字符串有没有超出行宽检查中断里有没有做耗时操作。另外RC522长时间工作发热时通信可能不稳加一个超时重试机制读失败重试两三次再报错比直接死等可靠。6. 二次开发改造从读卡Demo到可维护的小系统这套程序最值得改的地方不是读卡本身而是把“读卡”抽象成一个事件让业务逻辑跟驱动彻底分开。我一般会做三件事第一把Check_WhiteList和Relay_Open这些业务函数从main.c里抽出来放到app.cmain.c只负责调度第二给读卡加一个环形缓冲或者标志队列中断里只置标志主循环处理避免在SPI操作中间被串口中断打断导致时序错乱第三把卡号白名单和配置参数挪到EEPROM加两条串口命令做增删查这样不用每次改代码重新烧录。验证改造是否成功不用整机反复试写一个分层测试的顺序先单独测SPI读VersionReg再测寻卡返回ATQA再测防冲突拿UID最后测认证读块。每一层通了再往上走出问题能立刻定位到层。这个习惯是从一次血泪经验来的当时把LCD刷新和读卡放在同一个循环里读卡偶尔失败查了两天才发现是LCD写操作占用了太多时间导致SPI时序被拉长。从那以后我每次改这类程序都强制先跑一遍分层自检确认底层稳了再动业务。希望帮到你。本文还有配套的精品资源点击获取
阅读完成 · 觉得有帮助?