news 2026/8/21 2:18:38

基于STM32的智能除湿系统:从传感器到执行器的嵌入式闭环控制实践

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
基于STM32的智能除湿系统:从传感器到执行器的嵌入式闭环控制实践

在实际嵌入式开发项目中,湿度控制是一个经典且实用的应用场景。无论是家庭环境、仓库管理还是精密仪器室,过高的湿度都会导致设备锈蚀、材料霉变甚至电路短路。传统的除湿机往往功能单一,缺乏智能感知和远程控制能力。基于STM32微控制器构建一个智能除湿系统,不仅能精确采集环境数据,还能通过算法实现自动控制,是学习嵌入式系统从传感器到执行器完整链路、理解实时控制逻辑的绝佳实践。本文将以一个已开源的STM32智能除湿系统项目为蓝本,带你从零开始理解其设计思路,复现其硬件连接与软件实现,并深入剖析源码中的关键模块与配置细节。无论你是正在学习STM32的在校学生,还是希望将想法落地的电子爱好者,通过本文的步骤,你都能掌握搭建一个可运行、可扩展的智能除湿原型系统的核心技能。

1. 理解智能除湿系统的核心架构与工作原理

一个完整的智能除湿系统远不止是单片机读取一个湿度值那么简单。它需要形成一个“感知-决策-执行”的闭环,并考虑人机交互与系统可靠性。在开始动手之前,必须清晰地理解整个系统的架构和各部分之间的协作关系。

1.1 系统核心功能模块分解

典型的STM32智能除湿系统包含以下几个核心模块:

  1. 环境感知模块:负责采集关键的物理量。最核心的是温湿度传感器(如DHT11、DHT22、SHT3x等),用于获取当前环境的温度和相对湿度。此外,可能还包括水位检测传感器,用于监测除湿机水箱是否已满,防止溢出。
  2. 核心控制模块:以STM32微控制器为核心,负责运行控制算法、处理传感器数据、驱动执行器并管理其他外设。它是整个系统的大脑。
  3. 执行器驱动模块:根据控制器的决策,执行具体动作。最主要的是继电器模块,用于控制除湿机压缩机或风扇的电源通断。还可能包括蜂鸣器(用于报警)和指示灯。
  4. 人机交互模块:提供系统状态显示和参数设置界面。通常使用OLED显示屏、LCD屏或简单的数码管来显示实时温湿度、设定阈值、系统状态等。按键或旋转编码器则用于用户设定目标湿度阈值、手动开关机等。
  5. 通信模块(可选但推荐):用于实现远程监控和控制。可以通过ESP8266/ESP32等Wi-Fi模块连接网络,将数据上报到云平台或手机APP,也可以使用蓝牙模块与手机进行短距离通信。
  6. 电源模块:为整个系统提供稳定、隔离的电源。特别是继电器控制部分,通常需要将STM32的3.3V/5V逻辑电路与220V交流负载电路进行物理隔离,以确保安全。

1.2 系统工作流程与控制逻辑

系统的智能体现在其自动控制逻辑上。一个基础但有效的控制流程如下:

  1. 初始化:系统上电后,STM32初始化所有外设(GPIO、定时器、ADC、I2C/SPI、串口等),读取存储在EEPROM或Flash中的用户设定阈值(如目标湿度55%),并在显示屏上显示欢迎界面和当前参数。
  2. 数据采集:STM32以固定周期(例如每2秒)通过数字接口或模拟接口读取温湿度传感器的数据。
  3. 数据处理与判断:将读取到的当前湿度值与用户设定的目标湿度阈值进行比较。同时,检查水箱水位传感器状态。
    • 如果当前湿度 > 目标湿度 + 迟滞上限(例如设定55%,迟滞为5%,则上限为60%),且水箱未满,则启动除湿(闭合继电器)。
    • 如果当前湿度 < 目标湿度 - 迟滞下限(例如50%),则停止除湿(断开继电器)。
    • 引入“迟滞”是为了防止系统在阈值附近频繁启停,保护压缩机。这是实际工程中必须考虑的一点。
  4. 驱动执行:根据判断结果,控制GPIO引脚输出高/低电平,进而驱动继电器线圈吸合或释放,从而控制除湿机大功率负载的通断。
  5. 状态更新与交互:在显示屏上更新当前的温湿度值、系统运行状态(如“运行中”、“停止”、“水箱满”)、设定阈值等信息。同时检测按键事件,如有用户操作,则进入设置模式更新参数。
  6. 通信上报(如果具备):将系统状态和数据打包,通过串口发送给Wi-Fi模块,由模块上传至服务器。

