保姆级教程:用STM32F103C8T6和DHT11做个温湿度计(附完整代码和时序图解析)

张开发
2026/4/15 22:34:58 15 分钟阅读

分享文章

保姆级教程:用STM32F103C8T6和DHT11做个温湿度计(附完整代码和时序图解析)
从零打造STM32温湿度监测仪DHT11单总线通信全解析项目背景与硬件选型去年夏天我在帮朋友调试一个智能花房项目时第一次接触DHT11温湿度传感器。当时为了搞明白那个看似简单却暗藏玄机的单总线协议整整花了三个晚上反复调试。现在回想起来如果能有一份详尽的实操指南至少能节省一半时间。这正是我写这篇教程的初衷——让你用最短的时间完整掌握STM32与DHT11的协作奥秘。核心硬件选择依据STM32F103C8T6Blue Pill开发板72MHz主频的Cortex-M3内核GPIO响应速度完全满足DHT11的微妙级时序要求DHT11传感器模块3.3V-5.5V宽电压设计直接输出数字信号省去ADC转换环节杜邦线若干建议使用不同颜色区分电源、地线和数据线提示购买DHT11时注意选择带PCB板的版本这种模块已经内置上拉电阻可简化电路设计硬件连接与开发环境搭建1.1 物理连接示意图将面包板平放按以下顺序连接组件电源部分STM32的3.3V引脚 → DHT11的VCC引脚红色线STM32的GND引脚 → DHT11的GND引脚黑色线数据通信STM32的PA1引脚 → DHT11的DATA引脚黄色线若使用裸片DHT11需在DATA与VCC间接4.7kΩ上拉电阻# 接线验证命令需安装OpenOCD openocd -f interface/stlink-v2.cfg -f target/stm32f1x.cfg1.2 开发工具链配置推荐使用PlatformIO VSCode组合比传统Keil开发更高效安装VSCode后搜索安装PlatformIO IDE插件新建项目时选择STM32F103C8作为开发板修改platformio.ini配置文件[env:bluepill_f103c8] platform ststm32 board bluepill_f103c8 framework libopencm3 upload_protocol stlink单总线协议深度解析2.1 时序图拆解DHT11的通信过程就像两个严格遵守时间的舞者每个动作都有精确的时间要求起始信号主机发起拉低总线 ≥18ms实际取20ms更保险拉高20-40μs取中间值30μs响应阶段传感器回复DHT11拉低80μsDHT11拉高80μs数据传输每个bit以50μs低电平开始高电平持续时间决定数值26-28μs → 070μs → 1图示用示波器捕获的实际波形标注各阶段时间参数2.2 数据帧结构DHT11每次传输40位5字节数据格式如下字节序号数据内容说明0湿度整数部分范围20-90%RH1湿度小数部分固定为0DHT11无小数2温度整数部分范围0-50℃3温度小数部分固定为04校验和前四字节和的低8位校验示例 若收到数据0x35 0x00 0x18 0x00 0x4D计算0x35 0x00 0x18 0x00 0x4D → 校验通过代码实现与调试技巧3.1 GPIO配置要点在STM32上实现精确的微秒级控制需要特别注意GPIO模式设置// GPIO初始化函数 void DHT11_GPIO_Init(void) { rcc_periph_clock_enable(RCC_GPIOA); gpio_set_mode(GPIOA, GPIO_MODE_OUTPUT_50_MHZ, GPIO_CNF_OUTPUT_PUSHPULL, GPIO1); }注意切换输入输出模式时必须重新配置GPIO寄存器这是新手常踩的坑3.2 核心驱动代码以下是经过实战检验的驱动程序包含详细的超时处理#define DHT11_TIMEOUT 100 uint8_t DHT11_Read_Byte(void) { uint8_t data 0; for(int i0; i8; i) { while(!gpio_get(GPIOA, GPIO1) timeout DHT11_TIMEOUT); delay_us(30); // 关键延时点 data 1; data | gpio_get(GPIOA, GPIO1) ? 1 : 0; while(gpio_get(GPIOA, GPIO1) timeout DHT11_TIMEOUT); } return data; }常见问题排查表现象可能原因解决方案一直返回255数据线接触不良检查杜邦线连接校验总是失败时序延时不精确调整delay_us()参数偶尔读取超时电源不稳定在VCC与GND间加100μF电容项目优化与扩展思路4.1 数据滤波算法原始数据常有小幅波动可加入滑动平均滤波#define FILTER_SIZE 5 typedef struct { float temp_buf[FILTER_SIZE]; float humi_buf[FILTER_SIZE]; uint8_t index; } DHT11_Filter; float Moving_Average(float *buf, float new_val) { buf[filter.index] new_val; filter.index (filter.index 1) % FILTER_SIZE; float sum 0; for(int i0; iFILTER_SIZE; i) { sum buf[i]; } return sum / FILTER_SIZE; }4.2 OLED显示集成升级项目用0.96寸OLED显示温湿度曲线硬件添加SSD1306 OLED屏幕I2C接口连接STM32的PB6(SCL)和PB7(SDA)软件库添加在PlatformIO中安装Adafruit SSD1306库移植u8g2图形库实现中文显示// OLED显示示例 void Show_Data(float temp, float humi) { char str[16]; sprintf(str, 温度:%.1f℃, temp); u8g2_DrawStr(u8g2, 0, 20, str); sprintf(str, 湿度:%.1f%%, humi); u8g2_DrawStr(u8g2, 0, 40, str); u8g2_SendBuffer(u8g2); }进阶调试技巧5.1 逻辑分析仪使用当代码无法正常工作时Saleae逻辑分析仪是排查时序问题的利器连接探头到DATA线设置采样率≥4MHz添加协议解码器选择Custom模式对照标准时序检查起始信号低电平持续时间bit间隔是否准确高低电平比例5.2 功耗优化方案对于电池供电场景需要特别关注功耗间隔采样模式void Enter_Stop_Mode(void) { PWR_CR | PWR_CR_LPDS; // 进入低功耗模式 __WFI(); // 等待中断唤醒 }硬件改进选用DHT11的低功耗版本DHT11A增加MOSFET控制传感器电源项目源码结构最终项目应采用模块化设计推荐目录结构/dht11_stm32 ├── inc │ ├── dht11.h # 传感器驱动头文件 │ └── oled.h # 显示模块头文件 ├── src │ ├── main.c # 主程序 │ ├── dht11.c # 驱动实现 │ └── oled.c # 显示实现 └── platformio.ini # 构建配置完整代码已托管在GitHub示例仓库地址包含带详细注释的驱动程序多种滤波算法实现预编译的hex文件原理图PDF版本

更多文章