STM32智能门禁系统四合一方案:人脸识别+RFID+蓝牙+密码锁设计
2026/9/1 22:01:32 网站建设 项目流程

简介:本资源是一套基于STM32平台的完整智能门禁系统工程源码,面向计算机、电子信息、自动化等专业的本科生课程设计、毕业设计及单片机进阶学习者,解决多模态身份认证(人脸识别+RFID卡+蓝牙APP远程控制+数字密码)与嵌入式门禁逻辑集成的实际开发问题。压缩包共254个文件,含49个头文件(.h)定义硬件接口与功能模块,46个C源文件(.c)实现核心算法与外设驱动,以及编译生成的.o、.d、.axf、.hex等构建产物和Keil工程配置文件(.uvprojx/.uvoptx),整体大小为8.66MB,结构规范,便于理解STM32固件开发全流程。已有355人学习下载,资源提供可直接编译运行的完整工程,涵盖TIM/RCC/ADC/I2C/CAN等标准外设驱动代码,以及人脸识别图像采集、RFID读卡、蓝牙通信协议解析与密码锁状态机等关键模块,适合在掌握C语言与STM32基础后开展功能扩展与调试实践。 最近在整理一个综合性的嵌入式项目,刚好把基于STM32的智能门禁系统从头到尾理了一遍。这个项目的核心是四合一认证:人脸识别、RFID刷卡、蓝牙App远程控制、密码键盘开锁,整合在一颗STM32主控上。网上能搜到一堆零散的“门禁系统源码”,但真正能跑通、能讲清楚设计原理的不多。这篇就把我实际做过的方案、踩过的坑和最终的代码框架都拆开聊透,希望能给做毕业设计、比赛作品或者真实产品原型的朋友一个可复用的参考。

1. 这个项目解决什么问题:四种开锁方式的方案取舍

1.1 门禁场景的真实需求

门禁这个东西,看似简单,但一到实际场景就会发现单一认证方式永远不够用。办公室大门,白天人多,刷卡最快;晚上加班的人可能没带卡,这时候就需要密码;如果你手上抱着快递搬东西,腾不出手去按密码,人脸识别就很实用;而临时给访客开门、或者人在工位上个厕所被别人反锁在外面,手机蓝牙远程开锁就是救命的通道。

所以这套系统的定位很清晰:不是“做出来能开锁”,而是“在多重场景下都能稳定可靠地把门打开”。四个认证通道互相备份,任何一个单独用都能开锁,也可以配置成组合认证模式(人脸+密码同时满足才开门)。这种设计思路在真实产品和课程设计里都是加分项。

1.2 为什么选中STM32而不是树莓派或纯模块方案

核心原因就三个:成本、实时性、外设资源

树莓派跑人脸识别当然更强,Linux生态也舒服,但在门禁这种任务里,成本近百块、启动时间几秒、稳定性受SD卡影响,这些都是硬伤。纯模块方案(用一个人脸识别模组直接联动电磁锁)虽然简单,但四个通道之间没法做统一的权限管理和日志记录,相当于四把锁各自为政,不叫“智能门禁”。

STM32系列里,我选了STM32F103C8T6,也就是经典的蓝丸核心板。这颗芯片主频72MHz、64KB Flash、20KB RAM,资源上正好能扛住这套系统:

  • 人脸识别模组走串口,主控只是收发指令和响应,不跑算法,所以CPU压力不大
  • RC522 RFID走SPI接口,速度足够
  • 蓝牙模块走另一个串口
  • 矩阵键盘占用8个左右的GPIO
  • 电磁锁控制用继电器,一个GPIO就搞定

算下来外设刚刚好,不浪费也不紧张。如果你要额外加OLED显示屏、蜂鸣器、红外人体感应这些,F103C8T6也还留有富余。预算充裕的话可以直接上F407或F103ZET6,代码逻辑不用变,主要改引脚映射就能跑。

1.3 总体软件架构:裸机状态机