理解了这个闭环流程,再看源码和原理图就会清晰很多。接下来,我们将进入实战环节,从环境准备开始,一步步构建这个系统。

2. 环境准备与硬件平台搭建

在开始编写和阅读代码之前,必须准备好正确的开发环境,并理解硬件连接。这是后续一切工作的基础。

2.1 软件开发环境准备

对于STM32开发,我们主要需要以下软件工具:

  • 集成开发环境 (IDE)
    • Keil MDK-ARM (uVision):经典、稳定,国内用户广泛。需要安装对应的STM32器件支持包。
    • STM32CubeIDE:ST官方推出的免费IDE,基于Eclipse,集成了STM32CubeMX图形化配置工具,非常适合初学者和快速原型开发。本文后续示例将主要基于此环境。
    • IAR Embedded Workbench:另一款商业IDE,性能优异。
  • STM32CubeMX:这是一个独立的图形化软件配置工具,可以直观地配置引脚、时钟、外设、中间件,并生成初始化代码框架。即使使用STM32CubeIDE,其内部也集成了此功能。
  • 串口调试助手:用于查看STM32通过串口打印的调试信息,如printf输出。常用的有XCOM、SSCOM、Putty等。
  • 程序下载工具:用于将编译好的固件烧录到STM32芯片中。
    • ST-LINK/V2调试器/编程器:最常用的官方工具。
    • J-Link:SEGGER公司出品,支持芯片广泛,调试性能强大。
    • USB转TTL串口模块:如果使用串口下载方式(ISP),则需要此模块。

环境搭建步骤简述:

  1. 从ST官网下载并安装STM32CubeIDE
  2. 安装时,它会提示安装或更新STM32CubeMX和HAL库,同意即可。
  3. 安装完成后,打开STM32CubeIDE,它已经包含了编译器、调试器和CubeMX配置功能。
  4. 准备一个ST-LINK调试器,并将其SWD接口(SWCLK、SWDIO、GND、3.3V)与你的STM32开发板对应连接。

2.2 硬件元器件清单与核心连接

参考开源项目的原理图,我们需要以下核心硬件。这里以常见的STM32F103C8T6(蓝色战舰最小系统板)为例进行说明。

模块推荐型号主要功能与STM32连接方式(示例)
主控STM32F103C8T6系统核心,运行控制逻辑-
温湿度传感器DHT11采集温度、湿度数据线接GPIO引脚(如PA0),需接上拉电阻
继电器模块5V/10A单路继电器控制除湿机电源IN引脚接GPIO(如PA1),控制低电平有效
OLED显示屏0.96寸 SSD1306 I2C显示信息SCL接PB6,SDA接PB7(I2C1)
按键轻触开关设置参数、切换模式接GPIO(如PA2,PA3),配置为上拉输入
蜂鸣器有源蜂鸣器报警提示接GPIO(如PA4),低电平触发
水位传感器干簧管/浮球开关检测水箱是否满接GPIO(如PA5),配置为上拉输入

