【嵌入式实战-06】从零搭建 STM32+MFRC522 RFID 门禁系统
前言很多嵌入式初学者学完 RFID 理论后往往卡在 怎么落地成一个能用的项目 这一步。本文将带你从零开始搭建一个工业级可用的 RFID 门禁系统涵盖硬件选型、电路连接、代码实现、调试排坑全流程。本文亮点基于STM32F103C8T6MFRC522成本低、资料多、易移植完整可运行的HAL 库源码注释详细直接编译烧录支持按键加卡 / 删卡授权信息断电不丢失真实项目踩坑记录解决 90% 新手会遇到的问题提供 5 种以上功能扩展方案可直接用于毕设或小项目适合人群嵌入式初学者、物联网从业者、正在做毕设的学生一、系统整体设计1.1 核心功能✅ 刷卡开门识别授权 IC 卡自动控制电磁锁✅ 声光提示绿灯亮 短鸣 开门成功红灯亮 长鸣 非法卡✅ 授权管理通过按键添加 / 删除授权卡最多支持 20 张✅ 自动关门开门 3 秒后自动上锁✅ 防冲突处理多张卡同时刷卡时能正确识别单张卡1.2 系统架构STM32F103C8T6主控 ├─ MFRC522 RFID读卡器 → 读取IC卡UID ├─ 5V继电器模块 → 控制12V电磁锁 ├─ 有源蜂鸣器 → 声音提示 ├─ 红绿LED指示灯 → 状态指示 └─ 2个独立按键 → 加卡/删卡功能二、硬件选型与电路连接2.1 完整 BOM 表总成本约 80 元模块名称推荐型号核心作用选型原因成本参考主控板STM32F103C8T6 最小系统板系统核心控制入门经典款性价比高资料丰富15RFID 读卡器MFRC522带天线识别 13.56MHz IC 卡集成度高SPI 通信驱动简单12执行机构5V 单路继电器模块控制电磁锁通断带光耦隔离抗干扰能力强8门锁12V 电磁锁吸力 60kg执行开门 / 关门动作断电上锁安全可靠25提示模块有源蜂鸣器 红绿 LED声光状态提示成本低效果直观5输入模块2 个独立按键加卡 / 删卡操作简单易用无需额外驱动2电源模块12V/2A 适配器 3.3V 降压模块系统供电电磁锁单独供电避免干扰132.2 详细引脚连接表STM32 引脚连接模块引脚功能PA4MFRC522SDASPI 片选PA5MFRC522SCKSPI 时钟PA6MFRC522MISO主入从出PA7MFRC522MOSI主出从入PA8MFRC522RST复位PB0继电器模块IN控制信号PB1绿色 LED正极PB2红色 LED正极PB3有源蜂鸣器正极PA0加卡按键输入下拉PA1删卡按键输入下拉3.3VMFRC522/LED/ 蜂鸣器 / 按键电源GND所有模块地⚠️ 关键硬件注意事项MFRC522 只能用 3.3V 供电接 5V 会直接烧毁芯片电磁锁必须单独供电并在两端并联FR107 续流二极管阴极接 12V 正极阳极接负极防止断电瞬间的反电动势击穿继电器和主控MFRC522 天线要远离金属物体否则读取距离会大幅缩短正常 3-5cm继电器触点容量要大于电磁锁工作电流通常 1-2A三、软件实现完整 HAL 库源码3.1 开发环境Keil MDK5.38STM32CubeMX 6.10.0ST-Link/V2 仿真器3.2 STM32CubeMX 配置时钟配置外部 8MHz 晶振系统时钟 72MHzSPI1 配置Mode 0CPOL0, CPHA0数据大小 8 位波特率 5MHz实测最稳定GPIO 配置PA4/PA5/PA6/PA7/PA8推挽输出MFRC522PB0/PB1/PB2/PB3推挽输出继电器 / LED / 蜂鸣器PA0/PA1下拉输入按键USART1 配置波特率 115200用于调试输出3.3 核心代码实现3.3.1 MFRC522 驱动核心函数// mfrc522.h #ifndef __MFRC522_H #define __MFRC522_H #include stm32f1xx_hal.h #define MI_OK 0 #define MI_ERR 1 // MFRC522命令定义 #define PICC_REQIDL 0x26 #define PICC_ANTICOLL1 0x93 #define PICC_SELECTTAG 0x93 #define PICC_HALT 0x50 // 函数声明 void MFRC522_Init(void); uint8_t MFRC522_Request(uint8_t reqMode, uint8_t *TagType); uint8_t MFRC522_Anticoll(uint8_t *cardID); uint8_t MFRC522_Select(uint8_t *cardID); void MFRC522_Halt(void); #endif// mfrc522.c核心函数节选 #include mfrc522.h #include spi.h #include gpio.h // 写寄存器 void MFRC522_WriteReg(uint8_t reg, uint8_t value) { HAL_GPIO_WritePin(GPIOA, GPIO_PIN_4, GPIO_PIN_RESET); HAL_SPI_Transmit(hspi1, reg, 1, 100); HAL_SPI_Transmit(hspi1, value, 1, 100); HAL_GPIO_WritePin(GPIOA, GPIO_PIN_4, GPIO_PIN_SET); } // 读寄存器 uint8_t MFRC522_ReadReg(uint8_t reg) { uint8_t value; reg 0x80 | reg; HAL_GPIO_WritePin(GPIOA, GPIO_PIN_4, GPIO_PIN_RESET); HAL_SPI_Transmit(hspi1, reg, 1, 100); HAL_SPI_Receive(hspi1, value, 1, 100); HAL_GPIO_WritePin(GPIOA, GPIO_PIN_4, GPIO_PIN_SET); return value; } // 防冲突函数读取卡片唯一ID uint8_t MFRC522_Anticoll(uint8_t *cardID) { uint8_t status; uint8_t i, snr_check 0; uint16_t recvLen; uint8_t sendData[2] {PICC_ANTICOLL1, 0x20}; status MFRC522_Communicate(PCD_TRANSCEIVE, sendData, 2, sendData, recvLen); if(status MI_OK recvLen 40) { for(i0; i4; i) { cardID[i] sendData[i]; snr_check ^ sendData[i]; } if(snr_check ! sendData[4]) status MI_ERR; } else { status MI_ERR; } return status; }3.3.2 授权卡管理Flash 存储// card_manager.h #ifndef __CARD_MANAGER_H #define __CARD_MANAGER_H #include stm32f1xx_hal.h #define MAX_CARD_NUM 20 // 最多支持20张授权卡 #define FLASH_ADDR 0x0800F800 // Flash存储地址最后一页 // 函数声明 void CardManager_Init(void); uint8_t CardManager_Check(uint8_t *cardID); uint8_t CardManager_Add(uint8_t *cardID); uint8_t CardManager_Delete(uint8_t *cardID); void CardManager_Save(void); #endif3.3.3 主逻辑代码// main.c #include main.h #include spi.h #include gpio.h #include usart.h #include mfrc522.h #include card_manager.h #include relay.h #include beep.h #include led.h #include key.h int main(void) { HAL_Init(); SystemClock_Config(); MX_GPIO_Init(); MX_SPI1_Init(); MX_USART1_UART_Init(); MFRC522_Init(); CardManager_Init(); printf(RFID门禁系统启动成功\r\n); uint8_t cardID[4]; uint8_t status; uint32_t door_timer 0; uint8_t door_state 0; while(1) { // 按键处理加卡/删卡 Key_Process(); // 寻卡 if(MFRC522_Request(PICC_REQIDL, cardID) MI_OK) { // 防冲突读取UID if(MFRC522_Anticoll(cardID) MI_OK) { printf(检测到卡片UID: %02X%02X%02X%02X\r\n, cardID[0], cardID[1], cardID[2], cardID[3]); // 检查是否是授权卡 if(CardManager_Check(cardID) MI_OK) { printf(授权卡开门\r\n); Relay_Open(); LED_Green_On(); Beep_Short(); door_timer HAL_GetTick(); door_state 1; } else { printf(非法卡报警\r\n); LED_Red_On(); Beep_Long(); HAL_Delay(1000); LED_Red_Off(); } MFRC522_Halt(); // 休眠卡片 } } // 自动关门3秒后 if(door_state (HAL_GetTick() - door_timer 3000)) { Relay_Close(); LED_Green_Off(); door_state 0; printf(自动关门\r\n); } HAL_Delay(10); } }四、测试与验证4.1 测试步骤上电测试连接所有硬件上电后绿色 LED 常亮表示系统正常刷卡测试将一张空白 IC 卡靠近读卡器串口会输出卡片 UID加卡测试按下加卡按键PA0蜂鸣器响一声然后刷卡提示 加卡成功开门测试刷刚添加的授权卡继电器吸合电磁锁打开3 秒后自动关闭非法卡测试刷未授权的卡蜂鸣器长鸣红灯亮门锁不打开删卡测试按下删卡按键PA1蜂鸣器响一声然后刷卡提示 删卡成功断电测试断电后重新上电授权卡信息仍然保留4.2 预期结果授权卡刷卡成功率 100%响应时间 0.5 秒非法卡无法开门报警提示正常加卡 / 删卡功能正常断电不丢失数据自动关门时间准确无卡顿五、新手必看踩坑与解决方案这是我在实际项目中踩过的坑90% 的新手都会遇到5.1 MFRC522 读取不到卡问题现象上电后读卡器无反应串口无输出可能原因及解决SPI 引脚接反MISO 和 MOSI 是最容易接反的一定要仔细核对电源错误MFRC522 必须用 3.3V接 5V 会直接烧毁SPI 配置错误必须设置为Mode 0CPOL0, CPHA0速率不要超过 5MHz复位引脚未接RST 引脚必须接 STM32 的 GPIO不能悬空天线问题天线焊接不良或靠近金属会导致读取距离为 05.2 电磁锁干扰导致系统死机问题现象开门瞬间系统死机需要重新上电根本原因电磁锁是感性负载断电瞬间会产生数百伏的反电动势通过电源线路干扰主控解决方案电磁锁必须单独供电不要和主控共用电源在电磁锁两端并联FR107 续流二极管阴极接 12V 正极阳极接负极继电器模块必须带光耦隔离切断干扰路径在主控电源输入端加 100uF 电解电容和 0.1uF 陶瓷电容滤波5.3 多张卡同时刷卡出错问题现象两张卡同时靠近读卡器时系统无反应或识别错误解决方案正确实现 MFRC522 的防碰撞算法本文提供的代码已经包含完整的防碰撞处理能正确识别多张卡中的任意一张5.4 授权卡信息断电丢失问题现象断电后重新上电之前添加的授权卡全部失效解决方案不要将授权卡信息存储在 RAM 中要存储到 STM32 的Flash中。本文提供的 CardManager 模块已经实现了 Flash 读写功能断电后数据不会丢失。六、功能扩展方案这个基础门禁系统可以很方便地扩展更多功能添加 LCD 显示屏使用 0.96 寸 OLED 显示屏显示卡号、系统状态、操作提示WiFi 远程控制添加 ESP8266 模块实现手机 APP 远程开门、刷卡记录查询指纹识别集成 AS608 指纹模块实现 RFID 指纹双重认证密码开锁添加 4x4 矩阵键盘支持密码开锁刷卡记录上传将刷卡记录上传到云端服务器实现远程监控低功耗设计使用 STM32 的低功耗模式适合电池供电的场景七、总结本文详细介绍了如何从零搭建一个完整的 RFID 门禁系统从硬件选型到软件实现再到调试排坑每一步都给出了详细的说明和完整的代码。这个系统不仅可以作为学习项目还可以直接用于实际的门禁场景。通过这个项目你可以掌握STM32 HAL 库的使用SPI 通信协议MFRC522 RFID 模块的驱动开发Flash 数据存储硬件抗干扰设计嵌入式系统的整体设计思路创作不易如果本文对你有帮助欢迎点赞、收藏、转发你的支持是我持续输出的动力