很多人一上来就想着上FreeRTOS。但实际评估下来,门禁这种业务逻辑并不复杂,核心就是一个事件驱动的状态机:等待认证 → 收到某种认证请求 → 校验该通道的凭据 → 通过则开锁/失败则提示 → 回到待机状态。

裸机状态机的优势是调试直观、代码可读性强、没有任务调度的心智负担。四个外设的数据接收全部走中断,中断里只做收数据和置标志位,真正处理数据的逻辑放在主循环的状态机里。这样不会出现中断里跑复杂逻辑导致其他通道丢数据的风险。

提示:如果项目要求扩展多个传感器或联动更多设备,再考虑上FreeRTOS,否则裸机是性价比最高的方案。我在上一版项目里就曾硬上RTOS,结果为了处理优先级反转花了两天时间,而需求并未复杂到需要RTOS的程度。

2. 硬件连接细节:从最小系统板到各模块引脚的完整梳理

2.1 引脚分配的整体规划

硬件设计的第一原则是避免引脚冲突,尤其是STM32的下载引脚和I2C/SPI专用引脚。我的引脚分配如下:

外设接口类型引脚说明
人脸识别模组USART1PA9(TX)、PA10(RX)波特率115200
RFID RC522SPI1PA5(SCK)、PA6(MISO)、PA7(MOSI)、PA4(CS)STM32作为SPI主机
蓝牙HC-05USART2PA2(TX)、PA3(RX)波特率9600或115200
矩阵键盘(4x4)GPIO输入PB0-PB7行扫描+列检测
继电器GPIO输出PA1高电平触发开锁
蜂鸣器GPIO输出PA0认证成功/失败提示
状态指示灯GPIO输出PB8、PB9红绿LED

这几个外设接口之间没有复用,唯一要注意的是PA9/PA10、PA2/PA3串口的TX/RX交叉连接,这个是最容易接反的。人脸模组和STM32连接时,STM32的PA9(TX)要接模组的RX,PA10(RX)接模组的TX。

2.2 人脸识别模组的选型与接线

人脸识别模块是整套系统里唯一外购的“黑匣子”。市面上常见的有三类:

  • 串口型人脸识别模组(如中控智慧、汉王等):自带摄像头和算法,输出识别结果和用户ID,价格在50-150元之间
  • OpenMV/K210开发板:自己写图像识别代码,自定义程度高,但需要额外学习MicroPython或K210 SDK
  • ESP32-CAM+OpenCV后端:摄像头采集,WiFi传到服务端识别,延迟高,不适合门禁

我的推荐是串口型人脸识别模组,理由很简单:门禁系统主控的职责是逻辑控制和通道管理,不应该陷进图像算法里。串口型模组内部已经完成了人脸检测、特征提取、比对识别,对外只需发送“注册人脸”“删除人脸”“识别”等指令,返回结果也是现成的JSON或定长帧,这对STM32这种性能有限的主控非常友好。

接线就三根线:VCC(5V)、GND、TX/RX交叉连接。部分模组支持UART TTL电平,直接和STM32同电压域连接,不需要额外转换。如果是5V电平的模组,必须加电平转换芯片(如MAX3232)或用分压电阻,不能直接怼到STM32引脚上,不然大概率烧引脚。

2.3 RFID、蓝牙、键盘的连接

RC522 RFID模块是SPI接口,供电范围3.3V-5V,但IO逻辑电平必须注意:很多RC522模块板上自带稳压和电平转换,可以直接接3.3V供电并使用3.3V SPI信号。如果模块不带电平转换,5V供电时SPI信号千万不能直接接STM32引脚,否则电压超标。

HC-05蓝牙模块工作在3.3V,但它有个坑:STATE引脚和EN引脚电平是3.3V,而KEY引脚(进入AT模式)要求高电平。接STM32时,TX/RX用串口2,KEY引脚接一个GPIO或者直接接3.3V进入AT模式配置,配置完再断开。

4x4矩阵键盘的接线相对简单,8根引脚两边分别接STM32的PB0-PB3(行)和PB4-PB7(列),全部配置为输入上拉,通过行列扫描检测按键。注意PB3、PB4在F103上是JTAG引脚,默认是复用功能,需要先禁用JTAG才能当普通GPIO用,这个坑后面细说。