关键硬件连接详解:

  • DHT11:这是一个单总线数字传感器。只需要一根数据线。STM32的GPIO引脚需要配置为开漏输出模式,并外部接一个4.7K-10K的上拉电阻到VCC。通信时序要求严格,需要微秒级延时,通常用定时器或DWT周期计数器实现。
  • 继电器:继电器模块的“IN”信号引脚为低电平(0V)时,继电器吸合(常开触点闭合);高电平(5V/3.3V)时断开。STM32的GPIO输出高电平为3.3V,对于5V供电的继电器模块,这个电压可能无法可靠使其断开。因此,建议选用支持3.3V控制的继电器模块,或者在GPIO与继电器IN引脚之间增加一个电平转换电路或三极管驱动电路。在原理图中,这部分隔离和驱动设计至关重要。
  • OLED (I2C):连接简单,但需注意I2C总线上需要接上拉电阻(通常模块已集成)。在代码中需要正确实现I2C的读写函数。
  • 电源:STM32开发板通常由USB供电(5V)。继电器模块如果驱动大负载,建议单独供电,并与STM32的GND共地。绝对禁止将220V强电部分与STM32弱电部分有任何直接的电气连接,继电器是实现强弱电隔离的关键器件。

3. 基于STM32CubeMX创建工程与配置

理解了硬件连接后,我们可以使用STM32CubeMX来图形化地配置引脚和生成代码框架,这能极大减少底层驱动代码的编写工作量。

3.1 创建新工程与芯片选型

  1. 打开STM32CubeIDE,选择File -> New -> STM32 Project
  2. 在芯片选择器中,输入STM32F103C8,选择STM32F103C8Tx,点击Next
  3. 为工程命名,例如Smart_Dehumidifier,选择保存路径,点击Finish。CubeMX配置界面会自动打开。

3.2 图形化引脚与时钟配置

Pinout & Configuration标签页下进行配置:

  1. 系统核心(SYS)

    • System Core -> SYS中,将Debug设置为Serial Wire。这是ST-LINK调试所必需的。
  2. 时钟(RCC)

    • System Core -> RCC中,将High Speed Clock (HSE)设置为Crystal/Ceramic Resonator。这表示我们使用外部高速晶振(通常开发板上是8MHz)。
  3. GPIO引脚配置

    • 根据之前的硬件连接表,在芯片图形上点击对应引脚,选择其功能。
    • PA0: 设置为GPIO_Input,用于DHT11数据线。由于DHT11需要切换输入输出模式,这里先设为输入,代码中动态切换。
    • PA1: 设置为GPIO_Output,初始输出电平为High(继电器断开状态),用于控制继电器。
    • PA2, PA3: 设置为GPIO_Input,并激活内部上拉电阻(Pull-up),用于按键。
    • PA4: 设置为GPIO_Output,初始输出High(蜂鸣器不响),用于控制蜂鸣器。
    • PA5: 设置为GPIO_Input,激活内部上拉电阻,用于水位传感器。
    • PB6, PB7: 设置为I2C1_SCLI2C1_SDA,用于OLED显示屏。
  4. 定时器(TIM)配置

    • 我们需要一个定时器来产生精确的微秒延时,用于驱动DHT11。
    • Timers -> TIM2(或其他空闲定时器)中,将Clock Source设为Internal Clock
    • Parameter Settings中,设置PrescalerCounter Period,使定时器计数频率为1MHz(即每计数一次为1微秒)。假设系统时钟为72MHz,则预分频器Prescaler设为72-1=71,计数器周期Counter Period设为最大值65535即可。开启定时器中断不是必须的,我们可以用查询方式。
  5. I2C配置

    • Connectivity -> I2C1中,将I2C Speed Mode设置为Standard Mode(100kHz) 或Fast Mode(400kHz)。SSD1306通常支持400kHz。
  6. 串口(USART)配置(用于调试打印)

    • Connectivity -> USART1中,将模式设置为Asynchronous
    • 参数设置:波特率115200,字长8 Bits,停止位1,无校验,无流控。

3.3 生成工程代码

  1. 点击Project Manager标签页。
  2. Project子标签中,选择Toolchain / IDESTM32CubeIDE
  3. Code Generator子标签中,勾选Generate peripheral initialization as a pair of ‘.c/.h’ files per peripheral,这会使外设代码更模块化。
  4. 点击右上角的GENERATE CODE按钮。STM32CubeIDE会自动生成完整的初始化代码工程。

4. 核心功能模块的代码实现与解析

