这是个很典型的物联网方向毕业设计选题,一出来就有那种“既要能答辩、又要能演示、还要能跑通”的味道。STM32在这类项目里算是绝对主力,人脸识别负责“认人”,蓝牙负责“联动”,组合在一起就是一套多模态的门禁系统。和纯刷卡、纯密码的门禁相比,这套东西的好处就在于:它不是单一验证方式,而是能根据场景组合验证,既贴近实际产品,又比普通单片机课设高出不少技术含量。
我向来觉得,毕设这东西最怕的就是“看起来像玩具”。你用STM32点亮个OLED、按键控制个舵机,那叫课设;但一旦加入摄像头、人脸检测、无线联动、异常报警这些元素,整个系统的复杂度、知识覆盖面、可展示性就完全不一样了。这个题目选得聪明,它把嵌入式、图像处理、无线通信、传感器融合全串起来了,而且每一块都能单独拿出来讲,答辩的时候不怕没东西聊。
1. 系统整体方案设计与技术选型
1.1 多模态门禁到底在做什么
所谓多模态,绝不是把两个模块硬叠在一起就叫多模态。它的核心逻辑是:当多个信息来源相互印证时,系统的判断置信度会显著高于单一来源。
放在本系统里,具体场景是这样的:访客或用户站在门前,系统优先通过摄像头采集人脸图像,在本地完成人脸特征比对。如果比对分数超过阈值,主控直接驱动舵机/电磁锁开门。这是第一重验证,属于“生物特征”这一模态。如果人脸识别因为光线、遮挡、角度问题失败,系统不会立刻拒绝,而是自动切换/补足到第二重验证通道——手机蓝牙连接。用户手机通过蓝牙和门禁握手,门禁验证蓝牙MAC地址或加密令牌,验证通过后开门。这是第二重模态,属于“持有设备”验证。
更实际的场景是两者结合:人脸识别通过 + 蓝牙在范围内,双重确认后开门,用于高安全等级时段。人脸失败但蓝牙在范围内,可以降级为单重验证并生成一条日志。两者都失败,则触发蜂鸣器报警、摄像头抓拍,同时将告警记录写入本地日志。
这样一来,原先“刷脸失败就只能干瞪眼”的尴尬局面就解决了,系统可用性大幅提高。从毕设角度来讲,这也很好地向答辩老师展示了你对“冗余设计”和“多验证策略”的理解,而不只是把传感器插在开发板上跑通Demo。
1.2 为什么主控选了STM32而不是树莓派或ESP32
这是我反复权衡过的一个点。树莓派跑人脸识别确实性能碾压,OpenCV、dlib随便跑,但问题在于:它是Linux系统,启动慢、断电容易损坏SD卡、实时性不可控,而且很多学校实验室的电源环境并不稳定。作为毕设,它的“嵌入式感”会被削弱,答辩时老师容易把话题引到Linux应用层开发上,反而偏离了单片机系统的核心。ESP32虽然便宜、自带Wi-Fi和蓝牙,处理能力也比传统STM32强不少,但OpenCV级别的图像处理仍然吃力,跑轻量人脸检测模型也很勉强,加上摄像头接口方案偏复杂,并不适合做这种以“稳定演示”为目标的项目。
STM32的优势恰恰在于它的确定性:上电即跑、中断响应是微秒级、外设丰富,而且几乎所有物联网/嵌入式方向的课程都围绕它展开,调试工具、参考资料、例程代码极多。本设计选用STM32F407ZGT6作为主控,Cortex-M4内核带FPU,主频168MHz,SRAM达到192KB,Flash 1MB。这个配置在单片机里属于中高端了,人脸特征比对这种纯数学运算可以压在几十毫秒内完成。
人脸图像的采集和特征提取并不放在STM32上做,而是交给摄像头模块侧的协同处理器完成(下文详述)。STM32负责的是“控制”——读取识别结果、解析蓝牙指令、驱动外设、维护状态机、记录日志。这种“前端协同处理 + 主控决策控制”的架构,既避开了单片机算力不足的短板,又保留了单片机的实时性和稳定性。
1.3 整体架构与数据流向
系统的硬件拓扑是星型结构,STM32位于中心,外围挂着摄像头识别模块、蓝牙模块、舵机/电磁锁驱动、按键输入、OLED显示屏、蜂鸣器、LED指示灯。
数据流向分成两条链路。第一条是人脸识别链路:摄像头模块持续采集画面,内部运行人脸检测和特征提取,当检测到稳定人脸时,提取特征与本地注册的人脸特征库比对,然后把结果(通过/失败/未注册)通过串口发送给STM32。第二条是蓝牙链路:手机APP通过蓝牙模块与STM32建立连接,App端可以发送开门指令、添加用户、切换工作模式等;STM32也会把识别结果、门状态、日志事件推送到App显示。
两条链路在STM32内部汇聚,由主程序的状态机统一仲裁。这里有一个设计细节值得强调:人脸模块和蓝牙模块都走串口,但绝不能共用同一组USART,否则数据帧会互相干扰。我分配的是USART1接蓝牙(PA9/PA10,波特率9600或38400),USART2接摄像头模块(PA2/PA3,波特率115200),USART3预留用于调试日志输出(PB10/PB11,通过USB转TTL连接PC)。三个串口互不干扰,调试时用中断+DMA双缓冲接收,主循环里不做任何阻塞式串口读取。
2. 核心器件选型与关键参数分析
2.1 人脸识别模块:选TX510还是OpenMV
人脸识别模块的选择基本决定了整个项目的开发难度和稳定性。我对比了市面上常见的方案,最终推荐TX510人脸识别模块,理由如下:
TX510是一款集成了人脸检测、人脸比对、活体检测于一体的专用视觉模块,内部自带算力芯片,出厂即支持串口/韦根接口输出识别结果。它的工作流程是:模块上电后自动进入识别模式,摄像头视野中出现人脸时,模块会在本地完成检测、对齐、特征提取、比对,然后通过TX引脚输出识别结果数据帧。开发者不需要在STM32上跑任何图像算法,只需要解析串口数据即可。
它的关键参数对于嵌入式项目来说非常友好:
- 识别距离:0.3m ~ 1.5m,实测在0.4m ~ 1.2m范围内最稳定
- 识别速度:<500ms(本地比对)
- 人脸库容量:最多支持200张人脸(本设计注册10个用户绰绰有余)
- 通讯接口:UART TTL(3.3V),默认波特率115200
- 工作电压:5V(模块自带稳压,IO逻辑3.3V可与STM32直连)
相比之下,OpenMV虽然也可以做人脸识别,但它本质上是MicroPython环境下的开发板,需要自己调阈值、调特征质量,对光照非常敏感。而且OpenMV的 CPU 算力有限,人脸检测的帧率只有个位数,做演示时体验很差。如果非要用OpenMV,也不是不行,但你要接受“镜头一偏就检测不到人脸”“换个光线就识别失败”的实际情况。
还有一种思路是用ESP32-CAM + OpenCV跑在PC端,STM32通过串口和PC通信。这种方案技术深度最浅,因为图像处理全在PC上完成,单片机变成了纯粹的串口转发器。但从毕设角度,它不太像“嵌入式系统设计”,更像“Python课设套了个单片机壳子”。
所以我的明确建议是:用TX510或同类专用识别模块。它完美把STM32从“跑不动的图像处理”中解放出来,让主控专心干控制该干的事。
2.2 蓝牙模块:HC-05还是JDY-31
这个环节踩坑的人特别多。很多人在淘宝随手买了一个HC-05,结果连不上手机,怀疑模块坏了,其实是没搞清楚HC-05的进入AT模式方式和工作状态。
HC-05是经典的双模蓝牙2.0模块,支持主从一体,默认从机模式。它的AT指令配置相对成熟,网上资料极多,只要按住模块上的按键再上电,就能进入AT模式(此时指示灯慢闪),波特率默认38400。但HC-05的痛点在于:蓝牙2.0的兼容性差,新手机经常搜不到它;而且HC-05的蓝牙名称是“HC-05”,需要用AT命令修改。
JDY-31是基于蓝牙4.0 BLE的模块,兼容性远胜HC-05,功耗低,AT指令也更简洁。JDY-31默认波特率9600,进入AT模式只需把第2引脚(KEY)拉高再上电。实测下来,JDY-31和手机App(如BLE调试助手或自己写的App)的连接稳定度明显高于HC-05。
如果追求更好的扩展性,直接用ESP32做蓝牙协处理器也是一种方案——ESP32同时支持BLE和Wi-Fi,以后想加手机局域网控制、MQTT上云都很方便。但在本设计中,为了控制复杂度,建议先用JDY-31把蓝牙链路跑通,后续再做升级。
蓝牙模块的核心参数关注点如下:
| 参数 | HC-05 | JDY-31 |
|---|---|---|
| 蓝牙版本 | 2.0 | 4.0 BLE |
| 默认波特率 | 9600 / 38400 | 9600 |
| AT模式进入方式 | 按住按键上电 | KEY引脚拉高上电 |
| 手机兼容性 | 较差 | 很好 |
| 模块价格 | 约15元 | 约12元 |
| 适用场景 | 老旧设备互连 | 手机App联动 |
2.3 舵机与电磁锁的选型问题
门禁的执行机构有两种常见选择:舵机和电磁锁。
舵机(SG90或MG996R)的好处是模拟了真实门锁的转动过程,演示效果好,用PWM就能精确控制角度,而且安全、不会夹手。SG90扭矩约1.8kg·cm,够带动一个轻质有机玻璃门闩,但推动真实锁舌略显吃力。MG996R扭矩约11kg·cm,金属齿轮,力量足够,但需要5V/2A以上的外部供电,绝不能直接从STM32开发板的5V引脚取电,否则瞬间压降会直接导致主控复位。
电磁锁(12V单门磁力锁或电插锁)更接近真实门禁,断电开锁/通电开锁两种类型要分清。毕设场景下我建议用“通电开锁、断电闭锁”的电磁锁,因为如果断电反而开锁,实验时掉电门就开了,会造成安全隐患。但电磁锁需要12V供电,必须额外配一个继电器模块或者MOS管驱动电路,由STM32的GPIO控制。需要特别注意电磁锁关断时的反向电动势:继电器关断瞬间会产生高压尖峰,如果不加续流二极管,轻则干扰系统,重则击穿MOS管。我实际测试中发现,在继电器线圈两端并联一个1N4007二极管之后,系统稳定性提升非常明显。
如果演示环境是实验室的亚克力门模型,舵机完全够用且更直观;如果想做成挂在门上的真实门禁,电磁锁更有说服力。两者的驱动方式我都写在后面的接线说明里。
3. 硬件搭建与电路设计实战
3.1 电源系统:为什么必须分路供电
这是新手最容易翻车的地方。整个系统里有三个电压等级:STM32和传感器需要3.3V/5V,舵机需要5V且电流峰值可能到1A以上,电磁锁需要12V。如果全部从USB口取电,USB能提供的电流只有500mA,舵机一启动、电流一冲,整个系统就掉电重启了。
我的做法是三级供电架构:
- 输入电源:12V/2A DC电源适配器,作为系统总电源
- 一级降压:通过MP1584或LM2596降压模块,先将12V降压到5V/3A,给STM32、蓝牙模块、人脸模块供电
- 二级降压:STM32板载AMS1117-3.3稳压产生3.3V,给OLED、TX510的IO逻辑供电
舵机直接接在12V转5V降压模块的输出端,但要注意:降压模块的电流至少要3A,否则大扭矩舵机转速时电压波动会传导到STM32供电线上。如果条件允许,建议把舵机供电的5V和主控供电的5V完全分开,用两个独立降压模块,地线在末端单点相连。这叫“功率地与信号地分离”,在电机控制里是基本功。
电磁锁则直接接12V输入端,通过继电器控制通断,不经过降压模块。
3.2 最小系统接线速查表
下面这张表是我整理好的接线清单,照着接基本不会错:
| 模块 | STM32引脚 | 说明 |
|---|---|---|
| TX510人脸模块 TX | PA3 (USART2_RX) | 识别结果数据输入 |
| TX510人脸模块 RX | PA2 (USART2_TX) | 控制指令输出 |
| TX510 VCC / GND | 5V / GND | 模块供电 |
| JDY-31蓝牙 TXD | PA10 (USART1_RX) | 手机指令输入 |
| JDY-31蓝牙 RXD | PA9 (USART1_TX) | 数据发送给手机 |
| JDY-31 VCC / GND | 3.3V / GND | 注意:接5V会烧! |
| 舵机信号线 | PB1 (TIM4_CH3) | PWM控制 |
| 蜂鸣器 | PB12 | 高电平触发 |
| 继电器控制脚 | PB13 | 控制电磁锁 |
| OLED SDA | PB7 | I2C数据 |
| OLED SCL | PB6 | I2C时钟 |
| 按键1 | PE0 | 注册模式 |
| 按键2 | PE1 | 普通/安全模式切换 |
| 按键3 | PE2 | 手动开锁 |
3.3 舵机的PWM频率与角度控制
舵机控制是STM32里最基本但最容易出问题的PWM应用。SG90的工作脉冲周期是20ms(50Hz),高电平脉宽决定角度:0.5ms对应0°,1.5ms对应90°,2.5ms对应180°。
配置STM32定时器时,我选用TIM4的通道3(PB1),设置预分频器PSC为168-1,自动重载值ARR为2000-1。此时定时器计数频率为168MHz/168=1MHz,即1us计数一次;ARR=2000对应一个周期为2000us(2ms),输出PWM频率为500Hz,注意这里不是50Hz,但实际测试中依然能驱动舵机,原因在于舵机内部电路对脉宽更敏感。
稳妥起见,我建议这样计算:PSC设置为168-1,ARR设置为2000-1,然后CCR值的范围是50~250,对应0.5ms到2.5ms脉宽。也就是说:
- CCR = 50 → 0°
- CCR = 150 → 90°
- CCR = 250 → 180°
这样配置的精度是1us,对应约0.09°,完全够用。舵机从0°转到180°大约用时0.3s,开门动作做成“先转到120°→保持1s→归位到20°→保持”,这样看起来更自然,也不会让舵机长时间堵转发热。
4. 软件架构与核心代码实现
4.1 裸机状态机设计:不要用延时函数堆逻辑
很多同学写单片机程序的习惯是:一个while循环里不断查询传感器状态,遇到条件就调用延时函数。这在纯传感器Demo里问题不大,但到了多外设交互的门禁系统里,延时函数会直接毁掉整个系统——当程序在delay_ms(500)的时候,蓝牙数据帧来了无人解析,人脸识别结果来了没有人接收,OLED刷新也全卡住。
本设计采用“软件状态机 + 定时器节拍”的方式来组织代码。整个系统运行在10ms一个Tick的时基上,主循环只做三类事:
- 查询状态机的当前状态,根据状态执行对应的动作
- 查询串口接收缓冲区是否有完整数据帧,有则解析
- 刷新OLED显示(2Hz频率,减少I2C通信对总线的占用)
这里给出核心状态机的定义示例:
typedef enum { SYS_STATE_INIT = 0, // 上电初始化 SYS_STATE_IDLE, // 空闲监控 SYS_STATE_RECOGNIZING, // 人脸识别中 SYS_STATE_BT_AUTH, // 蓝牙认证中 SYS_STATE_DUAL_AUTH, // 双重验证 SYS_STATE_OPENING, // 开门动作 SYS_STATE_ALARM, // 告警状态 SYS_STATE_REGISTER // 注册新用户 } sys_state_t; sys_state_t current_state = SYS_STATE_INIT;状态机的迁移条件是核心逻辑,用一张简表来说明:
| 当前状态 | 触发条件 | 迁移到状态 |
|---|---|---|
| INIT | 初始化完成 | IDLE |
| IDLE | 检测到人脸且质量OK | RECOGNIZING |
| IDLE | 手机蓝牙配对成功 | BT_AUTH |
| RECOGNIZING | 人脸比对通过 | OPENING |
| RECOGNIZING | 人脸比对失败且无蓝牙 | ALARM |
| RECOGNIZING | 人脸比对失败但有蓝牙 | BT_AUTH |
| BT_AUTH | 蓝牙令牌正确 | OPENING |
| BT_AUTH | 蓝牙令牌错误 | ALARM |
| OPENING | 开门动作完成 | IDLE |
| ALARM | 时间到达或按键复位 | IDLE |
4.2 串口DMA双缓冲:接收不丢一帧数据
这是本项目里我认为最值得Nail的技术细节。TX510人脸模块和JDY-31蓝牙模块都是串口主动上报数据的设备,数据什么时候来完全是随机的。如果主循环每10ms才去查一次接收寄存器,当设备数据在两次查询之间到达,数据就可能被覆盖或漏读。
用USART空闲中断 + DMA接收是标准的解决方案。核心思路是:DMA自动把串口收到的数据搬运到内存缓冲区,CPU完全不参与;当一帧数据发送完毕(总线空闲一个字节时间),USART空闲中断触发,此时CPU才在中断里把DMA收到的数据处理掉。
可以参考这样的配置流程:
// 以USART1(蓝牙)为例 // 1. 配置DMA2_Stream2,通道4对应USART1_RX // 2. 设置DMA接收缓冲区 uint8_t usart1_rx_buf[128]; // 3. 使能USART1空闲中断和DMA接收 // 4. 在空闲中断中处理数据 void USART1_IRQHandler(void) { if (USART_GetITStatus(USART1, USART_IT_IDLE)) { USART_ReceiveData(USART1); // 清除空闲标志 // 获取实际接收字节数 uint16_t rx_len = 128 - DMA_GetCurrDataCounter(DMA2_Stream2); if (rx_len > 0) { process_bluetooth_frame(usart1_rx_buf, rx_len); } // 重新开启DMA接收 DMA_Cmd(DMA2_Stream2, DISABLE); DMA_SetCurrDataCounter(DMA2_Stream2, 128); DMA_Cmd(DMA2_Stream2, ENABLE); } }这种做法的好处是:主循环完全不会被高频串口数据拖慢,DMA搬运数据不占用CPU时间,数据一帧不丢。实测在TX510以最高频率持续输出识别结果、蓝牙同时传输大块数据的情况下,系统依然稳定运行。
4.3 数据帧协议设计:如何区分人脸、蓝牙和日志
多个串口设备接入后,最需要提前设计的就是数据帧协议。如果各设备的数据格式不统一,后续代码会越写越乱。我的做法是统一采用“帧头 + 设备ID + 数据长度 + 数据域 + 校验”的格式:
typedef struct { uint8_t frame_header; // 0xAA uint8_t device_id; // 0x01=人脸模块 0x02=蓝牙 uint8_t data_len; // 数据长度 uint8_t data[8]; // 数据域 uint8_t checksum; // 校验和:从帧头到数据域末的所有字节累加 } protocol_frame_t;人脸模块的识别结果数据域设计为:第一个字节表示识别结果(0x00=无脸、0x01=通过、0x02=失败、0x03=未注册用户),第二到第五字节表示用户ID(小端模式),第六字节表示相似度分数(0~100),这样在OLED上可以显示“User 3: 87%”这种直观信息。
蓝牙指令域设计为:第一个字节表示指令类型(0x01=开门、0x02=注册请求、0x03=切换模式、0x04=查询状态),第二个字节是参数(如注册模式下的用户ID、切换后的模式值),其余字节预留。手机App发送“0xAA 0x02 0x02 0x01 0x01”这样的帧,STM32解析后执行对应动作。
校验和的算法很简单:checksum = sum(全部字节) & 0xFF,接收端相同算法计算,如果不一致直接丢弃这一帧,不执行任何操作。这样能有效防止串口干扰导致的误动作。
5. 人脸识别与门禁联动逻辑实现
5.1 人脸注册流程:为什么先用串口工具测试
TX510模块拿到手先别急着焊到板子上。我强烈建议先在PC上用USB转TTL工具单独调通这个模块,确认它的数据格式后再接入STM32。
具体做法是:把TX510的TX/RX通过USB转TTL连到PC,打开串口助手(波特率115200),上电后可以看到模块不断输出实时检测数据。当人脸出现在视野里,串口会喷出一帧带有人脸检测框坐标和置信度的数据。此时向模块发送注册指令,模块会连续采集3张不同角度的人脸照片,提取特征存入Flash。
这里有一个非常关键的操作细节:注册用户时,人脸必须正对摄像头,保持约50cm距离,光照不能太暗也不能逆光,并且表情要自然。如果注册时采集到的人脸质量差,后续识别时无论光线多好都认不出来。这就像身份证照片拍糊了一样,后期再怎么处理都白搭。
TX510的串口指令格式可以在模块的数据手册里查到,核心就两类:
- 注册指令:向模块指定用户ID开始注册
- 删除指令:删除指定用户ID的特征数据
我在PC端全部验证通过后,才开始写STM32对接代码。这个习惯帮我省了大量的排查时间。
5.2 蓝牙配对与数据交互:JDY-31的AT指令坑
JDY-31在默认透传模式下,只要手机连接上模块,双方数据就是透明传输的,看起来很简单。但要想修改设备名称、设置PIN码、调整广播间隔,就必须进入AT模式。
JDY-31的AT模式进入方法是:将KEY引脚(第2脚)接到3.3V,再给模块上电。此时模块工作波特率固定为9600,发送“AT+”开头的指令。常用指令如下:
AT+NAME设置蓝牙名称,比如返回OK+Set:MyDoorLockAT+PIN设置配对PIN码AT+BAUD修改波特率,比如AT+BAUD8对应115200AT+ROLE设置主从模式,默认从机即可
设置完名称和PIN码后,把KEY引脚恢复低电平,重新上电,模块就进入正常工作状态。注意修改波特率后,STM32的串口初始化参数也要同步修改,否则两边速率不匹配,接收到的全是乱码。
我在实际测试中还发现一个现象:JDY-31在手机连接后,模块与手机之间大约每100ms会进行一次BLE心跳通信,此时如果STM32的串口中断优先级设置太低,偶发会丢失一两个字节。处理办法是把USART1中断优先级提高到2(NVIC抢占优先级),同时给蓝牙数据帧加上校验和,即使偶尔丢帧也能被识别并丢弃,不会误开门。
5.3 双通道仲裁:人脸和蓝牙同时触发的处理策略
多模态系统的核心价值在于“可以用多种方式开门”,但随之而来的问题是:当人脸识别通过的同时,手机蓝牙也发来了开门指令,系统该听谁的?
答案不是“谁先到听谁的”,而是要在代码里定义明确的仲裁规则。我设计的仲裁逻辑如下:
// 在状态机IDLE状态下集中处理外部事件 if (face_result == RESULT_PASS && bt_cmd.open_request) { // 人脸通过 + 蓝牙请求 → 双重确认 unlock_door(UNLOCK_MODE_DUAL); } else if (face_result == RESULT_PASS && !bt_cmd.open_request) { // 仅人脸通过 → 单重验证,记录日志 unlock_door(UNLOCK_MODE_FACE); } else if (face_result != RESULT_PASS && bt_cmd.open_request) { // 人脸不通过,但蓝牙认证通过 → 允许降级开门 // 但要在OLED和App都提示“face fail, bluetooth open” unlock_door(UNLOCK_MODE_BT); } else { // 全部失败 → 告警 trigger_alarm(ALARM_REASON_BOTH_FAIL); }这种仲裁策略的实际意义是:人脸识别作为首选的生物特征识别,蓝牙作为兜底验证手段,两者都能开门但会在日志中留下不同的验证方式标记。从安全角度讲,如果设置了“安全模式”,则必须双重验证通过才开门;如果处于“普通模式”,则可以单重验证开门。
这个逻辑看起来简单,但真正在代码里实现时需要小心:蓝牙指令是异步到达的,不能在一个串口中断回调里直接执行舵机控制。正确做法是把蓝牙指令解析后存入一个全局结构体,设置标志位,主循环在状态机空闲状态时再去读取这些标志并执行动作。
6. 系统联调、测试与常见问题排查
6.1 分模块测试:先保证每个外设单独能跑
不要一开始就把所有外设都堆在一起联调,否则出了问题根本定位不了原因。我的测试顺序是:
- 单独测试OLED显示:上电能显示文字、刷新正常
- 单独测试舵机转动:PWM输出角度准确,无抖动,电源稳定
- 单独测试TX510人脸识别:用串口助手看识别结果,注册3个人脸
- 单独测试JDY-31蓝牙:用手机连接,透传字符串能收到
- STM32对接TX510:串口助手验证STM32能正确解析模块数据帧
- STM32对接蓝牙:手机App发送指令,STM32能识别并执行
- 全部联动:上电完整流程验证
每完成一步,就把该模块的代码固化备份,然后再进入下一步。如果最后出了问题,至少可以二分法排查是哪一步引入的。
6.2 那些把人逼疯的常见故障
结合我这次开发和给朋友调试的经验,下面的故障速查表基本能覆盖90%以上的问题场景:
| 现象 | 可能原因 | 解决办法 |
|---|---|---|
| 蓝牙搜不到模块 | 模块没有上电或进入AT模式未退出 | 检查VCC是否在3.3V,重新上电 |
| 蓝牙连接后乱码 | 波特率不匹配 | 确认模块与STM32串口波特率一致 |
| 人脸识别一直报失败 | 注册时图像质量差 | 删除人脸重新注册,改善光照 |
| 舵机抖动不转 | 供电电流不足 | 改用独立5V电源,加1000uF电容 |
| 识别结果偶尔丢 | 串口中断被其他中断抢占 | 提高串口中断优先级 |
| OLED花屏 | I2C速率过快或接线过长 | 降低I2C时钟到200kHz,缩短杜邦线 |
| 上电后系统反复重启 | 电机/舵机启动瞬间拉低电压 | 功率地和信号地分开,换大电流电源 |
| 蓝牙App收不到状态推送 | STM32发送数据但模块未连接 | 先判断模块Link指示灯,检查连接状态 |
6.3 让系统更接近真实产品的三个小升级
如果时间和预算允许,这里还有三个性价比很高的升级方向,能让整个系统更像真正的产品级门禁:
第一个是增加离线日志存储。STM32F407有一块后备寄存器区和若干内部Flash页,可以把每次开门记录、报警记录、错误信息擦写到内部Flash的固定区域。就算断电,下次上电还能查询到历史记录。无需外挂EEPROM,免费功能不用白不用。
第二个是增加异常状态上报。当系统连续检测到多次人脸识别失败时,可以向蓝牙连接的手机推送“疑似非法尝试”的告警信息。配合蜂鸣器报警,整个安防逻辑就非常完整了。
第三个是外观设计。很多同学的毕设堆在开发板上显得很凌乱,但其实只要花20块钱打一块亚克力外壳、用3D打印一个门禁盒子,把开发板藏起来,外露OLED和摄像头,整体效果立刻提升一个档次。答辩时评分老师第一眼看的是整体形态,形态过关了,功能讲解才容易被认可。
7. 从毕设到创新点的延伸
很多同学担心做了这个题目会不会“撞车”。说实话,STM32加蓝牙加门禁的选题确实不少,但同样题目做出来的深度可以天差地别。如果你希望在这个基础上再挖深一点,有几个方向可以尝试:
一个是加云平台。用ESP32作为Wi-Fi协处理器,通过MQTT接入云平台(如阿里云IoT或其他开放IoT平台),实现手机App远程查看门禁日志、远程授予临时开门权限。这个方向能把你从纯粹的嵌入式扩展到物联网全链路,价值很高。
另一个是叠加传感器融合。在门禁周围加一个红外人体感应模块,当有人接近时才启动人脸识别,没人时让模块休眠——这不仅仅是在省电,还能延长人脸模块的寿命,更符合实际产品的运行逻辑。
还有人脸活体检测。TX510本身支持简单的活体检测,可以区分照片和真人,但如果想把这一点作为创新点,可以在论文里详细阐述活体检测的原理、实现方式、以及如何通过多帧图像时序判断来提升检测率。
做完这个项目之后,我对整个嵌入式系统设计的理解其实发生了不小的变化。以前觉得写代码驱动外设、点亮屏幕就算掌握了单片机,但真正做多外设协作的系统才知道,串口协议设计、状态机划分、电源分配、信号完整性才是决定系统稳不稳定的核心因素。STM32只是载体,真正值钱的是“让多个模块有序协作”的能力,这东西在工程实践里比会调任何一个API都重要。这套系统后续想扩展远程管理、联动安防报警、集成云平台,底层思路基本都不需要推翻重来。