1. 项目概述:从零打造智能除湿器

大家好,我是老李,在嵌入式行业摸爬滚打十多年了。今天想和大家分享一个特别实用的单片机项目——基于STM32的智能除湿器。这个项目特别适合潮湿的南方家庭或者需要精密湿度控制的仓储环境,我自己就做了两个放在地下室和书房,效果真的很不错。

智能除湿器的核心思想很简单:通过温湿度传感器实时监测环境数据,然后自动控制风扇、制冷器和加热器的工作状态。但想要做得智能,就需要设计多模式切换功能,包括自动模式、手动模式,以及针对不同场景的普通模式、加强模式和节能模式。我这次用的是STM32F103系列单片机,成本低且性能足够,配合SHT20温湿度传感器,精度可以达到±0.3℃和±3%RH,完全满足家用需求。

整个项目最有趣的部分是状态机设计。你需要让设备能够根据当前环境自动判断该做什么:湿度太高了就启动除湿,温度太高了就开始制冷,温度太低则加热。还要避免设备频繁启停,所以我在算法里加入了回差控制,比如温度超过设定值2度才启动制冷,降到设定值以下2度才停止,这样设备寿命更长,也更省电。

2. 硬件设计详解

2.1 核心元器件选型

做硬件设计,元器件选型是第一步也是最重要的一步。主控我选择STM32F103C8T6,这款芯片性价比极高,有足够的GPIO、ADC和通信接口,72MHz的主频处理我们的控制逻辑绰绰有余。

温湿度传感器我用的是SHT20,通过I2C接口与主控通信。这个传感器精度高且响应快,实测下来每秒钟读取一次数据完全没问题。显示部分选择了ILI9341 TFT液晶屏,240x320的分辨率足够显示所有信息,而且支持中文字库,可以通过SPI接口驱动。

执行部件包括:PC6控制风扇,PC4控制制冷器,PC13控制加热器。这里要注意,直接驱动大功率设备需要加驱动电路,我用的是继电器模块,简单可靠。电源部分设计了一个分压电路来检测电池电压,公式是Vbat = (ADC值 × 4 × 3.3V) / 4095,这样就能实时监控电源状态。

2.2 电路设计要点

电路设计上我踩过一些坑,分享给大家避免重复犯错。首先是电源部分,模拟和数字电源要分开,记得调用HAL_PWREx_EnableVddA()HAL_PWREx_EnableVddIO2()来启用模拟电源,否则ADC读数会不准。

I2C总线上一定要加上拉电阻,我用的是4.7kΩ,否则通信会不稳定。SPI驱动屏幕时,如果屏幕出现雪花点,可能是时钟速度太快,适当降低SPI速率可以解决。

按键输入设计了消抖电路,除了硬件上并联104电容外,软件上也用定时器做了消抖处理。IO分配要合理,把相关功能的外设分配到同一组GPIO上,比如控制用的PC4、PC6、PC13就都在GPIOC上,方便统一操作。

3. 软件架构设计

3.1 系统初始化与外设配置

软件部分我从初始化讲起。使用STM32CubeMX生成基础代码后,需要手动添加一些关键初始化。首先是ADC校准,这是很多人会忽略的一步:

HAL_PWREx_EnableVddA();  // 启用VDDA
HAL_PWREx_EnableVddIO2(); // 启用VDDIO2
HAL_ADCEx_Calibration_Start(&hadc4, ADC_CALIB_OFFSET, ADC_SINGLE_ENDED);

没有校准的ADC读数会有偏差,我最初没做校准时,电压读数差了0.2V左右。串口需要重定向printf,方便调试和状态上报:

int fputc(int ch, FILE *p) {
    while(!(USART1->ISR & (1<<7))) {} // 等待发送寄存器空
    USART1->TDR = ch;
    return ch;
}

屏幕初始化后建议先清屏并显示启动界面,给用户一个友好的反馈。我还会做一次自检,所有外设检测一遍,有任何问题直接显示在屏幕上,避免运行时出现莫名其妙的问题。

3.2 多任务调度机制

因为没用RTOS,所以任务调度要自己设计。在主循环中,我按顺序处理各个任务:

while (1) {
    BSP_SHT20_GetData();    // 读取温湿度
    ADC_Convert();          // ADC转换
    uart_handle();          // 串口处理
    auto_control();         // 自动控制
    lcd_display();          // 刷新显示
    HAL_Delay(100);         // 延时100ms
}