生成了基础工程后,我们需要在Core/Src/main.c和自行创建的模块文件中添加业务逻辑。一个良好的实践是将不同功能封装成独立的.c/.h文件。

4.1 微秒延时函数实现(用于DHT11)

由于DHT11的时序要求精确到微秒级别,标准的HAL_Delay()(毫秒级)不适用。我们可以利用之前配置的定时器TIM2来实现。

Core/Src下新建dht11.cdht11.h

dht11.h头文件定义:

#ifndef __DHT11_H #define __DHT11_H #include "main.h" // 定义DHT11数据线连接的GPIO端口和引脚 #define DHT11_GPIO_PORT GPIOA #define DHT11_GPIO_PIN GPIO_PIN_0 // 函数声明 void DHT11_GPIO_Init(void); uint8_t DHT11_Read_Data(uint8_t *temperature, uint8_t *humidity); void DHT11_Delay_us(uint16_t us); // 微秒延时函数声明 #endif

dht11.c源文件实现(关键部分):

#include "dht11.h" #include "tim.h" // 包含TIM2的头文件 // 微秒延时函数,基于TIM2 void DHT11_Delay_us(uint16_t us) { __HAL_TIM_SET_COUNTER(&htim2, 0); // 定时器计数器清零 HAL_TIM_Base_Start(&htim2); // 启动定时器 while (__HAL_TIM_GET_COUNTER(&htim2) < us); // 等待计数值达到us HAL_TIM_Base_Stop(&htim2); // 停止定时器 } // DHT11初始化,将引脚设置为输出模式并输出起始信号 void DHT11_GPIO_Init(void) { GPIO_InitTypeDef GPIO_InitStruct = {0}; GPIO_InitStruct.Pin = DHT11_GPIO_PIN; GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP; // 推挽输出 GPIO_InitStruct.Pull = GPIO_NOPULL; GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW; HAL_GPIO_Init(DHT11_GPIO_PORT, &GPIO_InitStruct); HAL_GPIO_WritePin(DHT11_GPIO_PORT, DHT11_GPIO_PIN, GPIO_PIN_SET); // 先拉高 } // 读取DHT11数据(简化版,未包含完整的校验和超时处理) uint8_t DHT11_Read_Data(uint8_t *temp, uint8_t *humi) { uint8_t data[5] = {0}; uint8_t i, j; // 主机发送起始信号 HAL_GPIO_WritePin(DHT11_GPIO_PORT, DHT11_GPIO_PIN, GPIO_PIN_RESET); DHT11_Delay_us(18000); // 拉低至少18ms HAL_GPIO_WritePin(DHT11_GPIO_PORT, DHT11_GPIO_PIN, GPIO_PIN_SET); DHT11_Delay_us(30); // 拉高20-40us // 切换为输入模式,等待DHT11响应 GPIO_InitTypeDef GPIO_InitStruct = {0}; GPIO_InitStruct.Pin = DHT11_GPIO_PIN; GPIO_InitStruct.Mode = GPIO_MODE_INPUT; GPIO_InitStruct.Pull = GPIO_PULLUP; HAL_GPIO_Init(DHT11_GPIO_PORT, &GPIO_InitStruct); // ... (等待DHT11拉低、拉高响应信号) // ... (读取40位数据,判断高低电平持续时间) // ... (将5字节数据存入data数组) // 校验和检查 if(data[4] == (data[0] + data[1] + data[2] + data[3])) { *humi = data[0]; *temp = data[2]; return 1; // 读取成功 } return 0; // 读取失败 }

注意:以上是DHT11驱动的核心框架。完整的驱动需要精确判断DHT11的响应时序和每一位数据的电平持续时间(约26-28us为0,70us为1),并加入超时判断,代码较长。在实际项目中,建议参考成熟的开源驱动库。

4.2 OLED显示驱动与界面逻辑

对于SSD1306 OLED,我们可以使用现有的开源驱动库,如OLED_SSD1306。将其oled.coled.hfont.h等文件添加到工程中。

Core/Src/main.c中,我们需要初始化OLED并显示信息。

