从DHT11到OLED:手把手教你用STM32F103C8T6做一个会说话的智能加湿器(附完整代码和PCB)

张开发
2026/4/7 21:17:55 15 分钟阅读

分享文章

从DHT11到OLED:手把手教你用STM32F103C8T6做一个会说话的智能加湿器(附完整代码和PCB)
从DHT11到OLED用STM32打造会说话的智能加湿器实战指南在干燥的冬季或空调房里一个能自动调节湿度并友好提示的加湿器远比单纯喷雾的设备更贴心。本文将带你用最常见的STM32F103C8T6开发板俗称蓝莓板和基础外设模块从零搭建一个具备温湿度监测、自动控制与语音交互能力的智能加湿系统。不同于简单的Demo拼接我们会重点解决多模块协同时的典型问题——比如当继电器动作时OLED显示为何会闪烁语音播报如何避免打断主循环以及如何用状态机优雅地管理加湿逻辑。1. 硬件选型与电路设计要点1.1 核心器件选型对比选择硬件时我们需要在成本、精度和易用性之间找到平衡。下表对比了关键模块的常见选项模块类型推荐型号接口方式优势注意事项主控芯片STM32F103C8T6-性价比高社区资源丰富注意区分正版与兼容版温湿度传感DHT11单总线价格低廉接线简单±5%湿度精度响应较慢显示模块SSD1306 0.96寸I2C低功耗可视角度大需注意I2C地址(通常0x3C或0x3D)语音模块JR6001UART支持中文播报可自定义语音片段需预烧录语音文件继电器SRD-05VDC-SL-CGPIO触点容量10A满足加湿器需求需加续流二极管保护1.2 电源设计关键细节多模块供电时电源噪声是导致传感器读数异常的主要原因。建议采用以下方案主控与数字电路使用AMS1117-3.3V稳压芯片继电器单独由5V电源供电与主控共地在DHT11的VCC与GND之间添加0.1μF去耦电容注意继电器线圈通电瞬间会产生200-300mA的冲击电流若与传感器共用电源线可能导致DHT11通信失败。1.3 PCB布局实战技巧手工制板时这些布局原则能减少后期调试麻烦将继电器及其驱动电路远离模拟信号走线I2C总线(SCL/SDA)走线尽量等长必要时串联22Ω电阻为DHT11设计可插拔的排针接口方便更换测试在电源入口处放置LED指示灯便于观察供电状态2. 软件开发环境搭建与驱动编写2.1 开发工具链配置推荐使用VSCodePlatformIO生态进行开发比Keil更友好的代码管理体验# 在PlatformIO中安装必要库 pio lib install Adafruit SSD1306 pio lib install DHT sensor library pio lib install Wire2.2 DHT11驱动优化标准库读取DHT11时容易因时序问题失败这里给出带超时检测的改进版本#define DHT11_TIMEOUT 1000 // 超时时间(us) uint8_t DHT11_ReadByte() { uint8_t data 0; for(int i0; i8; i) { uint32_t start micros(); while(!DHT11_READ_PIN (micros()-start)DHT11_TIMEOUT); delayMicroseconds(30); data 1; if(DHT11_READ_PIN) data | 1; start micros(); while(DHT11_READ_PIN (micros()-start)DHT11_TIMEOUT); } return data; }2.3 OLED显示状态机设计为避免频繁刷新导致闪烁采用状态机管理显示内容更新typedef enum { SHOW_NORMAL, // 显示温湿度 SHOW_SETTING, // 显示设置阈值 SHOW_WARNING // 显示报警信息 } DisplayState; void updateOLED(DisplayState state) { static uint32_t lastUpdate 0; if(millis() - lastUpdate 500) return; // 限频刷新 OLED.clearDisplay(); switch(state) { case SHOW_NORMAL: drawTemperatureHumidity(); break; case SHOW_SETTING: drawThresholdSettings(); break; case SHOW_WARNING: drawHumidityWarning(); break; } OLED.display(); lastUpdate millis(); }3. 多任务系统整合策略3.1 语音播报与主循环的协同JR6001语音模块的阻塞式播报会冻结主循环采用非阻塞方案解决创建语音任务队列QueueHandle_t voiceQueue; void setup() { voiceQueue xQueueCreate(5, sizeof(uint8_t)); } void playVoice(uint8_t voiceID) { xQueueSend(voiceQueue, voiceID, portMAX_DELAY); }在独立任务中处理语音void voiceTask(void *pv) { while(1) { uint8_t currentVoice; if(xQueueReceive(voiceQueue, currentVoice, 100/portTICK_PERIOD_MS)) { JR6001_Play(currentVoice); vTaskDelay(pdMS_TO_TICKS(50)); // 留出发送完成时间 } } }3.2 加湿控制PID算法实现简单的阈值控制容易导致频繁启停加入比例控制改善体验float calculatePID(float current, float target) { static float integral 0; static float lastError 0; float error target - current; integral error * 0.1; // 积分项 integral constrain(integral, -100, 100); float derivative (error - lastError) / 0.1; // 微分项 lastError error; return 0.8*error 0.1*integral 0.05*derivative; // PID系数 } void controlHumidifier() { float pidOut calculatePID(currentHumidity, targetHumidity); uint8_t pwmValue map(abs(pidOut), 0, 50, 0, 255); analogWrite(HUMIDIFIER_PIN, pidOut0 ? pwmValue : 0); }4. 系统调试与性能优化4.1 常见问题排查指南遇到以下问题时可以这样排查DHT11读数不稳定检查上拉电阻(4.7KΩ-10KΩ)是否接好缩短传感器与主控的连线距离(20cm)在读取失败时增加500ms延时再重试OLED显示乱码// 在I2C初始化后添加这些配置 Wire.setClock(400000); // 提升I2C时钟速度 OLED.begin(SSD1306_SWITCHCAPVCC, 0x3C); OLED.clearDisplay(); OLED.display(); // 首次清屏继电器触点火花在继电器线圈并联1N4007二极管触点两端并联0.1μF电容100Ω电阻组成的消弧电路4.2 功耗优化技巧需要电池供电时这些措施可延长续航将OLED改为间歇刷新模式void lowPowerOLED() { static bool displayOn true; if(millis() % 10000 8000) { // 每10秒显示8秒 if(!displayOn) { OLED.ssd1306_command(SSD1306_DISPLAYON); displayOn true; } } else if(displayOn) { OLED.ssd1306_command(SSD1306_DISPLAYOFF); displayOn false; } }降低主频至48MHzvoid setup() { SystemClock_Config(); // 修改时钟配置 __HAL_RCC_PLL_CONFIG(RCC_PLLSOURCE_HSI_DIV2, RCC_PLLMUL12); }5. 进阶功能扩展思路5.1 无线控制方案通过ESP-01S模块增加WiFi控制能力AT指令配置示例ATCWMODE1 // 设置为Station模式 ATCWJAPSSID,password // 连接WiFi ATCIPSTARTTCP,192.168.1.100,8080 // 建立TCP连接在STM32中解析网络指令void parseNetworkCmd(String cmd) { if(cmd.startsWith(HUM:)) { targetHumidity cmd.substring(4).toFloat(); playVoice(VOICE_SETTING_UPDATED); } }5.2 数据记录与可视化添加SD卡模块记录运行数据文件存储格式建议2023-12-01 14:30:00, 25.3, 45.2, ON 2023-12-01 14:31:00, 25.2, 47.8, ON 2023-12-01 14:32:00, 25.4, 52.1, OFF使用Python生成可视化报告import pandas as pd import matplotlib.pyplot as plt df pd.read_csv(humidity_log.csv) df.plot(xtime, y[temperature,humidity]) plt.savefig(report.png)在项目开发过程中最让我意外的是继电器对温湿度传感器的干扰程度。最初以为简单的软件滤波就能解决问题实际测试发现需要在硬件布局阶段就做好隔离。现在当加湿器用温柔的女声提示当前湿度已达标时那种人机交互的愉悦感正是嵌入式开发的魅力所在。

更多文章