基于STM32的智能衣柜毕业设计:从零搭建嵌入式系统实战指南
摘要:许多电子/物联网专业学生在毕业设计中选择“基于STM32的智能衣柜”项目,却常因缺乏系统性开发经验而陷入硬件驱动混乱、传感器数据不可靠或低功耗设计失效等困境。本文面向嵌入式新手,详解如何基于STM32F1/F4系列构建一个具备温湿度监测、衣物识别与远程控制功能的智能衣柜系统,涵盖外设选型、HAL库配置、低功耗策略及OTA升级可行性分析,帮助读者高效完成可演示、可扩展的毕业作品。
1. 背景痛点:新手最容易踩的五个坑
做“智能衣柜”听起来高大上,可真正动手时,实验室里常常一片哀嚎。我帮学弟妹调过三次板子,总结最常见的问题如下:
硬件兼容性差
某宝买的“XX智能模块套餐”里,DHT22 温湿度传感器号称 3.3 V 兼容,结果上电直接拉低整条 I²C 总线,STM32 反复复位。代码结构混乱
所有功能都写在main.c的while(1)里:读传感器 → 点灯 → 延时 500 ms → 串口打印 → 再读传感器…… 一旦加入 RFID 中断,串口数据立刻乱码。调试困难
没有打印口,只能拿 LED 闪灯排错;灯闪 3 下代表“I²C 应答失败”,闪 5 下代表“CRC 校验错”,最后连自己都记不住含义。低功耗设计失效
以为调用HAL_PWR_EnterSTOPMode()就能省电,结果 GPIO 没配置上下拉,板子停在 20 mA,三天就把锂电池榨干。传感器数据漂移
衣柜内部温度其实挺稳定,但读出来的湿度一天内能跳 20 %RH,原因是 ADC 参考电压被 Wi-Fi 模块的突发发射拉低了 80 mV。
如果你也遇到以上任何一条,别急,下文从选型到代码一条线帮你捋顺。
2. 技术选型:STM32F1 vs F4、DHT22 vs SHT30、RFID vs 蓝牙标签
毕业设计资源有限,选错芯片/模块,后面填坑的时间直接翻倍。我把当时做的对比表贴出来,供你直接抄作业。
2.1 主控:STM32F103C8T6 vs F407VET6
| 维度 | F103 “最小系统板” | F407 “小黑板” |
|---|---|---|
| 主频 | 72 MHz | 168 MHz |
| Flash | 64 KB | 512 KB |
| RAM | 20 KB | 192 KB |
| 外设 | USB FS 从设备 | USB OTG、自带 FS/HS |
| 价格 | 12 元 | 45 元 |
| 低功耗 | 停机 20 µA | 停机 300 µA |
| 总结 | 够用、便宜、资料多;OTA 升级空间吃紧 | 跑 RTOS+GUI 才划算,功耗高,毕设容易“性能过剩” |
结论:只做温湿度+继电器+RFID,F103 足够;想上彩色触摸屏、以太网或后期跑 MicroPython,再考虑 F407。
2.2 温湿度传感器:DHT22 vs SHT30
DHT22(AM2302)
单总线,读取一次 4 字节,分辨率 0.1 ℃ / 1 %RH,典型误差 ±2 %RH。致命伤:响应 1 ms 窗口,必须关中断、关调度,否则时序被拉长直接返回 0xFF。SHT30(或 SHTC3)
I²C 接口,最高 0.5 Hz – 1 MHz 时钟,16 bit 温度+16 bit 湿度+CRC,低功耗 0.5 µA,休眠 0.3 µA。一颗 6 脚小芯片,价格 7 元,比 DHT22 贵 2 元,但 HAL 库直接调用HAL_I2C_Mem_Read()就能拿数据,再也不用“精准纳秒延时”。
结论:毕设时间紧,直接上 SHT30,代码量减半,稳定性翻倍。
2.3 衣物识别:RFID vs 蓝牙标签
- RFID RC522 13.56 MHz
优点:模块 5 元,UART/SPI 接口,读卡距离 0 – 3 cm,抗金属差,需要把标签缝在布兜内侧。 - 蓝牙 iBeacon(唯传、E73 系列)
优点:手机直接扫描,距离 0 – 5 m,可广播电池电量;缺点:功耗 0.5 mA,需要纽扣电池,成本 18 元/个,识别逻辑要写蓝牙协议栈。
结论:衣柜门一关金属屏蔽严重,蓝牙信号衰减 20 dB,毕设演示时手机经常搜不到。RC522 虽然距离近,但“嘀一下”动作直观,老师看得懂,推荐 RFID。
3. 核心实现:CubeMX 配置 + HAL 驱动 + 状态机
3.1 CubeMX 初始化步骤
- 选芯片:STM32F103C8Tx
- RCC 页面:HSE 选 Crystal/Ceramic,LSE 不用
- Clock Configuration:PLL 9×,72 MHz
- 外设:
- I²C1 (PB6/PB7) 400 kHz 标准模式 → SHT30
- SPI1 (PA5/6/7) 分频 8 → RC522
- USART1 (PA9/10) 115200 → 调试打印
- TIM3 1 kHz 中断 → 系统滴答
- GPIO PC13 → 板载 LED,PB12 → 继电器
- 低功耗:勾选 PWR、RTC(唤醒用)
- Project Manager:选 MDK-ARM V5,Generate peripheral initialization as a pair of .c/.h files(方便移植)
生成代码后,先Build一遍,保证 0 Error 0 Warning,再往下写应用层。
3.2 传感器读取封装(SHT30)
/* file: sht30.c */ #include "i2c.h" #define SHT30_ADDR 0x44<<1 int SHT30_Read(float *temp, float *humi) { uint8_t cmd[2] = {0x2C, 0x06}; // clock stretching, high repeatability uint8_t dat[6] = {0}; if (HAL_I2C_Mem_Read(&hi2c1, SHT30_ADDR, 0x2C, I2C_MEMADD_SIZE_8BIT, cmd, 2, 50) != HAL_OK) return -1; HAL_Delay(15); // 等待测量完成 if (HAL_I2C_MemC(&hi2c1, SHT30_ADDR, 0x00, I2C_MEMADD_SIZE_8BIT, dat, 6, 50) != HAL_OK) return -2; uint16_t t = dat[0]<<8或大端 dat[1]; uint16_t h = dat[3]<<8或大端 dat[4]; *temp = -45.0f + 175.0f * t / 65535.0f; *humi = 100.0f * h / 65535.0f; return 0; }调用者只需:
float t, h; if (SHT30_Read(&t, &h) == 0) printf("T=%.1f H=%.1f\r\n", t, h);3.3 状态机控制逻辑
智能衣柜业务可拆成 4 个状态:
- IDLE:低功耗,RTC 每 30 s 唤醒一次
- MEASURE:读取 SHT30,若湿度 > 70 % → 开排风继电器
- RFID:检测 RC522,读到卡号 → 串口上报 “UID=0xXX 0xXX …”
- ERROR:连续 3 次传感器失败 → 闪灯+看门狗复位
状态机用switch(curr_state)写法,最直观;千万别把业务写成“超级循环+标志位”,否则调试时大脑栈溢出。
4. 低功耗与唤醒示例
很多教程告诉你“进入 STOP 模式就完事”,却忘了把 GPIO 拉到合理电平。下面给出完整流程,实测 3.3 V 下整机 18 µA。
- 进入低功耗前:
void EnterStopMode(void) { // 1. 关闭高耗电外设 HAL_SPI_D(&hspi1); HAL_I2C_D(&hi2c1); HAL_UART_D(&huart1); // 2. GPIO 全部下拉,防止悬空漏电流 GPIO_InitTypeDef g = {0}; g.Pin = GPIO_PIN_All; g.Mode = GPIO_MODE_ANALOG; g.Pull = GPIO_PULLDOWN; HAL_GPIO_Init(GPIOA, &g); HAL_GPIO_Init(GPIOB, &g); HAL_GPIO_Init(GPIOC, &g); // 3. 设置 RTC 唤醒 30 s HAL_RTCEx_SetWakeUpTimer_IT(&hrtc, 30, RTC_WAKEUPCLOCK_RTCCLK_DIV16); // 4. 进入 STOP HAL_SuspendTick(); HAL_PWREnterSTOPMode(PWR_REGULATOR_LP, PWR_STOPENTRY_WFI); }- 唤醒后:
void HAL_RTCEx_WakeUpTimerEventCallback(RTC_HandleTypeDef *hrtc) { // 重启系统时钟,恢复 72 MHz SystemClock_Config(); HAL_ResumeTick(); // 重新初始化外设 MX_I2C1_Init(); MX_SPI1_Init(); // 设置标志,让主循环回到 MEASURE 状态 wake_flag = 1; }5. 性能与安全:ADC 噪声、看门狗、OTA 边界
ADC 参考电压
如果同时用 ADC 测电池电压,记得把 VREF 引脚单独接 0.1 µF 到地,远离继电器走线;否则每次继电器吸合,ADC 读数抖动 2-3 个 LSB,湿度阈值判断误触发。独立看门狗 IWDG
上电后 40 ms 内必须喂狗,推荐在 RTC 唤醒后第一时间HAL_IWDG_Refresh(&hiwdg),防止死机后卡在半开状态把衣服烤变形。OTA 升级安全边界
F103 的 64 KB Flash 建议分 3 区:- Bootloader 8 KB(0x08000000)
- APP-A 28 KB(0x08002000)
- APP-B 28 KB(0x08009000)
升级时先下载到 B,CRC32 校验通过再改写vtor跳转;失败可回滚 A。注意:写 Flash 必须关中断,且把 I²C 中断优先级设成 5,否则 RC522 的SPI_Interrupt会把 erase 流程打断,直接 HardFault。
6. 生产环境避坑指南
PCB 布局
继电器线圈回路单独走 24 mil,下方不要横越晶振;晶振底部铺地+guard ring,防止衣柜金属侧板形成寄生电容,起振失败。GPIO 悬空
程序里没用到 BOOT0、NRST 以外的一切引脚,一律GPIO_Analog + Pull-down,否则 18 µA 低功耗目标永远达不到。串口调试干扰
用 CH340G 下载完程序后,一定拔掉 TXD 跳线,否则 PC 端串口助手打开瞬间,STM32 的 RX 被拉到 3.3 V,导致HAL_UART_Receive_IT连续进中断,主循环卡死。
7. 效果展示
下图是第二版打样的 10 × 10 cm 双层板,整板高度 1.6 mm,直接贴在衣柜侧壁;锂电池 + 18650 支架在背面,排风 MOSFET 放在继电器下方,避免长线寄生电感。
思考延伸:下一步,让衣柜开口说话?
目前系统只能“被动”上报温湿度和 UID,如果再加一颗 LD3320 离线语音识别或 ESP32-S3 做本地语音模型,就能实现“小衣柜,明天北京 5 °C,帮我找羽绒服”——衣物流程管理 + 本地 TTS 反馈,毕业答辩的亮点瞬间拉满。你会怎么选?是走离线关键词,还是直接上云端 NLP?欢迎留言一起头脑。