/* 在main函数开头变量定义部分 */ uint8_t current_temp, current_humi; uint8_t set_humi_threshold = 55; // 默认设定湿度阈值 uint8_t system_state = 0; // 0:停止,1:运行,2:水箱满报警 /* 在main函数初始化部分,while(1)之前 */ HAL_Init(); SystemClock_Config(); MX_GPIO_Init(); MX_TIM2_Init(); // 初始化微秒延时定时器 MX_I2C1_Init(); MX_USART1_UART_Init(); OLED_Init(); // 初始化OLED OLED_Clear(); DHT11_GPIO_Init(); /* 在while(1)循环中 */ // 1. 读取传感器数据 if(DHT11_Read_Data(&current_temp, ¤t_humi)) { // 2. 更新显示 OLED_ShowString(0, 0, "Temp:", 16); OLED_ShowNum(40, 0, current_temp, 2, 16); OLED_ShowString(60, 0, "C", 16); OLED_ShowString(0, 2, "Humi:", 16); OLED_ShowNum(40, 2, current_humi, 2, 16); OLED_ShowString(60, 2, "%", 16); OLED_ShowString(0, 4, "SetH:", 16); OLED_ShowNum(40, 4, set_humi_threshold, 2, 16); OLED_ShowString(60, 4, "%", 16); // 3. 控制逻辑判断 uint8_t water_full = HAL_GPIO_ReadPin(WATER_SENSOR_GPIO_Port, WATER_SENSOR_Pin); if(water_full == GPIO_PIN_RESET) { // 假设传感器满水时输出低电平 system_state = 2; // 水箱满 HAL_GPIO_WritePin(RELAY_GPIO_Port, RELAY_Pin, GPIO_PIN_SET); // 强制停止除湿 HAL_GPIO_WritePin(BUZZER_GPIO_Port, BUZZER_Pin, GPIO_PIN_RESET); // 报警 OLED_ShowString(0, 6, "State: FULL!", 16); } else { HAL_GPIO_WritePin(BUZZER_GPIO_Port, BUZZER_Pin, GPIO_PIN_SET); // 关闭报警 if(current_humi > set_humi_threshold + 5) { // 当前湿度高于设定值+迟滞 system_state = 1; HAL_GPIO_WritePin(RELAY_GPIO_Port, RELAY_Pin, GPIO_PIN_RESET); // 拉低,继电器吸合,开始除湿 OLED_ShowString(0, 6, "State: RUN ", 16); } else if(current_humi < set_humi_threshold - 5) { // 当前湿度低于设定值-迟滞 system_state = 0; HAL_GPIO_WritePin(RELAY_GPIO_Port, RELAY_Pin, GPIO_PIN_SET); // 拉高,继电器断开,停止除湿 OLED_ShowString(0, 6, "State: STOP ", 16); } } } else { OLED_ShowString(0, 6, "DHT11 Error!", 16); } HAL_Delay(2000); // 每2秒读取一次

4.3 按键扫描与参数设置

为了允许用户修改湿度阈值,我们需要实现按键扫描功能。通常采用状态机或简单的延时消抖方式。

// 在main.c中定义一个按键扫描函数 void Key_Scan(void) { static uint8_t key1_last_state = 1; static uint8_t key2_last_state = 1; uint8_t key1_current = HAL_GPIO_ReadPin(KEY1_GPIO_Port, KEY1_Pin); uint8_t key2_current = HAL_GPIO_ReadPin(KEY2_GPIO_Port, KEY2_Pin); // 按键1按下(假设低电平有效),增加设定湿度 if(key1_current == 0 && key1_last_state == 1) { HAL_Delay(10); // 简单消抖 if(HAL_GPIO_ReadPin(KEY1_GPIO_Port, KEY1_Pin) == 0) { set_humi_threshold++; if(set_humi_threshold > 80) set_humi_threshold = 80; // 上限 // 可以在这里将set_humi_threshold保存到EEPROM } } key1_last_state = key1_current; // 按键2按下,减少设定湿度 if(key2_current == 0 && key2_last_state == 1) { HAL_Delay(10); if(HAL_GPIO_ReadPin(KEY2_GPIO_Port, KEY2_Pin) == 0) { set_humi_threshold--; if(set_humi_threshold < 30) set_humi_threshold = 30; // 下限 // 保存到EEPROM } } key2_last_state = key2_current; }

