南方的回南天有多可怕,住过的人都知道:墙能渗水,镜子上全是雾气,鞋柜里的皮鞋靴子隔一夜就返潮发臭。最初我也只是往柜子里塞了几包干燥剂,直到某天推开柜门闻到那股混合着霉味和汗渍的味道,才下定决心,自己做一套基于STM32单片机的智能鞋柜系统出来。整个项目从硬件设计到代码调试,前前后后花了一个多月,最终实现了自动除湿烘干、UV杀菌、定时通风、旋转翻找和状态显示。这篇文章不吹不黑,把我从需求拆解到最终调通的完整过程写出来,给想玩STM32实战项目的朋友一个参考,也顺带聊聊那些文档里查不到的坑。
1. 为什么做个智能鞋柜:从痛点拆解到功能定义
先别急着画原理图,我做的第一件事,是把自己对"智能鞋柜"的想象全部写下来,再逐个划掉。比如市面上概念图里常见的自动识别鞋型、机械臂取鞋,我评估了一下成本和可靠性,直接放弃了。一个鞋柜最核心的使命不是炫技,而是让鞋子在收纳期间保持干燥、干净、无味。围绕这个核心,我最终敲定了六项功能。
功能清单如下:
- 自动除湿烘干:温湿度传感器实时监测柜内湿度,超过设定阈值且持续一段时间后,自动启动PTC加热模块和风扇,形成热风循环强制对流除湿。
- UV杀菌:每天固定时段自动开启紫外线灯,抑制鞋内细菌和真菌滋生,从源头减少异味。
- 定时通风:每天多个时段自动开启风扇换气,防止封闭柜体内气味积聚。
- 旋转翻找:通过步进电机驱动旋转鞋架,用户按键选择需要取用的层架,不用再把头钻进柜子里翻。
- 状态显示与参数设置:OLED屏显示温度、湿度、运行模式、倒计时等信息,三个按键完成模式切换、手动开关和参数调整。
- 多重安全保护:加热器过热自动停机、温度传感器异常报警、紫外线灯与柜门锁定联动(这部分我放在升级方向里,后面细说)。
为什么这样定义功能?我在项目里给自己定了一条原则:凡是可能因为复杂而失效的功能,一律砍掉或者做冗余。机械臂就是典型的复杂机构,动作精度要求高,电机减速器、关节连接、力度反馈任何一个环节出问题都会导致整机不可用。相比之下,旋转鞋架是简单的圆周运动,用步进电机加转盘就能实现,结构上可靠得多,维护也方便。除湿杀菌则是鞋柜的核心刚需,尤其在南方,一场回南天下来皮鞋底部能长出青霉,这三项功能直接决定用户体验。
如果你也想复刻这个项目,建议先问自己一个问题:你的鞋柜放在什么环境里?是南方潮湿地区还是北方干燥地区?柜内主要放皮鞋、运动鞋还是靴子?这会影响传感器阈值、加热功率和通风策略。我按南方用户场景设计,默认湿度高于65%RH且持续30分钟才触发除湿,北方用户可以适当调高到70~75%RH。
2. 系统架构与硬件选型:先画电源树,再选主控和传感器
2.1 模块划分与总体连接关系
整个系统按功能分成五个模块:主控板、传感板、驱动板、电源板、执行器。主控板负责逻辑运算,它通过单总线接口读取温湿度传感器和柜壁温度传感器,通过I2C接口驱动OLED屏幕,通过普通GPIO读取按键,通过一组GPIO控制步进电机驱动芯片,再通过几个GPIO加上光耦和功率MOS管控制加热器、风扇、UV灯。执行器全部由12V电源供电,主控部分由3.3V供电,中间用光耦和MOS管隔离。
这种模块化分层的好处是调试时非常方便。传感器异常只查传感板,电机不转只查驱动板和电源,主控代码崩了也不影响其他模块的独立供电,另外后续想换更强的MCU或者加联网模块,只需要改主控板的接口定义,执行器部分完全不用动。
2.2 主控芯片选型:STM32F103C8T6的取舍
主控我选了STM32F103C8T6,这是最常见的STM32入门芯片,48脚LQFP封装,72MHz主频,64KB Flash,20KB SRAM。网上资料极其丰富,遇到问题随手就能搜到参考代码。对于这个项目,它其实还有大量余量,即使后期加了FreeRTOS、图形界面、联网协议栈,资源依然够用。
唯一要提醒的是Flash只有64KB,如果开启RTOS加一堆中间件,编译出来可能逼近上限。我在项目里用标准外设库裸机开发,整个工程的固件大小约40KB,剩余空间还能放不少UI字库。如果你打算用HAL库加CubeMX生成工程,注意裁剪不必要的模块,HAL库本身会吃掉不少Flash。
2.3 传感器选型:DHT22加DS18B20的双传感器方案
湿度检测用的是DHT22(也叫AM2302),温度和湿度一体式传感器,单总线数字输出,温度精度±0.5℃,湿度精度±2%RH,量程0~99.9%RH。我没有选择更便宜的DHT11,原因是DHT11的湿度精度只有±5%RH,在临界湿度60%~70%这个区间误差很大,容易造成除湿开关频繁抖动,而且DHT11在低湿度环境下漂移明显。DHT22单颗十几块钱,对于整套系统来说占比很小,但可靠性提升非常明显。
我在柜壁外侧还加了一颗DS18B20,这是数字温度传感器,同样是单总线,精度±0.5℃。它贴在柜体侧壁外表面,专门用来监测柜体结构温度。为什么需要这个传感器?因为PTC加热器吹出的热风在柜内循环时,如果长时间运行,柜体板材表面温度会缓慢上升,热量传递到柜壁外表面。如果只靠柜内空气温度判断是否过热,空气温度可能因为通风良好而维持在40℃左右,但柜壁某一块板材因为局部热桥效应温度已经很高,这就有安全隐患。DS18B20贴在柜壁外表面,能间接反映柜体是否已经过热,一旦超过40℃就强制停止加热。
双传感器方案的成本增加不到十元,但解决了单一传感器无法覆盖的"空气热但壳体不热"和"壳体热但空气不热"两个极端情况,我认为这个投入非常值得。
2.4 执行器与电源模块:功率预算先算清楚
执行器部分,我的配置是:12V/30W的PTC陶瓷恒温加热器、12V/0.15A的涡轮风扇、12V/3W的395nm UV灯珠板、五线四相步进电机28BYJ-48配合ULN2003驱动板。为什么加热器选30W?因为我的柜内容积大约0.15立方米,实测30W加热器能在15分钟内把柜内温度从25℃升到45℃,再大功率很容易出现局部过热,皮鞋表面被烤变形。小功率加热器配合风扇形成的热风循环,虽然慢但安全,皮鞋保养最怕高温烘烤,我曾经见过别人的烘鞋器把鞋头烤出裂纹。
电源部分,外部用12V/3A直流适配器供电,12V直接给加热器、风扇、UV灯和步进电机供电;12V经过LM2596-5.0降压模块得到5V,给主控板和OLED屏供电;5V再经AMS1117-3.3得到3.3V,给MCU和传感器供电。选适配器时很多人只把所有器件额定功率相加,但忽略了同时率和启动浪涌。我的功率估算表如下:
| 负载 | 电压 | 额定功率 | 工作特点 |
|---|---|---|---|
| PTC加热器 | 12V | 30W | 冷态启动时冲击电流较大 |
| 涡轮风扇 | 12V | 约1.8W | 连续运行,可PWM调速 |
| 步进电机 | 12V | 约2.5W | 只在翻找时短时运行 |
| UV灯 | 12V | 3W | 每天定时运行15分钟 |
| 主控板+OLED+传感器 | 3.3V/5V | 约2W | 持续运行 |
我设计了一个简单的联动规则:加热器工作时,步进电机不转、UV灯不亮。这样最坏情况是加热器30W加风扇1.8W加主控2W,总功率约34W,12V/3A适配器的峰值容量36W勉强够用但余量不足。后来我实测发现,PTC冷态启动瞬时电流接近额定值的1.5倍,所以如果你要复刻,至少选12V/3.5A或者12V/4A的适配器,别省这几块钱。
这个电源树是整个项目里我最后悔没有一开始就画出来的东西。起初我凭感觉选了一个12V/2A适配器,结果第一次整机联调时,加热器一开机主控就直接复位,排查了一整天才发现是电源过载导致电压跌落。
3. 核心电路设计要点:光耦隔离、MOS管开关和接口定义
3.1 加热器控制:为什么用光耦加MOS管而不是继电器
PTC加热器是纯阻性负载,控制方式无非继电器和功率开关两种。我选了光耦EL357N加功率MOS管IRLZ44N的方案,而不是继电器。原因有三:继电器有机械寿命,频繁通断几次后触点氧化会影响导电;继电器吸合和释放的瞬间有电弧,在这个项目里虽然电流不大,但长期使用会产生触点烧蚀;继电器切换时还会发出咔嗒声,放在卧室里半夜除湿会自动响,非常扰人。
实际电路连接逻辑如下:MCU的PA2引脚输出高电平,经过一个1k电阻限流,驱动EL357N光耦的输入侧发光二极管,光耦输出侧导通后,将IRLZ44N的栅极上拉到12V,MOS管导通,PTC加热器负极接通GND,开始加热。MCU的3.3V域和12V功率域之间通过光耦实现了电气隔离,加热器开关瞬间的电流扰动不会通过地线干扰到MCU的复位电路。
MOS管的散热问题也值得说。IRLZ44N导通电阻典型值只有0.025Ω,通过加热器的电流大约2.5A,导通损耗P=I²R大约0.16W,几乎不需要外加散热片,贴在PCB铜箔上就能正常工作。很多人喜欢用继电器,觉得简单,但我实测在12V 30W负载下,继电器触点温升明显比MOS管的大,而且没有光耦隔离。
3.2 传感器与OLED接口:单总线、I2C和上拉电阻的细节
DHT22和DS18B20都是单总线协议,数据线上需要接4.7k欧姆上拉电阻到3.3V。这个上拉电阻很多新手会忘记,结果就是传感器读数全乱或者读不到。线长方面,单总线协议建议数据线不要超过20米,我的柜体内传感器到主控板距离不到1米,完全没问题。接线时我把传感器放在柜体中部侧壁的背风处,没有放在角落,更没放在加热器出风口附近——这个位置选择的教训我在后面踩坑章节详细展开。
OLED屏用0.96寸SSD1306,I2C接口,SCL和SDA分别接到PB6和PB7,这是STM32F103的I2C1引脚。I2C总线也需要上拉电阻,但SSD1306模块板上通常已经有了,不需要额外加。我实际使用中遇到OLED显示闪烁的问题,原因是柜内风扇和加热器开启时,电源上的纹波变大,OLED的VCC引脚对电源纹波比较敏感。解决方法是OLED电源脚并联一个100uF电解电容和一个0.1uF瓷片电容,这个组合对低频和高频纹波都有抑制作用。
按键方面,三个功能键分别接PB0、PB1、PB10,外接10k欧姆上拉到3.3V,按下时接地,低电平有效。需要注意的是PB2引脚是BOOT1引脚,上电时会决定启动模式,不建议拿来当普通IO;PB3、PB4是JTAG复用引脚,如果不做重映射,这两个引脚在外部默认连接调试电路,直接当输入用会出现意想不到的干扰。我选GPIO时特意避开了这些引脚,省去了重映射的麻烦。
3.3 步进电机驱动:ULN2003和28BYJ-48的接线与驱动
28BYJ-48步进电机是五线四相电机,内部自带减速齿轮箱,减速比1:64,空载转速约每分钟15转。它看似转速不快,但扭矩经过64倍减速放大之后,带动一个直径40厘米的鞋架转盘在轻载情况下完全没问题。驱动芯片用ULN2003,这是达林顿管阵列,输入端接MCU的PB12到PB15,输出端接电机的四个相线,电机的公共端接12V电源。
驱动方式我推荐用8拍半步驱动,比4拍整步驱动更平稳,噪声也更小。四相电机按A、AB、B、BC、C、CD、D、DA的顺序轮流通电,每个脉冲转过半个步距角,配合减速箱,转动一圈需要大约4096个脉冲。在代码里我建了一个查表数组,按顺序输出到四个引脚,每两个脉冲之间延时8毫秒,实测这个速度下鞋架转动平稳,不会出现明显的顿挫感。如果延时太短,比如小于3毫秒,电机会出现啸叫和丢步,因为减速箱来不及吸收冲击。
4. 主控逻辑与代码实现:DHT22时序、除湿状态机和防呆设计
4.1 DHT22读取时序:单总线的严格时序与微秒延时
DHT22是单总线协议,时序要求很严格,主机和传感器之间一来一回的信号必须精确到微秒级。读取流程分为四步:主机拉低总线至少18毫秒,让传感器从睡眠中唤醒;主机释放总线,上拉电阻把总线拉高,延时20~40微秒;传感器收到启动信号后,先输出80微秒低电平再输出80微秒高电平作为应答;应答完成后,传感器连续输出40位数据,高位先出,分别是湿度整数、湿度小数、温度整数、温度小数和校验字节。
我在裸机环境下写了一个微秒级的延时函数,用的是DWT模块的周期计数器,而不是简单的软件循环。原因是软件循环会被中断打断,一旦在读取DHT22的过程中发生定时器中断,延时就会不准确,轻则读取失败重试,重则直接卡死在读时序里。DWT延时函数代码如下:
void delay_us(uint32_t us) { DWT->CTRL |= DWT_CTRL_CYCCNTENA_Msk; // 使能DWT周期计数器 uint32_t start = DWT->CYCCNT; uint32_t ticks = us * (SystemCoreClock / 1000000); while((DWT->CYCCNT - start) < ticks); }读取DHT22的完整函数中有几个容易出问题的地方,我封装了一个简单的读取接口,核心结构如下:
uint8_t DHT22_Read(float *temp, float *humi) { uint8_t data[5] = {0}; // 1. 主机拉低至少18ms GPIO_ResetBits(GPIOA, GPIO_Pin_0); delay_us(20000); GPIO_SetBits(GPIOA, GPIO_Pin_0); // 2. 等待传感器应答低电平 delay_us(30); if(GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_0)) return 1; // 没有应答,读失败 // 3. 等待80us低电平结束 while(!GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_0)); // 4. 等待80us高电平结束 while(GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_0)); // 5. 读取40位数据 for(uint8_t i = 0; i < 40; i++) { while(!GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_0)); // 等待位开始低电平 delay_us(40); // 从高电平开始延时40us uint8_t bit = GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_0); data[i / 8] = (data[i / 8] << 1) | (bit ? 1 : 0); while(GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_0)); // 等待位结束 } // 6. 校验 if((data[0] + data[1] + data[2] + data[3]) != data[4]) return 2; // 校验失败 *humi = (data[0] << 8 | data[1]) / 10.0f; *temp = (data[2] << 8 | data[3]) / 10.0f; return 0; }注意第5步中延时40微秒后读到的电平就是这一位是0还是1。DHT22的时序里,每位数据起始都是一个12~15微秒的低电平,然后是27~32微秒的高电平表示0,或者116~130微秒的高电平表示1。在40微秒这个时间点采样,高电平已经结束的话读到0,还在持续的话读到1,这也是用延时采样而不是用定时器捕获周期的原因,逻辑更简单,实测误码率极低。
4.2 除湿状态机:阈值、滞回和防频繁启动
整个鞋柜的控制核心是除湿状态机,它决定了系统在待机、除湿、冷却、通风之间如何切换。状态机设计我考虑了三个关键点:湿度的滞回区间、启动前的持续确认、以及加热和冷却的交替节奏。
滞回区间是为了防止湿度在临界值附近抖动导致继电器和MOS管频繁通断。我设定湿度超过65%RH且持续30分钟才启动除湿,降到45%RH以下才停止除湿。这中间20个百分点的滞回区间,让控制逻辑不会因为传感器读数上下波动而反复切换。持续30分钟这个确认条件也很重要,平时开门取鞋放鞋,柜内湿度也会短暂上升,如果一超过65%就马上启动加热,不仅白白耗电,还会把常温鞋子烘烤一遍。
主循环里的状态机核心逻辑如下,用了一个简化的方式来表达:
typedef enum { STATE_IDLE = 0, STATE_DEHUMIDIFY, STATE_COOLING, STATE_UV, STATE_ERROR } SystemState; while(1) { // 每2秒读取一次传感器,标志位由定时器置1 if(sensor_tick) { sensor_tick = 0; ret = DHT22_Read(&temp, &humi); wall_temp = DS18B20_Read(); if(ret != 0) { error_count++; if(error_count > 5) state = STATE_ERROR; // 连续5次读取失败,进入错误保护 } else { error_count = 0; } } switch(state) { case STATE_IDLE: if(humi > 65 && high_humi_count >= 30) { state = STATE_DEHUMIDIFY; heater_on = 1; fan_speed = FAN_HIGH; } break; case STATE_DEHUMIDIFY: if(humi < 45 || wall_temp > 40 || dehum_running_min >= 10) { heater_on = 0; // 退出加热阶段 state = STATE_COOLING; fan_speed = FAN_MEDIUM; cool_running_min = 0; } break; case STATE_COOLING: if(cool_running_min >= 5) { state = STATE_IDLE; fan_speed = FAN_LOW; } break; case STATE_UV: // UV定时点亮逻辑由独立计时器处理 break; case STATE_ERROR: Buzzer_Set(1); // 蜂鸣器长鸣,等待人工重启 break; } }除湿阶段为什么只持续10分钟就要强制停5分钟?我最初是连续加热30分钟,结果发现鞋面靠近出风口的位置已经烫手,但鞋子和鞋之间堆积区域还是湿冷。后来改成加热10分钟、风扇中速冷却5分钟,让热量有时间向鞋材内部传导,鞋面外层快速干燥形成的"壳"才不会阻挡内部水汽向外排出。这个间歇式加热的经验对靴子特别有效,后期我会把这个周期细化为加热5分钟、停3分钟、再加热5分钟,实测靴筒内部干透时间缩短了将近一半。
4.3 定时通风与UV杀菌:低功耗状态下怎么省心
除湿之外,定时通风和UV杀菌则是完全靠定时器驱动。系统上电后,我设置了一个以1秒为基准的软件计时器,从每天早上8点开始,每隔4小时自动开启风扇低速运行5分钟。UV灯每天固定在晚上7点开启15分钟,这个时段是大多数人刚回家换下鞋的时间,紫外线照射可以及时处理当天鞋内的汗湿和细菌滋生。
UV灯的安全处理是个重点。紫外线直射人眼会导致损伤,虽然395nm波段的LED紫外灯能量密度比我印象里的汞灯低很多,但我还是加了两个保护:UV灯开启期间,蜂鸣器每5秒响一声提醒柜子附近的人;UV灯只允许在柜门关闭的前提下开启,检测方式用门磁开关——一个干簧管贴在柜门边框,磁铁贴在门上,柜门关闭时干簧管导通,UV控制信号才能通过。这个门磁开关在智能门铃、门窗传感器里很常见,几块钱一个,安全设计不能省。
4.4 按键交互和菜单逻辑:长按短按、防抖和参数记忆
三个按键的功能分配是:Key1短按切换"自动/手动"模式,长按3秒进入参数设置;Key2在设置界面切换项目,在翻找模式下选择层架;Key3在设置界面调整数值,确认当前选项。
按键防抖我用了经典的20毫秒延时消抖,没有额外加RC滤波电路,因为软件消抖已经足够稳定。MCU在主循环里轮询三个按键电平,检测到下降沿后延时20毫秒再读一次,确认仍为低电平才算有效按键。这个方案的缺点是按键响应有20毫秒延迟,但人在柜子前面操作根本感知不到。
参数设置的值包括湿度阈值、除湿时长、UV开启时间等,都存储在STM32内部Flash的最后几页里。存储时注意先擦除整个扇区再写入,因为Flash只能把1写成0,不能把0写成1。我封装了一个非常简单的读写函数,每次写入的参数用两个字节备份,读取时对两个字节做校验,不一致则恢复默认值。这个方法虽然简单,但足以应对鞋柜这种不频繁写参数的场景。
5. 实测效果与踩坑记录:湿度虚高、热风干不透和电机共振
5.1 标准场景测试数据
整个系统装进柜子之后,我找了一个模拟回南天的场景做实测:环境温度25.3℃,柜内初始湿度83%RH,放了五双鞋,其中两双是刚穿过的运动鞋,一双是潮湿的皮鞋。柜内容积约0.15立方米,机器全自动运行。测试数据如下:
| 时间点 | 柜内湿度 | 柜内温度 | 加热器状态 | 备注 |
|---|---|---|---|---|
| 0分钟 | 83%RH | 25.3℃ | 关 | 启动除湿 |
| 20分钟 | 68%RH | 33.5℃ | 开 | 湿度快速下降 |
| 40分钟 | 55%RH | 41.2℃ | 开 | 间歇周期切换 |
| 60分钟 | 48%RH | 43.8℃ | 开 | 热风循环 |
| 90分钟 | 43%RH | 45.0℃ | 关 | 进入冷却通风 |
| 120分钟 | 39%RH | 37.6℃ | 关 | 自动结束除湿 |
两个小时把柜内湿度从83%降到39%,这个效果基本达到了我对回南天场景的预期。功耗方面,整个除湿周期实际加热约55分钟,30W加热器加风扇,单次耗电约0.06kWh,每天按三个周期算也就0.2kWh左右,比烘干机省电得多。这就是小空间热风循环的优势,热量在封闭柜体内不断循环,不会像房间除湿机那样把热量散到整个空间。
5.2 踩坑之一:DHT22热风直吹导致湿度读数虚高
第一次整机测试时,我遇到一个非常迷惑的现象:除湿开启后,柜内湿度不降反升,DHT22读数一路飙到90%以上,我还以为是传感器坏了。折腾了半天,最后把柜门打开观察才发现,DHT22安装位置正好在PTC加热器的出风方向上,热风带着水汽直接吹在传感器外壳上,传感器周围微环境的湿度比柜内真实平均湿度高得多。
这个问题本质上不是DHT22不准,而是采样位置没有代表性。解决方法是把传感器换到柜体中部侧壁的背风位置,并且用一块亚克力小挡板挡在传感器朝向气流的那一面,让传感器感受的是整个柜体的平均温湿度场,而不是某一路气流的局部参数。改完位置后再测,湿度读数稳定下降,和柜门上的独立校验湿度计误差保持在2%RH以内。
这个坑告诉我一个原则:传感器布点一定要避开风口和热源,宁可让读数略微滞后于真实值,也不要让局部气流把读数带偏。
5.3 踩坑之二:热风干不透靴子内部
第二个坑是从用户体验上发现的。第一版除湿策略是加热器连续工作20分钟,风扇高转速不停。测试皮鞋表面基本干爽了,但第二天穿靴子时,靴筒内部还是明显发潮。原因是热风只循环在柜内空间,它优先加热鞋的外表面,鞋材表面的水分迅速蒸发后形成一层干燥的外壳,阻碍了内部水汽向外扩散。连续高温只会让外层越烤越热,但内部的水分根本没有出来。
解决方法是把连续加热改成间歇脉冲式:加热5分钟,停3分钟,再加热5分钟。停止加热的3分钟里,热量继续向鞋材内部传导,内部水汽受热后向鞋面方向迁移,下一次热风循环时正好把这部分水汽带走。实测间歇脉冲式比连续加热的干燥效率高约30%,而且鞋面温度始终控制在45℃以内,不会伤害皮质和胶水。
这个经验如果放在烘鞋器上效果更明显,烘鞋器直接插进鞋内,热量能直接抵达鞋腔内部,但同样的间歇加热原则依然适用。
5.4 踩坑之三:28BYJ-48步进电机低频共振
电机带动旋转鞋架时,在某一低速区间内整个柜体会发出明显的嗡嗡声,声音频率大概在几十赫兹,听起来特别难受。这是步进电机在低转速下的共振现象,当脉冲频率接近电机转子的固有机械频率时,电机轴会剧烈振动,声音通过柜体板材放大。
解决措施有三个:第一,驱动脉冲间隔避开共振区间,我用示波器配合微调延时,最终固定为8毫秒,绕开了共振带;第二,用8拍半步驱动而不是4拍整步驱动,半步模式下换相更平滑,冲击力更小;第三,电机固定螺丝上加橡胶减震垫圈,并在鞋架转盘底部加了一圈硅胶缓冲条。三管齐下之后,噪声从明显的嗡嗡声降到了可以接受的程度,在卧室里也不会吵人。
另外我还加了一个逻辑限制:步进电机只在除湿加热器关闭的冷却间歇期运行,防止翻找动作和热风循环同时进行,既避开了功率叠加,也减少电机在热环境中的负载,对电机寿命有好处。
5.5 踩坑之四:电源浪涌导致主控复位
这个问题在第2章的功率预算里提过,实际发生的场景是:整机通电瞬间,PTC冷态电阻很低,加热器的冲击电流接近正常工作电流的1.5倍,直接把12V电源轨拉低,5V降压模块跟着跌落,MCU就复位了。表现就是插电之后,屏闪一下又重启,然后进入轮询状态,隔几秒又重启一次。
硬件上我把适配器换成了12V/4A,留足余量;软件上加了两道保险:MCU上电后延迟3秒才允许加热器导通,而且第一次导通用PWM软启动,前5秒占空比从30%逐渐升到100%。这样就算适配器容量余量小一点,也不会因为瞬间全功率冲击导致电压崩溃。这个软启动思路在控制电机、加热器这类感性或阻性大负载时都适用,值得复用。
6. 从Demo到日常可用:我建议优先升级的几个方向
第一个升级方向是联网控制和远程监测。加一个串口转WiFi模块,比如常见的ESP8266模块,通过UART串口与STM32通信,就能实现手机端查看柜内温湿度、手动远程除湿、接收过热报警推送。这套联网方案在STM32侧代码改动量极小,只需在原有状态机基础上增加一条串口命令解析分支,把控制权从按键扩展成"按键+网络消息"两种来源。我测试下来稳定工作了一个月,唯一要注意的是确保串口波特率和WiFi模块配置一致,另外Socket长连接的心跳机制要写好,防止设备长时间待机后连接断开。
第二个方向是鞋架智能分组。我给旋转鞋架每个层板加了一个简易的压力传感器薄膜,放在层板与鞋的接触面上,检测该层是否放了鞋以及鞋的重量范围。这样系统能记录哪一层放了哪双鞋,配合OLED显示屏直接显示"第2层:运动鞋",按Key2翻找到对应层架。压力传感器薄膜的成本不高,ADC读取也很简单,但注意薄膜传感器长期承压会老化,需要定期校准。
第三个方向是更精细的温控策略。目前我的除湿是基于湿度开启、温度保护,没有做精确的温度闭环。如果你家有真皮皮鞋和翻毛皮靴子,建议增加一个PID温度控制模块,把柜内温度稳定在38~40℃再烘干,超过42℃自动降功率。我的实测经验是,40℃是一个比较安全的温度点:既能显著加速水分蒸发,又不会让真皮表面干裂,也不会让鞋胶熔化。PID参数我建议用位置式PID配合PWM控制MOS管,比例项系数先从Kp=5开始调,积分项时间常数为30秒,微分项先关闭,观察温度超调再微调。
第三个方向是柜体密封优化。除湿效果和柜体气密性有很大关系,我的柜子原本有一条门缝,热风会从门缝泄漏,导致柜内温度上升慢、湿度回升快。我在门框上贴了一圈密封条,实测同样除湿周期下,柜内湿度降低速度提高了约15%。这个改动几乎没有成本,但效果是可感知的。
还有一个小经验:鞋柜内壁最好用能够吸收水汽的材料做一部分贴面,我用的是硅藻土片,分布在柜体两侧,它在湿度高时吸收水分,在加热除湿时释放水分并被热风带走,相当于给除湿系统加了一个缓冲层,能明显减缓开门取鞋后的湿度尖峰。
我自己做完这套系统之后最大的体会是:单片机项目的难点往往不在单片机上,而在如何把传感器、执行器和结构件可靠地整合到一个真实场景里。STM32F103C8T6在整个系统里扮演的角色并不复杂,它只是一个稳定、资源够用、资料充足的控制核心,真正花时间的是功率预算、传感器布点、时序设计、状态机打磨和一轮又一轮的实测修改。
最后再分享一个我后来添加的小功能:柜门打开超过2分钟,系统会主动启动风扇低速运行30秒,把开启柜门时涌入的潮湿空气快速排出。这个功能实现起来就几行代码,但实际使用频率很高,每次取鞋放鞋之后柜内湿度都能很快恢复常态,算是整个项目里性价比最高的一次改动。