2026/10/17 6:14:20

基于STM32的智能晾衣架设计与实现

基于STM32的智能晾衣架设计与实现 1. 项目概述为什么要做一个智能晾衣架做这个项目的起因其实很朴素——家里阳台的晾衣架还是手摇式的晴天要跑出去摇雨天忘了收衣服就白洗。后来发现市面上所谓智能晾衣架核心无非就是电机升降、烘干、风干、紫外线消毒这几件事但价格动不动两三千而且没法按自己的习惯改逻辑。作为一个嵌入式玩家自然想到用STM32自己搭一套完整系统成本压到几百块还能把联动逻辑写成自己想要的。这个项目的完整定义是基于STM32主控通过雨滴传感器、光照传感器、温湿度传感器感知环境状态自动控制晾衣架的升降电机、烘干风机、加热器以及状态指示灯并配合按键或蓝牙小程序实现手动干预。简单说就是让晾衣架具备“下雨自动收、晴天自动晾、湿冷自动烘”的能力。这套系统适合谁参考如果你是正在学STM32的学生可以用它把外设驱动、传感器采集、电机控制、状态机设计、低功耗策略全部串起来是一块非常完整的综合实训项目。如果你是对智能家居感兴趣的爱好者也可以直接照这套思路改造自家晾衣架成本不高改造难度中等偏下。我会尽量把设计决策背后的为什么讲透而不是只贴一堆代码。先列一下整体架构感知层雨滴模块光敏模块DHT11温湿度、执行层直流减速电机驱动晾杆升降、PTC加热器PWM调速风机做烘干、主控层STM32F103C8T6、交互层按键OLED显示蓝牙模块、电源层12V适配器降压模块。这套分层思路是后面所有设计的骨架。2. 硬件选型与关键器件解析2.1 主控为什么选STM32F103C8T6市面上智能家居类作品常看到用Arduino的或者用ESP8266的。我最终选STM32F103C8T6不是因为“显得高端”而是从实际需求和资源角度考虑。首先是资源丰俭F103C8T6属于M3内核72MHz主频64KB Flash、20KB RAM片上资源有ADC、定时器、USART、I2C、SPI、PWM等。在这个项目里需要至少4路ADC雨滴、光敏、湿度、温度、2路PWM风机调速、加热功率调节、1路I2C或模拟I2C驱动OLED、1路USART接蓝牙、若干GPIO控制电机正反转和继电器还要跑一个带状态迁移的主逻辑。这些资源F103C8T6绰绰有余。更重要的是生态。STM32的HAL库和标准外设库文档极其完善网上例程多到泛滥遇到问题搜一下就有思路。相比之下ESP8266虽然自带WiFi更“物联网”但要在上面同时做多路ADC采样和实时电机控制需要跟WiFi协议栈抢资源调试复杂度明显上升。Arduino虽然上手快但底层细节被封装得太多做这种偏“控制逻辑”的项目反而不容易理解硬件本质。另外还要考虑成本。F103C8T6的“蓝色药丸”板子市价十几块钱比很多Arduino板子便宜即便加上外围器件整套硬件成本也能压在100元以内不含电机和电源。2.2 传感器选型雨滴模块、光敏模块、DHT11雨滴传感器我选的是常见的LM393比较器输出的雨滴模块。它其实由两部分组成一块梳状裸露铜箔板作为检测面一个带电位器的比较器电路。水滴落在铜箔板上会改变检测面两电极之间的阻抗从而改变比较器输出电压。这个模块可以直接输出数字信号DO和模拟信号AO我选用AO引脚接STM32的ADC因为数字信号只给出“有雨/无雨”二值对于判断“雨量大小”和“雨滴残余”不够细腻而模拟量可以设定多级阈值。需要注意一点雨滴模块不要直接裸露放在户外否则长时间风吹日晒会加速铜箔氧化检测灵敏度会漂移。我用一块3D打印的百叶窗外壳把它罩住既能让雨水流入又避免阳光直射和灰尘堆积。这个细节后面实测时发现很关键最初直接裸装用了两周后晴天电阻就开始偏大导致误判。光敏传感器我用的是一颗普通的5539光敏电阻加一个10K分压电阻组成的分压电路输出接到ADC。选择光敏电阻而不是模块化光敏传感器是因为后者通常板载了比较器输出开关量而我想按不同光照强度划分“晴天、阴天、夜间”三个区间分压电路加ADC的方式更灵活。换算光照强度其实有公式但工程上不需要精确的照度值只要标定出“强光2.8V、弱光1.2V”这种经验阈值就够用了。温湿度传感器选择DHT11说实话精度不高±2℃、±5%RH但胜在便宜、单总线协议简单、资料丰富。对于晾衣架这种控制场景我们需要的是判断“衣服能不能晾干”的相对趋势而不是实验室级的精确温湿度数据。如果追求更高精度可以换DHT22或SHT30但代码结构和接线需要相应调整。DHT11读取要注意时序问题它是单总线协议主机需要先拉低总线至少18ms发起开始信号然后释放总线等待传感器响应。响应过程包括80us的低电平脉冲和80us的高电平脉冲然后开始传输40位数据湿度高位、湿度低位、温度高位、温度低位、校验和。用HAL库时可以配合HAL_Delay和微秒延时函数但需要注意DHT11时序要求比较严如果延时函数不准确很容易读到超时或数据校验失败我这里直接用寄存器级别的定时器延时解决了。2.3 执行机构选型升降电机、烘干加热、风机晾杆升降是整个系统最核心的执行动作。我选用12V直流减速电机搭配一个双路H桥电机驱动模块如L298N的国产替代或TB6612。为什么不用步进电机因为晾杆升降不需要精确的位置控制只需要“上到位”和“下到位”两个极限位置直流减速电机加两个限位开关行程开关就足够了成本更低驱动也更简单。步进电机在断电时无法保持力矩反而需要额外的抱闸机构复杂化了。电机驱动模块的选型也要注意。L298N是经典方案但它的压降大、发热严重满负荷效率低12V供电时实际到电机的电压可能只有10V左右。如果晾杆比较重电机启动电流大L298N容易过热。我更推荐TB6612FNG它的MOSFET导通压降远小于L298N的三极管压降体积还小最大驱动电流3.2A对家用晾衣架的负载绰绰有余。我实际用的就是TB6612搭配两颗旋转编码器做升降行程计数当然编码器不是必需的但加上之后可以知道晾杆当前展开长度后续可以配合自动收放策略。烘干系统由PTC陶瓷加热器和直流风机组成。PTC加热器有个特性温度升高时电阻会增大功率自动下降因此本身有限温作用不会像镍铬丝那样干烧失控安全性好。我用的是额定150W的12V PTC加热器用功率MOS管做PWM调功率把风速和温度做成闭环控制如果温度已经到45℃以上就减小PWM占空比如果低于30℃就加大占空比。风机同样使用PWM调速这样可以独立控制风量大小和加热功率形成类似“热风烘干”的效果。电源部分整个系统市电接入一个12V 5A的开关电源适配器12V直接给电机和加热器供电再通过一个LM2596降压模块降到5V给STM32板、OLED、蓝牙模块供电再用AMS1117-3.3降到3.3V给传感器供电。这里要特别注意分层供电电机和加热器的启动电流很大瞬时压降可能超过1V如果直接和主控共用电源轨会导致STM32频繁复位。我最后是用两路独立降压一路专门给逻辑部分一路给执行机构地线单点汇接这样干扰小了很多。2.4 交互模块OLED、按键、蓝牙交互方面我选择了0.96寸I2C接口的OLED屏128x64分辨率显示系统状态、温度、湿度、光照、雨滴、当前模式等信息。I2C接口只需要两根线省GPIO而且这个屏幕非常大众网上驱动代码一堆移植起来很顺手。按键方面设计了三颗独立按键“模式切换”自动/手动/烘干、“上升”、“下降”。按键处理没有用库函数轮询这么简单而是加入了一定程度的消抖逻辑和长按短按区分短按切换模式长按进入参数设置。这里其实涉及到一个常见痛点机械按键的抖动会导致一次按下触发多次逻辑。我一开始用简单的延时消抖后来发现还会偶发误触发最终改成“扫描确认状态机”的方式即每10ms扫描一次连续3次相同电平才算有效状态变化这样消抖可靠性高很多。蓝牙模块用的是HC-05这是蓝牙2.0的经典模块通过串口透传数据。在手机上可以用任意串口助手App或者自己写小程序来连接。为什么选HC-05而不是ESP32直接做蓝牙因为主控已经是STM32了加一个透传模块是成本最低的蓝牙方案。HC-05支持AT命令配置默认波特率9600可以改。在本项目里我把蓝牙模块接在USART1上波特率设为115200这样手机端收发消息更快延迟低。蓝牙的作用不只是远程遥控而是让用户可以在室内看到晾衣架的状态、远程控制升降和烘干、获取传感器数据。例如下雨时自动收回来但用户在客厅不知道发生了什么用蓝牙就能看到“当前天气有雨已自动收回”体验完整很多。虽然蓝牙距离有限约10米但阳台到客厅一般不超过这个范围日常够用。3. 系统整体设计与状态机建模3.1 为什么用状态机而不是一堆判断语句很多初学者写这种逻辑很自然会用一系列if else去判断“如果下雨且光照低且湿度高则收回晾杆且加热”。但这样做有个严重问题当条件变化频繁时执行机构会来回抖动。比如雨滴传感器检测到微量露水执行收回过两分钟露水蒸发又检测到晴天执行伸出再过一会又有几滴雨又收回……晾杆会像抽风一样上下运动电机频繁启停驱动模块发热机械结构磨损。状态机能解决这个问题。我把整个系统抽象出几个稳定状态自动待机、晾晒伸出、雨天收回、烘干运行、手动控制。每种状态都有自己的行为并且定义了“从什么状态在什么条件下迁移到什么状态”的规则。例如从“晾晒伸出”切换到“雨天收回”除了需要雨滴传感器判断有雨外还要满足“该状态保持至少2分钟”的条件防止瞬时水滴造成的误触发。这里就是状态机设计的核心迁移不仅依赖传感器输入还依赖状态驻留时间。我在落地实现中给每个状态维护一个计时器迁移条件中加上时间约束整体上就天然形成了防抖逻辑。这样代码结构清晰扩展新功能比如“夜间自动收回”只需要增加一个状态和几条迁移规则不用改动主循环里的判断堆。3.2 状态定义与迁移条件具体状态设计如下自动待机AUTO_IDLE系统上电初始状态表示当前没有晾晒需求。进入条件为系统上电或从其他状态切换为自动模式。此时电机停止加热器关闭风机关闭。晾晒伸出AUTO_EXTEND在自动模式下环境适宜无雨、光照充足、湿度低于阈值时进入。系统会控制电机正转伸出晾杆到达上限位停止然后保持电机断电等待下一次迁移。雨天收回AUTO_RETRACT晾晒过程中检测到雨水或光照过低或者湿度接近饱和时进入。系统控制电机反转收回晾杆到达下限位停止并保持收回状态。在这个状态中烘干器可以部分开启如果气温低且衣服未干也可以完全关闭按配置决定。烘干运行DRY_RUN这个状态是独立于自动晾晒的可以从自动待机、雨天收回或手动控制进入。它表示无论室外天气如何都启动加热和风机进行烘干通常用于阴雨天或夜间用户手动触发或定时触发。烘干运行可以设置持续时间例如30分钟、60分钟时间到自动退出到待机。手动控制MANUAL用户通过按键或蓝牙切换为手动模式后进入用户可以直接控制上升、下降、加热开关、风机开关系统不进行自动迁移直到用户切回自动模式。状态迁移的核心规则当前状态条件目标状态自动待机无雨且光照阈值且湿度阈值晾晒伸出晾晒伸出有雨或光照夜间阈值保持2分钟雨天收回晾晒伸出用户切换手动模式手动控制雨天收回无雨且光照阈值且湿度阈值保持5分钟晾晒伸出雨天收回用户启用烘干烘干运行烘干运行烘干计时结束雨天收回或自动待机手动控制用户切换自动模式自动待机这里最麻烦的是“雨天收回”到“晾晒伸出”的死区问题。因为雨停后雨滴传感器板面的水分不会立刻蒸发完其模拟量还是“有雨”的状态。如果直接按当前采样判断会导致雨停后几小时内都无法自动伸出晾杆。解决方法是增加一个干燥恢复计时只有当传感器连续检测到无雨5分钟以上才允许切回晾晒。同时可以开启风机快速吹干传感器表面这个在实际中很有效。3.3 状态机的软件实现思路状态机代码采用结构体加函数指针的方式也可以用switch-case。对于这个项目我推荐用结构体数组每个元素包含“状态ID、进入函数、运行函数、退出函数、迁移条件表”这样新增状态时只需要往数组里添加一行主循环只调用当前状态的运行函数和迁移检查。伪代码思路typedef struct { uint8_t id; void (*onEnter)(void); void (*onRun)(void); void (*onExit)(void); Transition trans[]; } State; State states[] { {ST_AUTO_IDLE, enterAutoIdle, runAutoIdle, exitAutoIdle, trans_autoIdle}, {ST_AUTO_EXTEND, enterAutoExtend, runAutoExtend, exitAutoExtend, trans_autoExtend}, {ST_AUTO_RETRACT, enterAutoRetract, runAutoRetract, exitAutoRetract, trans_autoRetract}, {ST_DRY_RUN, enterDryRun, runDryRun, exitDryRun, trans_dryRun}, {ST_MANUAL, enterManual, runManual, exitManual, trans_manual}, };但在实际工程中用函数指针会增加阅读门槛。如果大家是初学者我建议先用switch-case把逻辑跑通再重构为函数指针。我在第一版里用的就是switch-case运行完全没问题。后来为了加“倒计时烘干”功能才改成状态机结构。主循环本质上是四步读取所有传感器并更新全局结构体——检查当前状态迁移条件——如果发生迁移调用当前状态的onExit和新状态的onEnter——调用当前状态的onRun。这个循环周期控制在10ms左右DHT11读取耗时较长约20ms我用定时器中断做10ms调度主循环里只做状态逻辑读传感器放在中断外的低速任务里。4. 核心功能模块的实现细节4.1 传感器数据采集ADC、DHT11与滤波ADC采集是基础。STM32的ADC是12位的参考电压3.3V所以读取值范围是0~4095对应0~3.3V。我使用ADC的规则组多通道扫描模式一次性采完雨滴、光敏两个通道DHT11温度湿度则用单总线协议单独读取。三路数据会经过一个滑动平均滤波处理防止传感器噪声导致状态误判。滑动平均滤波的具体做法为每个传感器维护一个长度为N的环形缓冲区每次采样将新值压入同时计算缓冲区内所有值的平均值。N取10采样周期500ms这样既不会滞后太多又能过滤高频干扰。雨滴传感器尤其需要这个因为雨滴在传感器表面跳动会造成ADC值剧烈波动如果直接使用瞬时值状态机会在“有雨/无雨”之间来回横跳。DHT11读取时有个坑它是单总线设备读取时序必须严格。首先主机发送开始信号拉低18ms拉高20us然后释放总线等待设备响应设备会拉低80us再拉高80us表示应答之后输出40位数据。每一位数据由低电平50us和后续的高电平时间区分高电平26~28us表示0高电平70us表示1。由于DHT11时序是微秒级的不能直接用HAL_Delay它最小精度是1ms必须用定时器做微秒延时或者用空指令循环做粗略延时。我用的是TIM2的微秒计时器读取DHT11的成功率高达99%以上。我之前用DWT寄存器Cortex-M内核的数据观察点实现了一个精准延时函数在这里也很方便。温度湿度数据除了显示还参与控制逻辑。比如判断“衣服是否晾干”不能只看湿度值因为环境湿度本身就很高比如梅雨天空气湿度85%。我采用“相对干燥度”概念如果环境湿度持续低于65%且温度高于24℃并且光照充足判定为适合晾晒如果环境湿度过高或温度过低则即使无雨也不建议伸出晾杆而应该烘干。4.2 电机控制实现PWM调速与限位开关电机控制用的是TB6612驱动。TB6612有四个输入端AIN1、AIN2、BIN1、BIN2和两路PWM输入PWMA、PWMB。控制一路电机正转时设置AIN11、AIN20然后PWM占空比控制转速反转则AIN10、AIN21。这个逻辑非常简单关键是防止上下限位撞到后电机还继续堵转。堵转状态下电机电流很大驱动芯片容易烧毁而且晾杆机构和支架也会承受额外冲击。因此限位开关是保险丝级别的保护。我用两个微动开关分别作为上限位和下限位串在电机控制回路中。正确的做法是硬件上将限位开关的常闭触点串联在电机供电回路中一旦触发即使软件出现问题电机电源也会被物理切断。同时软件上还要读取限位开关的GPIO状态用来判断当前晾杆是否已到位并更新状态机的状态位置。软件方面还应该实现堵转保护。如果电机已经运行了超过预设时间比如20秒还没有触发限位开关说明可能卡住或限位开关失效此时立即切断电机控制并发出报警信号OLED显示“错误电机超时”。这个超时时间需要实际测量——我量过手头电机的速度晾杆从完全缩回到完全伸出约需要12秒所以超时设定为20秒留出余量。电机还需要PWM调速吗对晾衣架来说其实不需要高速相反应该用较低的PWM占空比让晾杆缓缓升降避免衣服晃动甚至甩落。我使用50%占空比作为默认升降速度实测升降平稳。如果晾杆上挂的衣服太重电机会有“嗡嗡”声但不动这时需要提高占空比到70%左右但不能超过80%否则启动电流过大驱动芯片发热严重。4.3 烘干控制PTC加热与风机的联动烘干功能是一个独立子模块。它的目标不是把衣服烘到“干透”而是把湿度降低到可以收进衣橱的程度。我的策略是先把风机全速运转3秒然后再开启加热器PWM这样可以让热气更均匀地流动避免局部过热。加热器功率我采用分段控制刚启动时用全功率100% PWM当温度传感器我额外加了DS18B20检测出风口温度达到45℃后降低到50%功率维持当温度超过55℃降到30%功率并报警提示用户检查出风口。这个温控逻辑防止了衣物被热风烤坏的风险。风机的转速也分三档低风30%、中风60%、高风100%。默认启动时用高风出风口温度稳定后如果环境湿度低于40%可以降为中风如果湿度仍高于70%保持高风。温湿度和风速的联动可以在后期做成模糊控制甚至PID但就这个项目而言简单的分段控制已经能获得不错的烘干效果。这里有一个很关键的细节热风循环方向。如果烘干风机从下往上吹衣服下方的湿气会被吹上来但衣服上方如果盖着别的衣服湿气不容易散开。我的方案是把出风口设计在晾衣杆上方斜向下吹这样空气可以穿过衣物并从下方散开类似于衣物护理机的气流设计。但这个角度和位置与晾衣架的机械结构强相关大家在自己的架子上需要按实际调整我最初用直吹方式烘干效率至少低了30%。另外PTC加热器功率比较大150W长时间工作会使得晾衣架周围温度升高。如果是密闭阳台一定要保证通风否则热量积聚可能导致塑料件变形甚至有安全隐患。我的建议是烘干运行时间最长不要超过90分钟可以通过蓝牙设置定时关闭。4.4 人机交互OLED显示、按键与蓝牙协议OLED显示内容决定了用户体验。我在一屏上显示四行第一行是模式自动/手动/烘干、温度、湿度第二行是光照强度和雨滴状态第三行是晾杆位置状态伸出/收回/运行中第四行是系统状态提示如“即将自动收回”。刷新频率为每秒一次因为OLED如果频繁刷新全屏会闪而且I2C带宽有限没有必要。按键的消抖和防误触前面提到过。这里再补充一个设计长效按键与模式切换分开。比如“模式切换”按键是短按方便用户快速切换但为了防止放兜里误触我把“切换为烘干模式”设置在长按2秒短按只是切换自动/手动。这个细节看起来小实际用起来很顺手。蓝牙通信协议我定义了简单的3字节帧格式第一字节为帧头0xAA第二字节为命令字第三字节为校验和。命令字包括手动上升0x01、手动下降0x02、停止0x03、切换自动模式0x04、切换手动模式0x05、启动烘干0x06、停止烘干0x07、查询状态0x08。我还在手机端的串口调试工具里预设了配好的快捷键按钮这样使用起来非常方便不用每次手动敲十六进制。蓝牙收到命令后执行前还要做校验和检查防止脏数据。校验和有最简单的按位累加三字节相加后取低字节为0表示通过。对于用户来说不一定需要自己写手机App用开源的串口助手也可以。如果有Android开发经验的人可以写一个二十行的小App通过蓝牙串口发送命令但这不是本项目的核心。4.5 低功耗与异常处理晾衣架在大部分时间是待机的这个时候如果主控一直全速运行既浪费电力也增加系统发热。我的做法是让STM32进入睡眠模式使用RTC唤醒定时器每500ms醒来一次去读取传感器并判断状态。如果当前状态是“自动待机”且所有条件都不满足就继续保持睡眠。如果检测到传感器信号发生变化比如突然下雨立即唤醒执行机构。实际测试下来待机电流从常转的65mA降到了约12mA对整体功耗改善明显。异常处理是容易被忽略但极其重要的部分。我做了这样几类异常监控传感器超时DHT11读取失败3次、电机超时升降运行20秒未触发限位、电流过流通过采样电阻检测电枢电流超过阈值自动停止、加热器温度过高DS18B20温度高于65℃自动关闭。这些异常都会在OLED和蓝牙端显示对应的代码方便排查。还需要注意的是电源掉电恢复。如果电机正在升降过程中突然断电重新上电后系统不知道当前晾杆位置。我的解决方法是上电初始化时先让电机反转收回2秒触发下限位然后停止以此保证晾杆处于已知的收回状态。虽然整个过程有点呆但非常有效避免了上电后盲目伸出引起的意外。5. 实操过程从硬件搭建到整体联调5.1 硬件搭建与接线哪些线需要特别注意硬件走线是整个项目里最容易被“想当然”的地方。我先说接线分布再指出几个容易踩的坑。主控板使用STM32F103C8T6最小系统板引脚分配我做了如下规划功能引脚备注雨滴传感器AOPA0ADC1通道0光敏电阻分压PA1ADC1通道1DHT11数据PA3普通GPIO推挽输出/输入DS18B20数据PA4单总线OLED SCLPB6I2C1时钟OLED SDAPB7I2C1数据TB6612 AIN1/AIN2PB0/PB1电机正反转TB6612 PWMAPA8定时器1通道1TB6612 STBYPB10高电平使能上限位开关PB12外部中断下降沿触发下限位开关PB13外部中断下降沿触发按键1/2/3PB14/PB15/PA8上拉输入蓝牙TXD/RXDPA9/PA10USART1加热器PWM控制PB5定时器3通道2风机PWMPB6定时器4通道1与OLED的SCL复用注意上面表格里我故意标了一个冲突PB6同时给了OLED的SCL和风机PWM。这是初始设计时的教训我后来将风机PWM改到了PB0才对。大家在参考时一定要仔细核对引脚冲突STM32的复用功能虽然丰富但GPIO资源还是有限的规划引脚前先画一个端口占用表把每个引脚的复用到功能列出来能避免大量返工。电源接线方面12V电源正负极一定不能接反否则会烧毁降压模块和主控。为了防止意外我在电源输入端加了一个防反接二极管SS34肖特基压降约0.4V对12V来说可接受。同时在12V和5V之间加一个1000uF电解电容形成简单的储能缓冲应对电机启动电流的瞬时冲击。传感器接线时雨滴模块和光敏模块的信号线建议用带屏蔽的双绞线或同轴线因为电机和加热器工作时会产生较强的电磁干扰可能会在ADC通道上耦合出几十毫伏的噪声影响阈值判断。我一开始用普通杜邦线雨滴模拟量在电机启动瞬间会跳变0.15V左右虽然不多但在阈值边缘会造成抖振。改成屏蔽线后这个现象消失了。5.2 软件架构与代码组织软件按照功能模块划分为多个文件保持每个.c文件职责单一main.c系统初始化主循环调度state_machine.c状态机和迁移逻辑sensor.cADC、DHT11、DS18B20驱动motor.c电机控制、限位检测、超时保护dryer.c加热器和风机控制oled.cOLED显示驱动bluetooth.c串口蓝牙协议解析button.c按键消抖与事件产生这样的划分对后续维护很有好处。如果我想把DHT11换成SHT30只需修改sensor.c内部实现对上层状态机暴露同样的接口读温度、读湿度不影响其他模块。主循环结构大致是int main(void) { HAL_Init(); SystemClock_Config(); // 72MHz MX_GPIO_Init(); MX_ADC1_Init(); MX_I2C1_Init(); MX_USART1_UART_Init(); MX_TIM_Init(); sensor_init(); motor_init(); dryer_init(); oled_init(); bluetooth_init(); button_init(); stateMachine_init(); while (1) { sensor_update(); // 读取并滤波 stateMachine_run(); // 处理状态迁移和运行逻辑 display_update(); // 刷新OLED bluetooth_update(); // 处理蓝牙命令 button_update(); // 处理按键事件 HAL_Delay(10); // 主循环10ms } }系统时钟配置为72MHzADC时钟为12MHz采样时间为239.5周期这样可以获得较低的采样噪声。DHT11读取时由于其高电平持续时间是微秒级我用TIM2做了一个微秒延时函数实测读取成功率显著提高。状态机的迁移检查放在10ms循环里每个状态带一个“当前驻留时间”计数每10ms加1。迁移条件需要组合时间和传感器比如雨天收回后要等待DHT11湿度降到阈值以下且雨滴传感器连续300次采样5分钟无雨才能切回晾晒。5.3 阈值标定从理论到实际测量的调整传感器的阈值不能盲信网上的经验值因为每个模块的基准电压、分压电阻精度都不同。我做了这样的标定流程第一步先让雨滴传感器表面干燥读取ADC值记录下来。我的模块在干燥时ADC值大概是3800约3.06V。 第二步用手指沾水轻触传感器表面读取ADC值大概降到1100约0.89V。 第三步在阈值之间设置一个中间判定点比如2400。但考虑到水分蒸发后的渐变过程我将“有雨”判定设为ADC值低于1800“无雨”判定设为高于2800中间带作为滞回区间。滞回区间是状态机防抖之外的又一道保障。光敏电阻的标定类似我分别在阳台直射阳光下、阴天散射光下、夜间关灯时记录ADC值。实测结果晴天约3900阴天约2500夜间约200。然后设定“明亮”阈值为3000“昏暗”阈值为500同样带滞回。温湿度阈值DHT11在阳台雨天时湿度能到85%以上晴天午后湿度在45%~60%。我把“适合晾晒”的湿度阈值设为65%温度阈值设为18℃。如果温度低于18℃即使湿度合适也不建议晾出去因为衣服容易有阴干味。阈值的参数我全部定义为宏方便用户按当地气候调整。比如南方回南天湿度阈值可能需要改为75%否则系统会一直认为不适合晾晒导致长时间不伸出。5.4 首次整体联调踩过的坑联调阶段我把几个环节串起来后最先暴露的问题不是传感器而是电机驱动逻辑。第一次上电时晾杆没有自动收回反而直接伸出并撞到上限位持续堵转了一会儿我才反应过来切断电源。排查后发现是因为TB6612的STBY引脚悬浮默认状态下输出不确定电机随意乱转。解决方法是硬件上接10K下拉电阻保证上电时STBY为低禁用输出软件初始化后再拉高。这是一个典型的硬件初始化顺序问题大家接线时一定要把STBY、使能引脚用电阻固定初始电平。第二个问题是蓝牙串口干扰。HC-05模块的TXD/RXD和STM32的USART1连接后系统频繁复位。用示波器看发现蓝牙模块上电瞬间TXD线上有毛刺进入了USART1的RX中断导致卡死。解决方法是在蓝牙模块的VCC上串联一个10欧姆电阻并在GND和VCC之间加100uF电容。同时把蓝牙初始化改成延迟到系统稳定后再配置避免上电时序竞争。第三个问题是OLED显示异常。I2C总线上同时挂了OLED和风机PWM导致引脚冲突这个问题在焊接时就该注意。我当时为了赶进度图省事想当然地复用引脚结果就是OLED有时白屏有时花屏。最后便重新飞线把风机PWM改到别的引脚问题解决。6. 常见问题排查与避坑指南6.1 传感器测量数据明显异常怎么办先区分是硬件还是软件。用万用表测传感器输出引脚的对地电压对比ADC读到的值。如果电压正常但ADC读数偏差很大多半是ADC参考电压不对。F103的VREF引脚默认接3.3V但有些最小系统板没有把VREF引出来默认接内部参考这时候如果供电电压不是精确3.3VADC读数会整体偏大或偏小。解决方法是软件校准测量板上3.3V实际值用实际值除以4096作为转换系数。DHT11读数偶尔为0或跳变最常见原因是总线长度过长或者没有接上拉电阻。DHT11数据线在主机和DHT11之间必须接一个4.7K到5K的上拉电阻到VCC否则信号沿太缓时序就会错。很多模块已经内置了上拉电阻但如果用裸的DHT11一定要自己加。雨滴传感器灵敏度过高或过低调节模块上的电位器可以改变比较器阈值但注意这是针对DO输出的。如果用的是AO就不依赖电位器直接程序标定。有些模块的AO输出范围很窄我遇到过一模块干燥时1.8V淋雨后1.6V电压变化太小很难分辨。这种情况建议直接买质量更好的模块或者用两个铜片自己做探头再接分压电路。6.2 电机启动时系统复位电机启动瞬间电流可达正常工作电流的5倍以上12V电机堵转电流甚至超过2A。如果电源线太长太细线损压降会让电压瞬时跌到9V以下而LM2596降压模块需要输入至少比输出高1.5V才能稳定输出5V一旦输入掉到6.5V以下5V输出就会塌陷主控复位。解决办法一是换短粗的电源线至少使用18AWG以上的线缆二是在12V母线上并一个4700uF/25V电解电容作为储能三是在软件上设计“软启动”电机PWM占空比从20%开始递增到50%启动电流可以降低很多。软启动不仅保护电源也保护机械机构衣服不会突然被猛拉。6.3 蓝牙连接不稳定或收不到数据HC-05几个坑值得说清楚模块默认波特率可能不是9600不同厂家固件版本不同。如果手机串口助手收到乱码先检查波特率。HC-05进入AT模式的条件是上电前按住按键或者EN引脚拉高。我在AT模式下把模块名称改成“SmartDryingRack”同时把波特率调到115200并且设置了PIN码1234。改完AT配置后必须重新上电才生效。蓝牙模块与STM32共地否则串口电平没有参考地数据完全不通。如果蓝牙连接不上手机多是因为之前已经配过对但PIN码不匹配。用AT指令清除配对信息可以解决。6.4 烘干效果差怎么排查如果烘干运行很久衣服还不干先检查出风口温度。用温度枪测出风口温度是否在40℃以上。如果温度一直上不去可能原因是PTC加热器额定电压是12V但你用的电源实际带载后电压掉到10V左右功率会下降很多。这时可以把适配器换成15V但要注意电机和降压模块的耐压或者加大适配器功率。另外风机转向如果装反了热风会吹向反方向但加热器还在发热容易导致局部过热。我犯过一次这个错误后来在风机上标了气流方向箭头再安装。如果设备上有温升但衣服感受不到风大概率是风路被异物堵住或者风机接线反了。7. 进阶扩展与经验总结7.1 可以往哪个方向升级这套系统的可扩展性很强按我的经验最值得升级的三条路第一把蓝牙换成WiFi模块比如ESP8266或ESP32接入MQTT配合Home Assistant之类的智能家居平台实现手机远程查看状态和控制。这相当于把晾衣架从“蓝牙遥控”升级为“真正的物联网设备”。原理上只需要把HC-05换成ESP8266通过AT固件透传数据即可软件改动很小。第二增加称重传感器感知衣物重量和湿度的变化。衣服在晾晒过程中水分蒸发重量会逐步下降。通过持续采样重量变化曲线可以估算“含水量”和“预计晾干时间”这比单纯依赖环境湿度判断要准确得多。我当时想加但阳台空间有限所以没有做。如果用HX711模块加一个悬臂梁称重传感器机械结构的改动比较大需要重新设计晾杆悬挂结构。第三把烘干和紫外线消毒结合起来。晾衣架的紫外线消毒灯管在室内收回状态时开启杀菌但要注意紫外线对人眼和皮肤有伤害必须设计成“晾杆收回后且检测到人不在附近”才允许开启感应方案可以用红外人体传感器。7.2 关于这个项目最终的实际体会做完整个项目我最大的体会是智能硬件项目的核心不在于主控有多高性能而在于把每一个传感器数据、每一段控制逻辑放到真实的物理环境中去验证。理论上的阈值、时序、状态迁移到了实际的阳台、忽晴忽雨的天气、晾满湿衣服的晾杆面前总会出现你意料不到的情况。比如滞回区间和驻留时间的双重防抖这个设计是一开始没有的是在经历了一次“晾杆反复伸出收回”的搞笑场景后才加入的。当时我刚把系统装好挂了几件衣服测试恰逢外面下着毛毛雨雨滴传感器表面一会儿有水、一会儿被风吹干晾杆电机就跟着来回折腾咔嗒咔嗒响了好几次。后来我在状态机里加入“雨天收回后至少等待5分钟且传感器稳定无雨”的条件这个问题才算根治。另外一个重要的心理准备是不要一开始就追求完美。先把最小系统打通——比如只实现手动升降再逐步加入传感器、状态机、蓝牙、烘干。每一步能跑通了再继续。如果一上来就想着全套做完调试时一旦出问题很难定位是传感器的问题、驱动的问题还是电源的问题。这种分阶段交付的思路其实也是嵌入式项目里最常用的推进方式。最后说一个实用的小技巧在代码中保留一个“调试标志”可以通过蓝牙发送特定的命令来打开串口打印把当前状态、各传感器原始值、状态迁移时间都输出到终端。这个对验证系统行为极其有帮助。正式使用的时候可以把打印关掉避免影响主循环时序。如果你也打算做这个项目希望这份记录能帮你少走一些弯路。晾衣架虽小但一个完整的“感知—决策—执行—反馈”闭环都有了把这个逻辑吃透后面再做任何自动化设备都会顺手很多。