while(1)循环中调用Key_Scan()函数即可。

5. 系统联调、验证与常见问题排查

代码编写完成后,需要编译、下载到开发板,并进行实际测试。这个阶段最容易遇到各种问题。

5.1 编译与下载

  1. 在STM32CubeIDE中,点击工具栏上的锤子图标进行编译。确保0错误,0警告(一些未使用的变量警告可暂时忽略)。
  2. 将ST-LINK通过SWD接口与开发板连接好,并给开发板上电。
  3. 点击虫子图标进入调试模式,程序会自动下载并运行。或者点击绿色播放箭头直接下载并复位运行。

5.2 功能验证步骤

按照以下顺序验证系统功能:

  1. 电源与显示:上电后,观察OLED屏幕是否点亮并显示初始界面(如温度、湿度、设定值、状态)。
  2. 传感器读取:用手握住DHT11传感器,观察屏幕上的温湿度数值是否发生变化。如果显示“DHT11 Error”,则说明通信失败。
  3. 按键功能:按下增加/减少按键,观察“SetH”(设定湿度)数值是否随之变化。
  4. 控制逻辑
    • 用嘴对DHT11哈气(增加湿度),使其读数超过“设定值+5”。观察状态是否变为“RUN”,同时继电器模块的指示灯是否亮起(或听到“咔哒”吸合声)。
    • 停止哈气,等待湿度下降至低于“设定值-5”。观察状态是否变为“STOP”,继电器是否断开。
  5. 报警功能:模拟水箱满的状态(将水位传感器的输入引脚短接到地),观察状态是否变为“FULL!”,蜂鸣器是否鸣叫,继电器是否强制断开。

5.3 常见问题与排查路径

在调试过程中,你可能会遇到以下典型问题:

问题现象可能原因排查步骤与解决方案
OLED不显示1. I2C地址错误。
2. I2C引脚接反或接触不良。
3. 初始化时序或命令错误。
4. 电源问题。
1. 用逻辑分析仪或示波器抓取I2C波形,确认是否有起始信号、地址和数据。SSD1306的I2C地址通常是0x78或0x7A。
2. 检查PB6、PB7连接,确认上拉电阻(4.7K-10K)已接好。
3. 核对OLED驱动库的初始化序列,特别是复位引脚(如果有)的时序。
4. 测量OLED模块VCC电压是否为3.3V或5V(视模块而定)。
DHT11读取失败1. 时序不精确,微秒延时不准。
2. 引脚模式切换错误。
3. 未接上拉电阻。
4. 传感器损坏或接触不良。
1. 使用示波器或逻辑分析仪监测DHT11数据线波形,对照数据手册检查起始信号、响应信号和各数据位时长。
2. 确保在发送起始信号时为输出模式,等待响应和读取数据时为输入上拉模式。
3. 在数据线和VCC之间连接一个4.7K电阻。
4. 更换传感器测试。
继电器不动作1. STM32 GPIO输出电流不足。
2. 继电器模块控制逻辑弄反(高/低电平有效)。
3. 继电器模块供电不足。
4. 负载过大或短路。
1. STM32 GPIO最大输出电流约20mA,检查继电器模块IN端所需电流,过大则需要加三极管驱动。
2. 用万用表测量继电器IN端电压,当代码输出GPIO_PIN_RESET(0V)时,IN端应为低电平。根据模块规格书确认控制逻辑。
3. 确保继电器模块的VCC和GND供电稳定(5V或3.3V)。
4.特别注意:调试强电部分务必断电操作,确保安全。先空载测试继电器动作声音,再接负载。
按键不灵敏或连击1. 消抖处理不当。
2. 扫描频率太快或太慢。
3. 硬件上拉电阻未启用或失效。
1. 采用状态机或更可靠的消抖算法,避免在中断或循环中简单使用HAL_Delay
2. 将按键扫描放在主循环中,周期在10-50ms为宜。
3. 确认GPIO配置为输入上拉模式,或硬件有上拉电阻。
程序运行不稳定,偶尔死机1. 堆栈溢出。
2. 中断冲突或优先级设置不当。
3. 电源纹波大。
4. 看门狗未处理。
1. 在STM32CubeIDE的工程属性中,适当增大Stack SizeHeap Size(如从0x400增加到0x800)。
2. 检查是否在中断服务程序(如定时器中断)中执行了耗时操作或调用了HAL_Delay
3. 用示波器测量开发板电源电压,尤其在继电器动作时是否有大幅跌落。
4. 如果使能了独立看门狗(IWDG),需要在主循环中定期“喂狗”。