每个任务执行时间要短,保证系统响应及时。比如读取温湿度大约需要10ms,ADC转换需要20ms,控制逻辑和显示各需要5ms左右,这样整个循环大约140ms,响应速度足够快。

中断处理包括定时器中断和串口中断。定时器中断用于按键消抖和定时上报,串口中断处理远程命令。中断服务函数中不要做耗时操作,我一般只是设置标志位,在主循环中处理具体逻辑。

4. 核心算法实现

4.1 温湿度控制逻辑

控制算法是项目的灵魂,我设计了优先级策略:湿度控制优先于温度控制。当湿度超过设定阈值时,全力除湿,这时候不管温度如何,风扇、制冷器和加热器都会打开。因为除湿是首要任务,只有湿度降下来了,才需要考虑温度调节。

湿度正常后,开始温度控制。这里有个技巧:设置回差防止设备频繁启停。比如设定温度上限为26℃,那么实际温度超过26℃时启动制冷,但直到温度降到24℃才停止制冷。加热也是类似,温度低于20℃时启动加热,升到22℃后停止。

if (T > TempHigh) {
    // 启动制冷
    HAL_GPIO_WritePin(GPIOC, GPIO_PIN_6 | GPIO_PIN_4, 1);
} else if (T < TempHigh - 2) {
    // 停止制冷
    HAL_GPIO_WritePin(GPIOC, GPIO_PIN_6 | GPIO_PIN_4, 0);
}

这种滞后设计很实用,我自己实测下来,设备启停次数减少了70%以上,既省电又延长了设备寿命。

4.2 多模式切换实现

模式切换是通过一个模式变量实现的,0表示自动模式,1表示手动模式。在自动模式下,系统完全根据环境参数自动控制设备。手动模式下,用户可以通过按键或串口命令直接控制设备。

手动模式下还有个标志位flag,用来指示当前正在调整哪个参数:1调整温度上限,2调整温度下限,3调整湿度阈值。在LCD屏幕上,当前正在调整的参数会以蓝色背景高亮显示,非常直观。

加强模式和节能模式是通过调整阈值实现的。加强模式会将湿度阈值调低5%,让除湿更彻底;节能模式则会将湿度阈值调高5%,减少设备工作时间。这两种模式可以通过串口命令切换,也可以在代码中预设。

5. 人机交互设计

5.1 按键输入与消抖处理

按键输入设计了四个按键:PA12用于模式切换,PC9用于切换调整项,PC8和PC5用于增减数值。机械按键最大的问题是抖动,所以我采用了软件消抖方式:

void HAL_GPIO_EXTI_Falling_Callback(uint16_t GPIO_Pin) {
    HAL_TIM_Base_Start_IT(&htim6); // 启动定时器消抖
}

void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim) {
    if (htim == &htim6) {
        // 再次检测按键状态
        if (HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_12)==0) {
            mode = 1 - mode; // 切换模式
        }
        HAL_TIM_Base_Stop_IT(&htim6); // 停止定时器
    }
}

定时器中断中再次检测按键状态,如果仍然是按下状态,才认为是有效按键。这种方法简单有效,成本几乎为零。

5.2 LCD界面布局

LCD显示内容要清晰易读,我分了几个区域:顶部显示标题"Smart dehumidifier",接下来显示实时温湿度数据,中间部分显示当前阈值设置,底部显示设备状态和模式。

特别要注意的是刷新策略。如果每次循环都刷新整个屏幕,会有明显的闪烁感。我采用局部刷新方式,只有数据变化时才更新相应区域。比如温度值每秒最多更新一次,设备状态只有在变化时才更新。

显示阈值调整时,当前正在调整的项会以蓝色背景高亮,其他项为白色背景。这样用户一眼就能知道当前在调整哪个参数,大大提升了用户体验。

6. 串口通信协议

6.1 自定义通信格式

串口通信采用文本协议,格式为"设备ID 参数名=值"。比如设置湿度阈值为50%:"123 Hum_level=50.0"。为什么要用文本协议?因为调试方便,直接用串口助手就能发送命令,不需要专门的上位机软件。

设备ID用于多设备区分,如果你有多个除湿器,可以通过ID分别控制。解析命令时先用strncmp比较ID,匹配后再用strstr查找参数名,最后用sscanf提取数值:

if (strncmp(recv_buf, "123", 3)==0) {
    if (strstr(recv_buf, "Hum_level=")) {
        sscanf(recv_buf, "123 Hum_level=%f", &Hum_level);
    }
}