2.4 电源系统的估算

整套系统的功耗集中在大头:

  • STM32核心板:约50mA
  • 人脸模组:平均100-200mA,峰值300mA
  • RC522:约30mA
  • HC-05:约40mA
  • 继电器+电磁锁(通电瞬间):电磁锁工作电流300-800mA(视型号),继电器线圈约70mA

所以总电流峰值接近1A。USB供电(5V/2A)够用,但如果是锂电池供电,必须选容量足够且带过流保护的电池,并且考虑电磁锁的感性负载反向电动势问题。继电器线圈两端必须并一个1N4007续流二极管,否则断电瞬间产生的反向尖峰电压会直接冲击STM32电源轨,甚至导致主控复位。

3. 固件工程搭建:HAL库、多串口、DMA空闲中断与状态机框架

3.1 基础工程结构

整个固件代码我按模块化方式组织,目录结构大致如下:

Project ├── Core │ ├── Inc │ └── Src │ ├── main.c │ ├── stm32f1xx_hal_msp.c │ ├── stm32f1xx_it.c │ └── system_stm32f1xx.c ├── Drivers │ └── STM32F1xx_HAL_Driver ├── Middlewares │ └── src │ ├── state_machine.c │ ├── protocol.c │ └── event_queue.c └── App ├── face_module.c ├── rfid_module.c ├── keypad_module.c ├── bluetooth_module.c └── door_control.c

核心思路是:每个外设对应一个.c文件,提供Init()、Handle()、GetEvent()等接口,业务逻辑层只通过统一的接口访问各外设,避免在main.c里堆几千行的面条代码。

3.2 多串口的数据接收方案:DMA+空闲中断

门禁系统的人脸模组和蓝牙模块都会持续不断地发数据,而且数据长度不确定。最麻烦的问题是:STM32的USART接收如果不处理空闲状态,你永远不知道一帧数据什么时候结束

我给两个串口都用了DMA+IDLE空闲中断方案。原理是这样:DMA把接收到的字节持续搬运到内存环形缓冲区,当串口总线上出现空闲(一个完整帧发完了,线路空闲超过一个字节时间)时,USART会产生IDLE中断,此时读取DMA当前剩余计数,就能知道这一帧收了多少字节。这样不管发来的是4字节指令还是128字节的人脸特征数据,都能一次收完。

关键代码片段:

void USART1_IRQHandler(void) { if (RESET != __HAL_UART_GET_FLAG(&huart1, UART_FLAG_IDLE)) { __HAL_UART_CLEAR_IDLEFLAG(&huart1); /* 停止DMA,计算接收长度 */ HAL_DMA_Abort(&hdma_usart1_rx); receive_len = BUFFER_SIZE - __HAL_DMA_GET_COUNTER(&hdma_usart1_rx); /* 设置事件标志 */ event_set(EVENT_FACE_DATA_READY, receive_len); /* 重新启动DMA接收 */ HAL_UART_Receive_DMA(&huart1, (uint8_t*)face_rx_buf, BUFFER_SIZE); } HAL_UART_IRQHandler(&huart1); }

这个方案的优点是不占用CPU,主循环只管处理数据,收数据由DMA自动完成。实测在115200波特率下,即使连续接收几百字节的人脸模板数据,也不会丢字节。

3.3 事件状态机的设计

门禁的整个业务逻辑可以抽象成以下几种事件:

事件触发源对应动作
EVENT_FACE_DATA人脸模组返回识别结果判断是否注册用户,是则开锁
EVENT_RFID_CARDRC522检测到卡片读取卡号,比对授权列表
EVENT_KEYPAD_INPUT键盘按下收集数字,满N位后校验密码
EVENT_BT_CMD蓝牙收到App指令解析指令类型,执行开锁/添加卡/查询日志
EVENT_AUTH_SUCCESS任一通道校验通过继电器吸合2秒,蜂鸣器响一声
EVENT_AUTH_FAIL任一通道校验失败蜂鸣器响三声,连续失败5次锁定60秒
EVENT_TIMEOUT开锁后超时继电器释放,回到待机