6. 从原型到产品:最佳实践与扩展方向

一个能在实验室运行的原型,与一个稳定可靠的产品之间,还有不少距离。以下是一些提升系统鲁棒性和功能性的建议。

6.1 系统稳定性与可靠性增强

  1. 增加看门狗:启用STM32内部的独立看门狗(IWDG)或窗口看门狗(WWDG),在主循环或定时中断中定期喂狗。当程序跑飞或陷入死循环时,看门狗会自动复位系统,提高容错能力。
  2. 参数掉电保存:将用户设定的湿度阈值、系统配置等参数保存到STM32内部的Flash或外置的EEPROM芯片(如AT24C02)中。避免每次上电都需要重新设置。
    // 示例:使用HAL库操作内部Flash保存一个字节数据(需注意擦写寿命) #define SETTINGS_FLASH_ADDR 0x0800FC00 // 选择Flash末尾的某一页 void Save_Settings(void) { HAL_FLASH_Unlock(); FLASH_EraseInitTypeDef EraseInitStruct; uint32_t PageError = 0; EraseInitStruct.TypeErase = FLASH_TYPEERASE_PAGES; EraseInitStruct.PageAddress = SETTINGS_FLASH_ADDR; EraseInitStruct.NbPages = 1; HAL_FLASHEx_Erase(&EraseInitStruct, &PageError); HAL_FLASH_Program(FLASH_TYPEPROGRAM_HALFWORD, SETTINGS_FLASH_ADDR, set_humi_threshold); HAL_FLASH_Lock(); }
  3. 传感器数据滤波:直接读取的传感器数据可能存在毛刺。可以采用滑动平均滤波、中值滤波或一阶低通滤波算法,使显示和控制更加平滑稳定。
    #define FILTER_LEN 5 uint8_t humi_buf[FILTER_LEN] = {0}; uint8_t humi_index = 0; uint8_t Get_Filtered_Humidity(uint8_t new_val) { humi_buf[humi_index] = new_val; humi_index = (humi_index + 1) % FILTER_LEN; uint16_t sum = 0; for(int i=0; i<FILTER_LEN; i++) sum += humi_buf[i]; return (uint8_t)(sum / FILTER_LEN); }
  4. 异常状态处理:除了水箱满,还应考虑传感器长时间无响应、通信持续失败、环境温度超出传感器量程等异常情况,并设置相应的系统状态和提示。

6.2 功能扩展方向

  1. 增加通信模块
    • Wi-Fi (ESP8266/ESP32):通过AT指令或SDK,让STM32将数据发送给ESP模块,模块再连接MQTT服务器(如阿里云、腾讯云物联网平台)。实现手机APP远程查看和控制。
    • 蓝牙 (HC-05/06):与手机APP进行短距离通信,实现本地无线控制和数据查看。
  2. 升级传感器:将DHT11更换为更精确、更快速的数字传感器,如DHT22、SHT30、AHT20等。这些传感器通常使用I2C接口,通信更可靠,精度更高。
  3. 实现PID控制:对于要求更高的除湿场景,可以使用PID算法来控制继电器的通断时间(PWM占空比),实现更平滑的湿度控制,而不是简单的开关控制。
  4. 增加更多人机交互:使用触摸屏、旋转编码器+菜单系统,实现更复杂的参数设置(如多个湿度档位、定时开关机、风速调节等)。
  5. 低功耗设计:如果系统由电池供电,需要进入低功耗模式。在非采集和控制时段,让STM32进入StopSleep模式,通过RTC定时唤醒或外部中断(按键)唤醒。

