做单片机毕设这些年我经手的题目少说也有二十多个STM32 智能婴儿床系统是回头率最高的一类——题目听着温和做起来坑一个接一个。前年帮学弟改代码凌晨两点他发消息说电机一转 STM32 就重启今年又有人在群里问 HX711 数值乱跳怎么压。这两个问题几乎成了这个题目的固定节目。这篇就把我带学生从定需求、选器件、画板子、写代码一路到答辩演示的全过程摊开讲包括那些手册上不会写、只有焊过板子调过夜的人才知道的细节。如果你正在做基于 STM32 的智能婴儿床系统或者手里拿着单片机毕设题目还没想好怎么落地这篇可以当成一份施工图来看——它不只是一份器件清单而是一套可以照着复现、也能撑得住答辩追问的完整方案。1. 项目整体设计与方案拆解1.1 先把智能两个字拆成能落地的功能点很多同学一上来就想着做 App、做云平台、做 AI 识别结果做到一半发现连温湿度都读不稳。我的建议是先做减法把智能婴儿床系统拆成感知、执行、交互三层每层只留三到四个必须实现的功能其余作为加分项排在后面。感知层包括床内温湿度、婴儿是否在床称重或压力检测、哭声检测、尿湿检测执行层包括摇床电机、白噪音播放、夜灯交互层包括本地 OLED 显示、按键设置、以及一个能把数据推出去的联网/蓝牙通道。这样拆完你会发现真正吃时间的不是智能部分而是感知层的稳定性和执行层的电源干扰问题。拆功能的时候还要给每个功能定一个可量化的验收标准这是答辩时最容易被追问的地方。温度精度说±0.5℃以内响应时间说2 秒内更新哭声检测说3 米内正常室内噪声环境下误报率低于 10%摇床说摆幅 10 到 20 毫米、频率 0.5 到 1Hz 可调。有了这些数字你的方案选型才有依据答辩老师问为什么用这个传感器你也能答得上来。注意这个题目涉及婴幼儿场景作品定位一定要说清楚是教学演示与原理验证不能宣称可以直接用在真实婴儿身上。真实婴幼儿产品需要经过严格的安全与可靠性验证毕设阶段把功能跑通、把原理讲清楚就够了这一点在答辩开场主动说明反而会加分。1.2 主控选型为什么 STM32F103C8T6 依然是性价比最优解市面上能选的单片机很多51、STC、STM32G0、STM32F4 都能做这个题目但对毕设来说STM32F103C8T6几乎是默认答案理由很实在。第一是资源够用72MHz 主频、64KB Flash、20KB SRAM跑一个前后台程序加 OLED 显示、串口通信、PWM 输出完全没压力20KB 的 RAM 还能省出空间做 256 点 ADC 缓冲和简单 FFT。第二是外设齐全3 个通用定时器加 1 个高级定时器意味着你可以把系统滴答、PWM 输出、ADC 触发三个时间基准完全分开互不干扰这在多任务场景下非常关键。第三是生态这一点对毕设来说比性能重要得多。F103 的 HAL 库、标准库资料满天飞CubeMX 一键生成初始化代码遇到问题随便一搜就有人踩过同样的坑。相比之下 STM32G0 虽然更新更省电但网上现成的例程少一半你可能要花两周在查手册上。至于 51 单片机虽然便宜但它没有 DMA、没有硬件 PWM 多通道、ADC 还得外挂做到后面会非常别扭。如果要升级STM32F407VET6 是第二个选择主频 168MHz带 FPU做浮点 PID 和 FFT 会轻松很多价格也就贵二十来块。我的经验是如果你打算做哭声频谱分析或者加 FreeRTOS直接上 F407别在 F103 上硬扛浮点运算。如果只是阈值判断加简单滤波F103 足够。1.3 系统分层架构与数据流向整个系统的数据流可以这样理解传感器层每 100ms 采集一轮数据进入滤波与标定层然后送进状态机决策层状态机根据当前状态决定要不要启动摇床、要不要播放白噪音、要不要报警最后通过显示层和通信层把结果输出给人看。这个分层最大的好处是解耦——传感器坏了只影响采集层逻辑改需求只动状态机界面换风格只改显示层。状态机我一般定义四个状态SYS_MONITOR静默监测、SYS_SOOTHE安抚中摇床或白噪音开启、SYS_ALARM异常报警比如温度超限或长时间哭闹、SYS_IDLE待机无人时低功耗运行。状态之间的跳转条件就是你的核心业务逻辑写清楚了代码自然就出来了。这里要特别注意防抖与去回跳哭声检测不能一检测到就报警要连续满足条件 5 秒才切换状态温度报警要有 0.5℃ 的回差值否则会在阈值附近反复横跳继电器和电机被来回触发噪音大还伤器件。2. 硬件电路与关键参数计算2.1 电源树设计从 12V 到 3.3V 的每一步电源是这个项目最容易翻车的地方因为床上同时存在大电流的电机和小信号的传感器。我的方案是外部 12V/2A 适配器进来第一路直接喂给电机驱动第二路经 MP1584 或 LM2596 降压到 5V再经 AMS1117-3.3 稳到 3.3V 给 MCU 和传感器。关键点是电机的地和 MCU 的地一定要在电源入口处单点汇合不要让电机电流从 MCU 的地线上走否则电机启动瞬间地电位抬升MCU 直接复位。参数上MP1584 是开关电源效率高但纹波大输出端要并 220μF 电解加 0.1μF 陶瓷电容AMS1117 是线性稳压纹波小但压差大、发热明显5V 降到 3.3V 时压差只有 1.7V电流 200mA 以内问题不大但如果你接了 ESP8266 这种瞬时电流能到 300mA 的模块AMS1117 就会明显发烫建议换成 SPX3819 或 MP2359。电机驱动电源输入端一定要并一个 470μF 以上的电解电容作用是吸收电机换向时产生的反向电流尖峰。提示测电源纹波别用万用表看的是平均值看不出尖峰。用示波器、探头用弹簧地针在电机正反转瞬间抓波形你会看到几伏的尖峰——这就是 MCU 复位的真凶。2.2 传感器接口电路几个模块的取舍逻辑温湿度方面DHT22 便宜但单总线时序对延时敏感中断一频繁就容易读失败SHT30 走 I2C精度 ±0.2℃、响应快、完全不吃时序我强烈推荐 SHT30。它需要 4.7kΩ 上拉电阻一般模块已经自带。如果你手上只有 DHT22务必把读数据过程放在关中断的临界区里整个时序大概 5ms关中断不会影响其他任务。在床检测我试过三种方案。红外对管便宜但容易被床围遮挡薄膜压力传感器灵敏但一致性差最终选了20kg 量程的电阻应变片称重传感器加 HX711理由是它能同时给出在不在床和体重变化两个信息答辩时能多讲一个数据维度。这里有个选型坑很多人买 5kg 量程的结果婴儿加床垫加支架一压就超量程。婴儿体重按 10kg 算床垫支架按 5kg 算留一倍余量20kg 才是安全选择。关于 HX711 的精度5kg 传感器灵敏度典型值 1mV/V激励 5V 时满量程输出 5mV配 128 倍增益差分输入范围 ±20mV刚好匹配24 位 ADC 理论分辨率极高但实际有效位数在 19 到 20 位之间换算到 20kg 量程上静态稳定精度大约在 1 到 2 克足够判断有没有人。哭声检测用 MAX9814 麦克风模块最省事它自带 AGC 和 60dB 增益模拟输出直接接 ADC。采样率设 8kHz用定时器触发 ADC 加 DMA 搬运 256 点缓冲然后在主循环里算短时能量和过零率。人耳对 300 到 3000Hz 最敏感婴儿哭声能量集中在 400 到 800Hz 附近做个粗略的带通或者只看总能量配合持续时间判断就够了上 FFT 属于加分项。还有一个更便宜的方案是 LM393 比较器输出的声音模块只有一个数字量抗干扰差不建议单独用。2.3 摇床机构的参数计算摆幅和频率怎么定摇床是这个项目里唯一有机械运动的部分参数算错要么不动要么晃得吓人。常见结构是直流减速电机加偏心轮加连杆摆动角度由偏心距和连杆长度决定。假设偏心距 e 15mm摆杆有效长度 L 300mm那么单侧摆角 θ arcsin(e/L) arcsin(0.05) ≈ 2.87°全摆角约 5.7°横向振幅 A L × sin(θ) ≈ 15mm。这个幅度大概是成人轻拍的力度比较合适如果偏心距做到 30mm振幅翻倍到 30mm看起来就会有点夸张。频率方面成人哄睡摇动大概每分钟 30 到 60 次也就是 0.5 到 1Hz。如果你买的是 1:100 减速比的直流电机输出轴空载转速约 100rpm也就是 1.67Hz稍快用 PWM 把占空比压到 30% 到 40%转速降到 50 到 60rpm正好落进目标区间。这里就必须算 PWM 频率了STM32F103 的 TIM3 挂在 APB1 上定时器时钟 72MHz预分频 PSC 设为 71计数器时钟就是 1MHz要得到 20kHz 的 PWMARR 1 1MHz / 20kHz 50所以 ARR 49。为什么是 20kHz 而不是 1kHz因为 1kHz 落在人耳可听范围内电机会发出明显的滋滋啸叫夜里特别刺耳20kHz 超出人耳听觉上限安静得多而且这个频率下电机电流连续转矩更平顺。前提是你的驱动芯片能跟上——TB6612 支持到 100kHz没问题L298N 内部是双极性晶体管开关损耗大20kHz 下会明显发热建议降到 8 到 10kHz或者干脆换 TB6612。2.4 原理图与 PCB 布局的几个关键动作如果时间允许强烈建议把这个项目做成一块自制 PCB答辩时实物的完成度会直接拉高一个档次。布局上有几条硬规矩电机驱动部分和 MCU 部分物理分开至少隔 10mmHX711 是 24 位 ADC它的模拟输入走线要短、要等长、要远离任何 PWM 走线最好在它下面铺完整的模拟地晶振尽量靠近 MCU 引脚下面不要走任何信号线所有 I2C 和 SPI 走线控制在 10cm 以内。还有一个容易被忽略的点给电机加续流二极管。直流电机是感性负载断电瞬间会产生反向电动势虽然驱动芯片内部一般有体二极管但外并一个 SS34 肖特基会更稳。同时电机两端并 0.1μF 陶瓷电容做火花抑制能显著降低对麦克风和称重传感器的干扰。3. 软件架构与关键代码实现3.1 开发环境搭建与工程配置工具链我用的是 Keil MDK5 加 STM32CubeMX这套组合对毕设最友好。CubeMX 负责时钟树、引脚分配和外设初始化生成 HAL 库工程Keil 负责写业务代码和下载调试。注意一个细节大部分同学电脑上同时装了 Keil C51 和 MDK两个版本如果装在同一目录会互相覆盖导致 STM32 的芯片包丢失装的时候一定要分开路径。CubeMX 里记得生成单独的 .c/.h 文件对不要全塞进 main.c后期改代码会痛苦。时钟树配置上F103 用外部 8MHz 晶振经 PLL 倍频到 72MHzAPB1 分频系数 2 得 36MHz但定时器时钟会自动二倍频回 72MHz这一点在算 PWM 频率时千万不能记错否则算出来的 ARR 会差一倍。调试接口保留 SWD占用引脚少还能直接用 ST-Link 在线看变量。3.2 时间片调度框架与状态机落地不用 RTOS 也能做出很清晰的结构核心是定时器打节拍主循环跑任务。我用 TIM2 做 1ms 系统滴答在中断里只做计数和标志置位绝不做耗时操作volatile uint32_t g_tick 0; volatile uint8_t flag_10ms 0, flag_100ms 0, flag_1s 0; void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim) { if (htim-Instance TIM2) { g_tick; if (g_tick % 10 0) flag_10ms 1; /* 按键扫描 */ if (g_tick % 100 0) flag_100ms 1; /* 传感器采集 */ if (g_tick % 1000 0) flag_1s 1; /* 数据上报 */ } }主循环里按标志位执行标志位用完就清零。这种写法最大的好处是每个任务的时间间隔确定传感器采样周期稳定滤波算法的系数才有意义。很多人把HAL_Delay散落在各处结果一个传感器读 2 秒整个系统就卡 2 秒按键都按不动。状态机用 switch 实现配合超时计数器做去抖typedef enum { SYS_IDLE, SYS_MONITOR, SYS_SOOTHE, SYS_ALARM } SysState_t; void Sys_StateMachine(void) { switch (g_state) { case SYS_MONITOR: if (Cry_Detect_Confirmed(5)) { /* 连续5秒确认 */ Rock_Start(40); /* 40% 占空比软启动 */ Music_Play(TRACK_LULLABY); g_state SYS_SOOTHE; } if (Temp_OutOfRange(0.5f)) g_state SYS_ALARM; break; case SYS_SOOTHE: if (!Cry_Detect_Confirmed(3)) { /* 3秒无哭声停 */ Rock_Stop(); Music_Stop(); g_state SYS_MONITOR; } break; /* 其余状态略 */ } }Cry_Detect_Confirmed(n)内部维护一个秒计数器只有连续 n 次判定为哭声才返回真这样能滤掉偶发的关门声、咳嗽声。3.3 三个关键驱动HX711、SHT30 与 PWM 摇床HX711 的读取时序不难但要注意第 25 个脉冲决定下一次转换的增益通道写错的话读数会莫名其妙偏一半long HX711_Read(void) { uint32_t val 0; while (HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_0) GPIO_PIN_SET); /* 等 DOUT 拉低 */ for (uint8_t i 0; i 24; i) { HAL_GPIO_WritePin(GPIOB, GPIO_PIN_1, GPIO_PIN_SET); val 1; if (HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_0) GPIO_PIN_SET) val; HAL_GPIO_WritePin(GPIOB, GPIO_PIN_1, GPIO_PIN_RESET); } /* 第25个脉冲1个增益1282个323个64 */ HAL_GPIO_WritePin(GPIOB, GPIO_PIN_1, GPIO_PIN_SET); HAL_GPIO_WritePin(GPIOB, GPIO_PIN_1, GPIO_PIN_RESET); if (val 0x800000) val | 0xFF000000; /* 补码转换 */ return (long)val; }采样策略上HX711 用 10Hz 输出速率就够引脚配置为低电平连续采 8 次去掉最大最小再平均配合上电第一次读数作为去皮零点。别小看这个去极值平均实测能把抖动从 ±30 个计数值压到 ±8 以内。SHT30 走 I2C命令 0x2C06 触发单次测量等 15ms 再读 6 字节前 3 字节温度、后 3 字节湿度加 CRC8 校验。转换公式temperature -45.0f 175.0f * (raw_temp / 65535.0f); humidity 100.0f * (raw_humi / 65535.0f);PWM 启动和软启动斜坡是这样写的加斜坡是为了避免电机猛地一抖把婴儿惊醒HAL_TIM_PWM_Start(htim3, TIM_CHANNEL_1); void Rock_Start(uint8_t duty) { for (uint16_t d 0; d duty * 10; d 2) { __HAL_TIM_SET_COMPARE(htim3, TIM_CHANNEL_1, d); HAL_Delay(20); /* 约 1 秒爬升 */ } }这里占空比用千分比ARR 49 时比较值范围是 0 到 49所以__HAL_TIM_SET_COMPARE要传duty * 0.049写代码时换算清楚否则电机纹丝不动你还以为是驱动坏了。3.4 哭声识别的信号处理与联动逻辑哭声检测的采样链路是 TIM4 触发 ADC1DMA 循环搬运 256 点到缓冲区采样率 8kHz也就是每 32ms 采满一帧。主循环里对每一帧算两个特征短时能量和过零率。能量算法就是平方累加uint32_t energy 0; for (uint16_t i 0; i 256; i) { int16_t s (int16_t)pcm_buf[i] - 2048; /* 去直流偏置 */ energy (uint32_t)(s * s); } energy / 256;阈值不要写死用动态阈值维护一个缓慢更新的本底噪声均值判定门限设为本底 × 4 经验偏移这样白天夜里环境噪声变化都能自适应。这个细节答辩时说出来老师会觉得你真的调过。联动逻辑要注意优先级温度报警优先级高于安抚安抚进行中如果检测到异常报警要立刻停止摇床安全优先然后进入报警状态。而且摇床设一个最长运行时间比如连续 5 分钟没检测到哭声就自动停防止机械一直转。3.5 联网上报与本地交互上报链路我推荐两条备选。预算紧张的用 HC-05 蓝牙模块走串口手机端装个通用串口助手就能看数据简单可靠想做 App 或小程序的话上 ESP-01S 走 AT 指令连 WiFi通过 MQTT 把温湿度、体重、状态推出去。这里有个经典坑ESP8266 和 STM32 串口通信时模块返回的数据可能跨帧、可能带一堆 AT 回显串口接收中断里不能直接解析要老老实实做环形缓冲加状态机收到\r\n才算一帧完整数据。缓冲区小了会丢数据我一般给 256 字节。本地交互用 0.96 寸 OLEDSSD1306I2C加三个按键模式切换、手动摇床、报警复位。界面分三屏轮播每屏 2 秒避免信息挤在一起。OLED 刷新率别设太高每秒全屏刷新一次就够刷太快反而会因为 I2C 占用时间影响其他任务。4. 调试实录与常见问题排查4.1 常见问题速查表下面这张表是我这几年攒下来的病历本基本覆盖了这个项目 90% 的翻车现场。现象可能原因排查与解决电机一转到 MCU 就复位电源共地干扰、纹波尖峰单点接地、电机电源并 470μF0.1μF、加续流二极管HX711 读数乱跳电源纹波、走线过长、未滤波单独 LDO 供电、缩短模拟走线、去极值平均零点标定DHT22 读失败时序被打断、上拉电阻不对读取过程关中断、上拉 4.7kΩ、加大两次读取间隔OLED 花屏或全黑I2C 速率过高、地址错误降到 100kHz、确认地址 0x78 或 0x7APWM 无输出定时器未 Start、比较值超 ARR调HAL_TIM_PWM_Start、检查比较值范围程序卡在 while 等 DOUTHX711 未供电或接线反量电压、确认 VCC 4.7V 左右、检查 DOUT/SCK 是否接反串口收不到 WiFi 模块返回波特率不匹配、缓冲区溢出确认 115200、加大环形缓冲、AT 回显要先发ATE0关掉下载失败BOOT0 电平、串口被占用BOOT0 拉低、按复位时序、关闭占用串口的调试助手中断里调用 HAL_Delay 卡死优先级冲突、死等中断里只置标志耗时的活全放主循环摇床声音啸叫PWM 频率落在可听范围提高 PWM 到 20kHz 或换 TB6612 驱动4.2 几个把我坑惨的现场问题第一个是随机重启。症状是运行十几分钟后 MCU 突然复位加打印也看不出规律。折腾了两天最后用示波器抓到电机换向瞬间 12V 母线上有接近 8V 的下冲而这个下冲通过 AMS1117 传导到了 3.3V 上出现了一个 300mV、持续 2μs 的凹坑正好落在 MCU 的掉电复位门限附近。解决办法是电机电源单独走一路加 470μF 电解和 TVS 二极管同时在 MCU 的 3.3V 端补 100μF 电容。改完之后再没复现过。第二个是称重零点漂移。早上标定好的零点中午读数就偏了几十克。原因是 HX711 的参考电压来自激励电压而激励电压会被 LDO 的温度漂移带动。换成带温度补偿的基准源成本太高我的做法是每 10 分钟自查一次在床状态如果判断为空床就自动重新采集零点这样温漂被自然吸收掉了。这个小技巧写进答辩PPT里是个很实在的工程思路。第三个是哭声误报。装在窗边外面汽车鸣笛就触发。解决方法有两个一是提高判定门限二是引入过零率特征——鸣笛是高频段持续信号过零率高婴儿哭声是低频段且有起伏过零率低。两个特征一起判断误报率直接降下来了。4.3 抗干扰与稳定性的几条硬经验软件层面的抗干扰最有效的三招看门狗、参数合法性检查和失败重试。独立看门狗 IWDG 一定要开喂狗放在主循环末尾这样任何一个任务卡死都会被复位救回来。I2C 读传感器失败要重试三次再报错不要一次读失败就报警虚警比漏报更让人崩溃。所有从传感器来的数据先做范围检查比如温度读到 -200℃ 或者 500℃那肯定是 I2C 通信出错了直接丢弃这一帧不要拿脏数据去参与逻辑判断。还有一条经验是不要在中断里做浮点运算和 printf。串口打印占用时间长如果放在中断里会把系统时序全打乱。我的做法是搞一个 128 字节的日志环形缓冲主循环里慢慢往外吐调试完再关掉。5. 答辩呈现与后续扩展方向5.1 答辩时怎么讲才拿高分答辩的重点不是功能多而是逻辑闭环。你要能回答三个问题为什么这么选选型依据、为什么这么算参数来源、出问题怎么解工程能力。所以我建议 PPT 里专门放一页参数计算把 PWM 频率、摆幅、称重精度的推导过程写出来这比罗列一堆功能点有说服力得多。再放一页问题与解决把上面那些坑和排查过程讲一遍老师能立刻感受到这是真实做过的项目而不是抄来的。演示环节一定要做异常触发正常状态下摇床不动你拍一下手或者放段哭声录音摇床自动启动这就非常直观。如果再加上手机上实时看到温度曲线演示效果就完整了。5.2 这个作品还能往哪扩硬件上可以做低功耗改造把 F103 换成 G0 系列空闲时进 STOP 模式靠按键和 RTC 唤醒电池续航能拉长几倍。软件上可以加数据记录把整晚的温湿度和体动数据存到 Flash 或 SD 卡第二天生成一张曲线图这个功能在实用性和展示性上都很加分。再进一步可以做本地语音提示、和智能家居生态做一些联动的场景演示但要注意不要把项目摊得太大毕设的核心还是把基础功能做扎实。5.3 成本清单参考类别器件参考单价元数量主控STM32F103C8T6 最小系统板151显示0.96 寸 OLED SSD1306121温湿度SHT30 模块151称重20kg 应变片 HX711251声音MAX9814 麦克风模块121驱动TB6612 电机驱动101执行12V 直流减速电机251音频DFPlayer Mini 喇叭251通信ESP-01S 或 HC-05201电源12V 适配器 降压模块251其他洞洞板/PCB、杜邦线、按键、外壳601合计约 245这套清单的成本在两百多块是毕设里比较友好的水平。如果自己打 PCB 会多花一百左右的打样费但实物质感提升明显值得。最后分享一个我在这个项目里反复验证过的做法先把传感器全部调通再上机械。很多人上来就装电机装结构结果电机一跑起来所有传感器数据全乱然后分不清是传感器本身的问题还是干扰的问题。正确的顺序是逐个验证、逐个接入、每接入一个就做一次压力测试——这样你永远知道问题出在哪一层调试效率至少翻一倍。这个顺序看起来慢实际上是这个项目里最快的路径。