状态机就五态:IDLE、AUTHENTICATING、OPENING、LOCKED、ERROR

  • IDLE:等待事件,任何认证通道都能进入AUTHENTICATING
  • AUTHENTICATING:正在校验凭据,此时其他通道的数据可以排队但先不处理
  • OPENING:继电器已吸合,等待2秒后自动回到IDLE
  • LOCKED:连续认证失败触发锁定,倒计时结束才回IDLE
  • ERROR:异常状态(如看门狗复位后、存储校验失败),需要管理员密码才能恢复

状态机的实现在main循环里,用一个switch-case包裹,代码结构清晰、方便加新状态。

while (1) { uint32_t event = event_poll(); switch (current_state) { case STATE_IDLE: handle_idle_state(event); break; case STATE_AUTHENTICATING: handle_auth_state(event); break; case STATE_OPENING: handle_opening_state(event); break; case STATE_LOCKED: handle_locked_state(event); break; case STATE_ERROR: handle_error_state(event); break; default: break; } }

4. 人脸识别开锁:与识别模组的串口对接和协议解析

4.1 模组的工作原理与对外接口

人脸模组内部的事情我不展开说,但要知道它的工作流:上电初始化 → 检测到人脸 → 提取特征 → 与内部注册的人脸特征库比对 → 输出结果。对外暴露的指令集大致分三类:

  • 注册类指令:添加一个新用户,传入用户ID和人脸照片数据(通常需要人脸正对摄像头,模组自己采集)
  • 删除类指令:按用户ID删除人脸数据
  • 识别类指令:模组自动检测并比对,返回“通过/不通过+用户ID”或者直接返回识别到的用户ID

我的方案是让模组工作在人脸检测自动上报模式下,也就是每隔一段时间模组检测到人脸,自动向串口发送一帧识别结果。STM32这边只需要解析这一帧,不需要频繁地发识别指令。

4.2 通信帧格式的解析

我用的人脸模组帧格式是一个自定义协议,固定帧头是0xAA 0x55,长度字段表示后续数据长度,数据区包含指令类型、状态、用户ID和校验。

例如识别成功的帧可能是:

AA 55 0E 01 00 00 00 01 00 03 00 01 05 E2
  • AA 55:帧头
  • 0E:数据长度14字节
  • 01:指令类型(识别结果上报)
  • 00 00 00 01:状态,1表示识别成功
  • 00 03 00 01:用户ID整形(这里是769)
  • 05 E2:CRC16校验

解析代码就要做到:从字节流里找帧头,然后按长度收完一帧,校验CRC,再提取状态和ID。这里我强烈建议写一个通用的帧解析器,不要在一个中断回调里把帧处理完。帧解析器可以用状态机来写:

typedef enum { PARSE_FRAME_HEAD1, PARSE_FRAME_HEAD2, PARSE_FRAME_LEN, PARSE_FRAME_DATA, PARSE_FRAME_CRC } ParseState; void face_parse_byte(uint8_t byte) { switch (parse_state) { case PARSE_FRAME_HEAD1: if (byte == 0xAA) parse_state = PARSE_FRAME_HEAD2; break; case PARSE_FRAME_HEAD2: if (byte == 0x55) parse_state = PARSE_FRAME_LEN; else parse_state = PARSE_FRAME_HEAD1; /* 重新同步 */ break; case PARSE_FRAME_LEN: frame_len = byte; rx_index = 0; parse_state = PARSE_FRAME_DATA; break; case PARSE_FRAME_DATA: data_buffer[rx_index++] = byte; if (rx_index >= frame_len) parse_state = PARSE_FRAME_CRC; break; case PARSE_FRAME_CRC: if (crc16_check(data_buffer, frame_len, byte) == 0) { face_frame_callback(data_buffer, frame_len); } parse_state = PARSE_FRAME_HEAD1; break; } }