6.3 安全注意事项(重中之重)

  1. 强弱电隔离:继电器是隔离的关键,确保其线圈侧(控制端)与触点侧(负载端)之间没有电气连接。布线时,强电(220V)走线与弱电(STM32)走线应分开,避免平行走线,必要时使用屏蔽或开槽隔离。
  2. 电源安全:为继电器模块和STM32系统供电的电源适配器应有足够的功率余量和安全认证。强电部分接线必须牢固,使用绝缘端子,裸露部分用热缩管或绝缘胶带包裹。
  3. 软件互锁:在代码中,除湿动作(继电器闭合)必须同时满足多个条件:湿度超标、水箱未满、系统处于自动模式、无故障报警等。避免因单一条件误触发导致设备损坏。
  4. 外壳与防护:产品化时,必须使用符合安全标准的绝缘外壳,并考虑散热、防潮、防尘。

通过以上步骤,你不仅能够复现一个基本的STM32智能除湿系统,更能深入理解嵌入式系统开发中硬件选型、驱动编写、控制逻辑、调试排错和产品化思考的全过程。这个项目是一个优秀的起点,你可以基于它,结合具体的应用场景,不断迭代和扩展,最终打造出符合自己需求的智能硬件产品。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/8/21 2:14:24

从Claude到GLM:AI应用模型迁移实战与架构解耦指南

在实际的 AI 应用开发中&#xff0c;模型选型与集成是决定项目成败和长期维护成本的关键环节。当核心业务逻辑严重依赖某个大模型 API 时&#xff0c;一旦该服务出现访问问题、成本飙升或策略调整&#xff0c;整个应用就可能陷入停滞。我们最近就经历了一次这样的架构迁移&…

作者头像 李华
网站建设 2026/8/21 2:11:17

嵌入式软件架构设计:从概念到实战,解决代码混乱与维护难题

你是不是也遇到过这样的场景&#xff1a;接手一个老旧的嵌入式项目&#xff0c;代码像一团乱麻&#xff0c;功能模块之间纠缠不清&#xff0c;改一个BUG&#xff0c;三个地方报错&#xff1b;想加一个新功能&#xff0c;却发现无从下手&#xff0c;牵一发而动全身。或者&#x…

作者头像 李华
网站建设 2026/8/21 2:05:28

VMware替代方案实战指南:从技术选型到迁移验证

Broadcom 收购 VMware 已经过去两年&#xff0c;这场震动整个虚拟化与云计算行业的交易&#xff0c;其引发的连锁反应正进入一个全新的阶段。对于广大企业 IT 管理员、开发者和技术决策者而言&#xff0c;最核心的问题已经从“VMware 会变成什么样”转变为“现在有哪些可靠的替…

作者头像 李华
网站建设 2026/8/21 2:02:07

OpenAI暂停前沿模型强化学习训练两周 安全监控成本上升

OpenAI宣布暂停其最新部署模型的强化学习训练两周&#xff0c;同时将最大前沿RL运行保持暂停状态&#xff0c;直到完成更小规模训练和评估以验证安全措施。 这一决定直接源于2026年8月7日内部判定Astra模型达到“关键”网络安全能力阈值。判定依据包括7月Hugging Face泄露事件、…

作者头像 李华
网站建设 2026/8/21 1:53:21

声学相机电源设计:基于KU5P芯片的上电时序与PCB布局实战

这次我们来看一个面向声学相机产品的硬件设计课程&#xff0c;重点拆解其核心模块——基于KU5P芯片的电源系统设计与上电顺序控制。对于硬件工程师、嵌入式开发者以及从事声学成像、工业检测设备研发的团队来说&#xff0c;一个稳定可靠的电源方案是产品成败的基石。本文将直接…

作者头像 李华