这种解析方式灵活且容错性好,即使数据格式有些小问题也能正确解析。

6.2 远程控制实现

除了参数设置,还可以直接控制设备开关。比如"123 fan_on"开启风扇,"123 fan_off"关闭风扇。同样的方式可以控制制冷器和加热器。

定时器每2秒会上报一次设备状态,包括ID、模式、温湿度、阈值和电压等信息。这些数据可以接入物联网平台,实现远程监控。我自己就写了个简单的Python脚本接收这些数据,记录成CSV文件,方便分析设备运行情况。

安全方面做了基本验证,只有ID匹配的命令才会被执行,否则返回"未识别到该设备"。在实际应用中,还可以增加密码验证等更安全机制。

7. 实战调试与优化

7.1 常见问题解决

调试过程中我遇到不少问题,这里分享几个典型的。首先是I2C通信失败,SHT20读不到数据。检查后发现是上拉电阻没焊好,重新焊接后解决问题。I2C线长最好不要超过20cm,否则信号质量会变差。

ADC读数不稳定,波动很大。后来发现是电源噪声的影响,在电源引脚加了104和10uF的电容后,读数稳定多了。ADC采样时间也很重要,设置太短会导致采样不充分,我一般设置为239.5个时钟周期。

屏幕显示有时会出现花屏,原因是SPI速度太快。降低SPI时钟频率后问题解决。刷新屏幕时注意先设置好窗口地址,再发送像素数据,避免数据错位。

7.2 性能优化技巧

为了降低功耗,我做了几点优化:一是降低主频,在不需要高性能时将系统频率从72MHz降到32MHz;二是外设不用时就关闭,比如不需要显示时关闭屏幕背光;三是采用中断唤醒方式,设备大部分时间处于睡眠状态。

内存优化也很重要,STM32F103C8T6只有20KB RAM,要精打细算。我尽量使用局部变量,全局变量都用了最小的数据类型。字符串处理使用sizeof避免缓冲区溢出。

实时性方面,中断服务函数要尽可能短。我最初在串口中断中直接解析数据,发现有时会丢失数据,后来改成在中断中只设置标志位,在主循环中解析数据,问题就解决了。

8. 扩展功能与进阶应用

8.1 物联网接入

现有的串口通信可以很容易地扩展为物联网功能。加个ESP8266 WiFi模块,就能实现手机APP控制。我用AT指令让ESP8266连接路由器,然后通过MQTT协议接入云平台。

MQTT协议很轻量,特别适合单片机。每个设备一个主题,手机APP通过订阅主题来接收设备状态,通过发布主题来发送控制命令。我自己写了个简单的MQTT客户端,占用资源很少,运行稳定。

如果不想自己搭建服务器,可以用现成的物联网平台,比如阿里云物联网平台或者ThingsBoard。这些平台提供设备管理、数据可视化和规则引擎等功能,大大降低了开发难度。

8.2 数据记录与分析

加上SD卡模块,可以实现数据记录功能。每分钟记录一次温湿度和设备状态,形成历史数据。这些数据可以用来分析环境变化规律,优化控制参数。

我最初设置的阈值是固定的,后来通过分析历史数据,发现不同时间段的湿度变化规律不同,于是就增加了时段策略:白天湿度阈值设低些,晚上设高些,这样既保证舒适又节能。

进一步还可以做预测控制,根据历史数据预测未来一段时间的温湿度变化,提前调整设备状态。比如预测到要下雨了,就提前开启除湿,这样雨天地下室也不会潮湿。

9. 项目总结与心得

这个项目我从开始到调试完成用了大概两周时间,硬件成本不到100元,但效果堪比市面上千元的除湿器。最让我满意的是多模式切换功能,根据不同场景选择不同模式,真的很实用。

过程中最大的收获是对状态机的理解更深了。一个好的状态机设计能让程序逻辑清晰,易于维护和扩展。比如我后来增加了一个定时除湿模式,只需要在状态机中加个新状态就行了,其他部分几乎不用改。

给新手的建议是先从简单功能开始,比如先实现温湿度读取和显示,再逐步添加自动控制、多模式等功能。每步都充分测试,这样出了问题也容易定位。

Logo

智能硬件社区聚焦AI智能硬件技术生态,汇聚嵌入式AI、物联网硬件开发者,打造交流分享平台,同步全国赛事资讯、开展 OPC 核心人才招募,助力技术落地与开发者成长。

更多推荐