这种字节级状态机的好处是对数据流中的噪声不敏感,即使前一个帧头被干扰丢掉了,也能在下一个帧头处自动恢复同步。实际运行中,只要串口不丢字节,这个解析器是100%可靠的。

4.3 识别结果的异步处理

主循环里收到“识别成功”事件后,提取用户ID,查询在EEPROM/Flash中保存的用户权限表,决定是否放行。注意,人脸识别和密码/RFID的校验逻辑略有区别:人脸模组返回的ID是模组内部的用户索引,而门禁系统有自己的用户ID体系,所以中间需要一层映射。

我在设计里让模组用户ID就是从1开始的连续编号,而门禁系统的授权表采用“用户ID + 权限位 + 门禁时段”的结构。比如:

typedef struct { uint32_t user_id; uint8_t face_enable; uint8_t rfid_enable; uint8_t password_enable; uint8_t bt_enable; uint8_t time_slot; /* 索引到时间规则表 */ uint8_t is_admin; } AccessUser;

这样在新增一个用户时,管理员可以灵活指定他有哪些通道的权限。人脸识别成功只是通过了“脸”这个凭证,门禁系统还要看他是否有使用人脸开门的权限。这个设计在后期扩展用户管理时非常有用。

5. RFID与密码锁:RC522与矩阵键盘的完整实现

5.1 RC522的SPI初始化和M1卡操作

RC522是NXP的经典RFID读卡芯片,支持ISO/IEC 14443A协议的M1卡,比如常见的S50卡。STM32通过SPI接口访问RC522的寄存器,使用瑞萨/恩智浦官方提供的RC522驱动代码,把关键函数封装成3个接口:

  • RC522_Init():初始化SPI、复位RC522、设置天线增益
  • RC522_Request():请求寻卡,检测天线范围内是否有卡片
  • RC522_Anticoll():防碰撞,拿到卡片的唯一序列号(4字节)

卡片检测的典型时序是:

uint8_t rc522_check_card(uint8_t *card_id) { uint8_t status; status = RC522_Request(PICC_REQIDL); /* 寻卡 */ if (status == MI_OK) { status = RC522_Anticoll(card_id); /* 防碰撞,获取卡号 */ if (status == MI_OK) { /* 这里可以读取卡数据块的UID序列号 */ /* 然后执行Halt指令让卡片休眠 */ RC522_Halt(); return 1; } } return 0; }

处理卡号后要立即停止射频操作,即发送PICC_HALT命令,否则卡片会一直握手,影响下一次寻卡。很多初学者漏了这一步,结果发现第二张卡刷不进去。

5.2 卡号的存储与新增授权流程

卡号是4字节的UID,比如1A 23 45 67。授权卡号列表可以存在片上Flash的末尾扇区或外挂的AT24C02 EEPROM里。Flash的优点是省一个芯片,但有擦写寿命限制(F103的Flash擦写次数约1万次),如果需要频繁增删卡,推荐用EEPROM。

我处理的方式是:Flash专门开一个扇区来存“认证配置块”,每次改动先读出、修改、擦除扇区、写回。这个流程在写配置时要注意防止掉电丢数据——最简单的策略是“写前备份旧数据到下一个扇区”,掉电后上电检测到主扇区校验失败就自动从备份扇区恢复。

新增RFID卡的流程是:管理员密码验证通过 → 进入“发卡模式” → 新卡靠近 → RC522读到UID → 存入授权表 → 蜂鸣器提示成功。这类管理操作可以放在菜单逻辑里,配合密码键盘完成。

5.3 矩阵键盘扫描和密码验证逻辑

4x4矩阵键盘扫描的方法很常规:先将4根行线(PB0-PB3)设为输出低电平,4根列线(PB4-PB7)设为输入上拉,依次拉低每一行,检测列线是否被拉低。如果某一列被拉低,说明该行该列的键被按下。行扫描+列检测的代码如下:

uint8_t keypad_scan(void) { uint8_t row, col; for (row = 0; row < 4; row++) { GPIO_WriteLow(KEYPAD_ROW_PORT, row_mask[row]); for (col = 0; col < 4; col++) { if (GPIO_ReadInputDataBit(KEYPAD_COL_PORT, col_mask[col]) == RESET) { delay_ms(10); /* 消抖 */ while (GPIO_ReadInputDataBit(KEYPAD_COL_PORT, col_mask[col]) == RESET); return keymap[row][col]; } } GPIO_WriteHigh(KEYPAD_ROW_PORT, row_mask[row]); } return KEY_NONE; }

密码逻辑分几部分:输入状态机(等待密码长度、按#确认、按*清空)、密码校验(与存储的密码哈希比对)、连续错误锁定(5次失败锁60秒)。密码存储不要明文保存,我用的办法是CRC16+盐,即使Flash被读出来也还原不出原始密码。

5.4 密码锁与RFID的组合模式

在默认配置里,RFID和密码是“或”的关系:刷合法卡或输入正确密码都能开锁。但如果部署在安全等级高的场所,可以切换为“与”模式:必须先刷卡,然后在键盘上输入卡对应的PIN码,两者都通过才开锁。这个功能在代码里其实就是给状态机加一个STATE_AUTHENTICATING_MULTI_FACTOR状态,先缓存RFID卡号,再等待键盘输入密码,两件事都完成后合并校验。这就是多因素认证(MFA)在嵌入式设备上的一个典型实现。

6. 蓝牙App远程控制:自定义通信协议与手机端应用实现

6.1 HC-05模块的AT模式配置

HC-05是一款经典的蓝牙2.0 SPP模块,手机上用“蓝牙串口助手”类App就能连接。它默认是AT模式还是透传模式,主要看KEY引脚的电平:KEY接高电平后上电,进入AT模式;KEY接低电平或悬空,进入透传模式。

配置环节的关键步骤:

  1. 按住HC-05上的按钮上电,或者把KEY接3.3V再上电,模块LED慢闪表示进入AT模式
  2. 用USB-TTL连接模块,打开串口助手,波特率38400,发送AT,返回OK
  3. 设置名称:AT+NAME=SmartDoor
  4. 设置配对密码:AT+PSWD=1234
  5. 设置波特率:AT+UART=9600,0,0
  6. 断开KEY引脚,重新上电,进入透传模式

注意:HC-05的AT指令波特率经常被人忽略,新版本固件的AT波特率可能是38400,但透传波特率按AT+UART设置。如果连不上AT模式,先试试38400。

6.2 自定义协议格式设计

蓝牙通道的特点是:数据可以被第三方截获,所以协议里必须有基本的校验和安全设计。我的自定义协议帧格式:

起始符(0x5A) 帧类型(1字节) 数据长度(1字节) 数据区(不定长) 校验和(1字节) 结束符(0xA5)

帧类型定义:

帧类型值含义数据区内容
0x01开锁请求4字节时间戳
0x02心跳包1字节设备状态
0x03查询日志
0x04添加临时密码6字节新密码
0x05远程锁定
0x06开锁响应1字节结果+1字节剩余电量

校验和是“起始符+帧类型+长度+数据区”所有字节的累加取反。虽然不算高强度的加密,但足以防止普通串口调试工具伪造指令。真要安全,就要在上层加AES加密,STM32也能跑得动AES-128,只是代码量会翻倍,可以考虑为产品版本预留升级空间。

6.3 手机端App的实现思路

App端我用的是Android原生+一个蓝牙串口库(如经典的BluetoothSerial),核心流程很清晰:

  1. 扫描设备,找到名字为SmartDoor的HC-05
  2. 配对并建立SPP连接(UUID是00001101-0000-1000-8000-00805F9B34FB
  3. 发送开锁指令帧,等待STM32回响应帧
  4. 收到响应后根据结果弹提示

如果你不想写原生App,也可以直接用开源的“蓝牙串口助手”App,手动发送十六进制指令,把5A 01 04 A1 B2 C3 D4 校C 78 A5发出去就能开锁。对测试协议来说,这比开发App快得多。

App端的界面我做到了三个页面:

  • 主页:门锁状态显示、开锁按钮、远程锁定开关
  • 用户页:查看当前授权用户列表
  • 日志页:显示最近的开锁记录(这个需要STM32把日志存到Flash,再通过蓝牙查询指令传上来)

蓝牙操作的稳定性有个经验:HC-05透传数据时,STM32这边的接收中断里千万不能屏蔽全局中断太久。有一次我在USART2中断里调用了printf(内部阻塞等待串口1发送),结果蓝牙数据直接丢失,换来了一个很难查的问题。中断里只做收数据和置标志,其他的全部丢到主循环。

7. 系统联调中踩过的坑与最后的安全打磨

7.1 串口数据错乱和波特率匹配

联调时最容易出的问题就是人脸模组和蓝牙模块波特率不匹配。人脸模组默认是115200,蓝牙模块我配成9600。两个串口波特率不同,必须在STM32初始化时分别设置,别图省事直接用HAL_UART_Init的默认值。

还有一个隐蔽的坑:使用ST-Link离线下载程序会影响串口数据。ST-Link连在SWD引脚上时,如果软件里开了SWD调试、又同时跑着串口收发的话,ST-Link的复位和调试请求会和串口传输抢内部总线,导致串口数据出现随机错乱。解决办法是调试时不要直接用ST-Link的串口功能,也不要开着High priority的调试中断跑串口。

7.2 继电器控制电磁锁的反向电动势问题

这是项目里最危险的坑。刚开始测试时,我把继电器直接接在电磁锁上,发现STM32经常复位。用示波器看电磁锁断电瞬间,电源轨上出现了20多伏的毛刺。原因就是继电器切断感性负载的电流时,电磁锁线圈会瞬间产生高压反向电动势。

解决方案:

  • 继电器线圈两端并联1N4007续流二极管,阳极接GND,阴极接继电器控制端(对应电源正极)
  • 电磁锁本身并联一个RC吸收电路(如100Ω+0.1uF串联),吸收开关尖峰
  • 主控板供电和继电器驱动供电分开,共地但不共电源线,用光耦(如PC817)做隔离控制

经过这三层处理后,实测电磁锁反复开关上百次,STM32的供电非常干净。

7.3 安全策略:看门狗、失败锁定、事件日志

门禁系统是安防设备,安全性不能只看“能不能开锁”,还要看“开不了锁时怎么办”和“被攻击时怎么办”。

  • 独立看门狗(IWDG):在主循环里喂狗,一旦主循环卡死(比如内存溢出或死循环),看门狗自动复位整个系统,保证门禁不会因为程序异常永远瘫痪
  • 连续失败锁定:无论哪个通道,连续失败5次就锁定60秒,期间任何认证请求都不处理。防的就是暴力试密码和试卡
  • 事件日志:把每次开锁成功/失败、管理员操作、系统复位记录到Flash循环日志区。虽然STM32的Flash容量不大,但每条日志压缩成16字节,能存上千条,足够回溯最近使用情况

7.4 最终效果的实测和扩展方向

整机实测下来,人脸识别从检测到开门约2-3秒(模组的识别速度决定),RFID刷卡几乎是瞬时响应,蓝牙开锁受手机连接时间影响在1秒左右,密码开锁输入6位密码加确认约3秒。这个性能作为办公室门禁是完全够用的。

如果想把项目再往前推进一步,可以考虑这些扩展:

  • 加一块0.96寸OLED显示当前状态和用户信息,提升交互体验
  • 接入ESP8266/ESP32模块,把开门记录同步到云端,支持远程查看
  • 用FreeRTOS改造,增加电源管理,支持低功耗待机模式
  • 把密码和卡号换成更安全的算法,比如AES-128加密存储

根据我个人经验,这个项目的核心价值不在于“能跑通”,而在于把四种异构的外设认证方式统一到一个清晰的状态机框架里,同时在硬件上真正解决了干扰、电源和可靠性问题。如果你打算拿这套系统做毕业设计,代码结构和文档化的设计思路会比单纯的功能演示加分得多。祝调试顺利。

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

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询