当前位置: 首页 > news >正文

保姆级教程:用STM32F103C8T6驱动DHT11,从接线到串口打印温湿度一气呵成

从零玩转STM32与DHT11:手把手实现温湿度监测系统

当你第一次拿到STM32开发板和DHT11传感器时,那种既兴奋又忐忑的心情我完全理解。本文将带你完成一个完整的温湿度监测项目,从硬件连接到代码编写,再到数据读取和显示,确保你能获得"第一次成功"的成就感。不同于普通的教程,我会分享一些实际项目中容易踩的坑和调试技巧。

1. 硬件准备与连接

在开始编程之前,正确的硬件连接是项目成功的基础。你需要准备以下组件:

  • STM32F103C8T6最小系统板(蓝色药丸板)
  • DHT11温湿度传感器模块
  • USB转TTL串口模块(如CH340G)
  • 杜邦线若干(建议使用不同颜色区分功能)

关键连接步骤:

  1. 电源连接

    • 将DHT11的VCC引脚连接到STM32的3.3V电源
    • 将DHT11的GND引脚连接到STM32的地线
  2. 数据线连接

    • 将DHT11的DATA引脚连接到STM32的PA1引脚(可根据需要更改)
  3. 串口连接(用于调试输出):

    • 连接STM32的PA9(TX)到USB转TTL模块的RX
    • 连接STM32的PA10(RX)到USB转TTL模块的TX
    • 共地连接(GND到GND)

注意:DHT11模块有上拉电阻版本和无上拉电阻版本。如果是无上拉版本,需要在DATA线和VCC之间接一个4.7kΩ的上拉电阻。

常见连接错误及排查:

现象可能原因解决方法
DHT11完全不响应电源接反或电压不足检查VCC和GND连接,确保供电3.3-5V
数据不稳定未接上拉电阻添加4.7kΩ上拉电阻
串口无输出TX/RX接反交换TX和RX连接

2. 开发环境配置

工欲善其事,必先利其器。我们需要搭建完整的开发环境:

  1. 安装Keil MDK

    • 下载并安装Keil MDK-ARM最新版本
    • 安装STM32F1系列设备支持包
  2. 创建新工程

    Project → New μVision Project → 选择STM32F103C8T6设备
  3. 配置工程选项

    • 在"Target"选项卡中,勾选"Use MicroLIB"(便于使用printf)
    • 在"C/C++"选项卡的"Define"中添加:USE_STDPERIPH_DRIVER
  4. 添加必要库文件

    • STM32标准外设库
    • 串口通信库
    • 系统时钟配置

关键配置代码示例(system_stm32f10x.c):

void SystemInit(void) { // 设置系统时钟为72MHz RCC->CFGR |= RCC_CFGR_PLLMULL9; RCC->CFGR |= RCC_CFGR_PLLSRC; RCC->CR |= RCC_CR_PLLON; while(!(RCC->CR & RCC_CR_PLLRDY)); RCC->CFGR |= RCC_CFGR_SW_PLL; while((RCC->CFGR & RCC_CFGR_SWS) != RCC_CFGR_SWS_PLL); }

3. DHT11驱动实现

DHT11采用单总线协议,通信时序是关键。让我们深入理解并实现驱动代码。

3.1 理解DHT11通信协议

DHT11的通信过程分为几个阶段:

  1. 主机启动信号

    • 拉低总线至少18ms
    • 然后拉高20-40μs等待DHT11响应
  2. DHT11响应

    • 拉低总线80μs作为响应信号
    • 然后拉高80μs准备发送数据
  3. 数据传输

    • 每位数据以50μs低电平开始
    • 高电平持续时间决定数据位值:
      • 26-28μs表示'0'
      • 70μs表示'1'
  4. 数据格式

    • 40位数据包含:
      • 16位湿度数据(整数+小数)
      • 16位温度数据(整数+小数)
      • 8位校验和

3.2 关键驱动代码实现

GPIO配置函数:

// 设置PA1为输出模式 void DHT11_IO_OUT(void) { GPIO_InitTypeDef GPIO_InitStructure; RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(GPIOA, &GPIO_InitStructure); } // 设置PA1为输入模式 void DHT11_IO_IN(void) { GPIO_InitTypeDef GPIO_InitStructure; RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU; GPIO_Init(GPIOA, &GPIO_InitStructure); }

复位和检测函数:

// 发送复位信号 void DHT11_Rst(void) { DHT11_IO_OUT(); // 设置为输出模式 DHT11_DQ_LOW; // 拉低DQ线 Delay_ms(20); // 保持至少18ms DHT11_DQ_HIGH; // 释放总线 Delay_us(30); // 主机等待20-40μs } // 检测DHT11响应 uint8_t DHT11_Check(void) { uint8_t retry = 0; DHT11_IO_IN(); // 设置为输入模式 // 等待DHT11拉低总线 while(DHT11_DQ_READ && retry<100) { retry++; Delay_us(1); } if(retry>=100) return 1; retry = 0; // 等待DHT11拉高总线 while(!DHT11_DQ_READ && retry<100) { retry++; Delay_us(1); } if(retry>=100) return 1; return 0; }

数据读取函数:

// 读取一个位 uint8_t DHT11_Read_Bit(void) { uint8_t retry = 0; while(DHT11_DQ_READ && retry<100) // 等待低电平 { retry++; Delay_us(1); } retry = 0; while(!DHT11_DQ_READ && retry<100) // 等待高电平 { retry++; Delay_us(1); } Delay_us(40); // 等待40μs后采样 return DHT11_DQ_READ ? 1 : 0; } // 读取一个字节 uint8_t DHT11_Read_Byte(void) { uint8_t i, dat = 0; for(i=0; i<8; i++) { dat <<= 1; dat |= DHT11_Read_Bit(); } return dat; } // 读取温湿度数据 uint8_t DHT11_Read_Data(uint8_t *temp, uint8_t *humi) { uint8_t buf[5]; uint8_t i; DHT11_Rst(); if(DHT11_Check() == 0) { for(i=0; i<5; i++) { buf[i] = DHT11_Read_Byte(); } // 校验数据 if((buf[0] + buf[1] + buf[2] + buf[3]) == buf[4]) { *humi = buf[0]; *temp = buf[2]; return 0; // 成功 } } return 1; // 失败 }

4. 系统集成与调试

现在我们将所有部分整合起来,实现完整的温湿度监测系统。

4.1 串口配置与printf重定向

为了方便调试和数据查看,我们需要配置串口并重定向printf:

// 串口初始化 void USART1_Init(uint32_t baudrate) { GPIO_InitTypeDef GPIO_InitStructure; USART_InitTypeDef USART_InitStructure; RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1 | RCC_APB2Periph_GPIOA, ENABLE); // 配置TX(PA9)为复用推挽输出 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(GPIOA, &GPIO_InitStructure); // 配置RX(PA10)为浮空输入 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; GPIO_Init(GPIOA, &GPIO_InitStructure); USART_InitStructure.USART_BaudRate = baudrate; USART_InitStructure.USART_WordLength = USART_WordLength_8b; USART_InitStructure.USART_StopBits = USART_StopBits_1; USART_InitStructure.USART_Parity = USART_Parity_No; USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None; USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx; USART_Init(USART1, &USART_InitStructure); USART_Cmd(USART1, ENABLE); } // printf重定向 int fputc(int ch, FILE *f) { USART_SendData(USART1, (uint8_t)ch); while(USART_GetFlagStatus(USART1, USART_FLAG_TC) == RESET); return ch; }

4.2 主程序实现

int main(void) { uint8_t temperature = 0; uint8_t humidity = 0; // 初始化系统时钟 SystemInit(); // 初始化DHT11 DHT11_Init(); // 初始化串口 USART1_Init(115200); printf("STM32 DHT11温湿度监测系统启动...\r\n"); while(1) { if(DHT11_Read_Data(&temperature, &humidity) == 0) { printf("温度: %d℃ 湿度: %d%%\r\n", temperature, humidity); } else { printf("读取DHT11数据失败!\r\n"); } Delay_ms(2000); // 每2秒读取一次 } }

4.3 常见问题与调试技巧

问题1:DHT11无响应

  • 检查电源连接是否正确
  • 确认上拉电阻是否接好(如有需要)
  • 检查DATA线连接是否牢固
  • 尝试降低通信速度(增加延时)

问题2:数据校验失败

  • 确保时序精确,特别是延时时间
  • 检查电源稳定性,电压波动会影响通信
  • 尝试缩短DATA线长度(最好不超过20cm)

问题3:串口无输出

  • 确认TX/RX连接正确
  • 检查波特率设置是否匹配
  • 验证printf重定向是否正确实现

调试技巧:

  1. 使用逻辑分析仪:可以直观地观察DHT11的通信时序,帮助定位问题。

  2. 分段调试

    printf("开始复位DHT11...\r\n"); DHT11_Rst(); printf("复位完成,等待响应...\r\n"); if(DHT11_Check() == 0) { printf("DHT11响应成功\r\n"); }
  3. 延时微调:不同批次的DHT11可能对时序要求略有不同,可以尝试微调延时参数。

5. 项目优化与扩展

基础功能实现后,我们可以考虑以下优化和扩展方向:

5.1 提高测量精度

虽然DHT11的精度有限,但我们可以通过软件方法提高稳定性:

  1. 多次测量取平均

    #define SAMPLE_TIMES 5 uint8_t get_average_temperature() { uint8_t sum = 0; uint8_t temp, humi; for(int i=0; i<SAMPLE_TIMES; i++) { if(DHT11_Read_Data(&temp, &humi) == 0) { sum += temp; } Delay_ms(100); } return sum / SAMPLE_TIMES; }
  2. 数据滤波:实现滑动平均滤波或中值滤波算法

5.2 低功耗优化

对于电池供电的应用,可以优化功耗:

  1. 间歇工作模式

    void enter_low_power_mode() { // 关闭不必要的外设 RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, DISABLE); // 配置为待机模式 PWR_EnterSTANDBYMode(); }
  2. 延长测量间隔:根据应用需求调整采样频率

5.3 添加显示功能

除了串口输出,可以添加OLED或LCD显示:

void show_on_oled(uint8_t temp, uint8_t humi) { OLED_Clear(); OLED_ShowString(0, 0, "Temperature:"); OLED_ShowNum(0, 2, temp, 2, 16); OLED_ShowString(0, 4, "Humidity:"); OLED_ShowNum(0, 6, humi, 2, 16); }

5.4 无线传输扩展

通过添加ESP8266或蓝牙模块实现无线数据传输:

void send_via_wifi(uint8_t temp, uint8_t humi) { char buffer[50]; sprintf(buffer, "AT+CIPSEND=%d", strlen(buffer)); ESP8266_SendCmd(buffer); sprintf(buffer, "temp=%d&humi=%d", temp, humi); ESP8266_SendData(buffer); }

6. 实际应用案例

让我们看一个将本项目应用于智能家居系统的实际案例:

智能植物监控系统

  1. 硬件组成

    • STM32F103C8T6主控
    • DHT11温湿度传感器
    • 土壤湿度传感器
    • 继电器控制的水泵
    • OLED显示屏
  2. 系统逻辑

    void plant_monitor_system() { uint8_t temp, humi; uint16_t soil_moisture; while(1) { // 读取环境数据 DHT11_Read_Data(&temp, &humi); soil_moisture = read_soil_moisture(); // 显示数据 show_on_oled(temp, humi, soil_moisture); // 控制逻辑 if(soil_moisture < THRESHOLD) { pump_on(); Delay_ms(5000); // 浇水5秒 pump_off(); } Delay_ms(60000); // 每分钟检查一次 } }
  3. 扩展功能

    • 通过WiFi上传数据到云平台
    • 设置手机APP远程监控
    • 添加光照传感器优化植物生长环境

在完成这个项目后,我发现最关键的还是对DHT11时序的精确控制。实际测试中,不同环境温度下,延时参数可能需要微调才能获得最稳定的数据。建议在正式产品中使用更高精度的传感器,如SHT30或BME280,但对于学习和原型开发,DHT11仍然是一个经济实惠的选择。

http://www.jsqmd.com/news/853563/

相关文章:

  • 机器人旋转变形逻辑分析
  • 使用Python快速编写第一个调用Taotoken多模型服务的对话程序
  • AI写教材的秘密武器!低查重工具,精准打造高质量专业教材!
  • 给娃讲编程:用ICode的Python游戏关卡,趣味理解for循环和变量自增自减
  • 嵌入式OTA更新:从架构设计到安全实现的完整指南
  • 多线路环境下 Tailscale 如何选择最优 DERPS 服务器节点
  • Fog Project 部署与实战配置指南
  • 如何快速掌握MifareOneTool:Windows平台最强NFC卡片管理完全指南
  • 别再只把CLIP当分类器了:手把手教你用HuggingFace Transformers玩转以图搜图
  • 终极指南:使用Driver Store Explorer彻底清理Windows冗余驱动,快速释放C盘空间
  • 如何快速配置专业歌词同步工具:macOS用户的完整攻略
  • 2026年,如何挑选靠谱的GEO优化公司? - 品牌企业推荐师(官方)
  • 如何用Akagi雀魂AI辅助工具在30天内成为麻将高手
  • Lenovo Legion Toolkit源码级架构揭秘:高性能笔记本管理工具的实现原理与优化实践
  • 【数据结构与算法】-二叉树(2):实现顺序结构二叉树(堆的实现),向上调整算法,向下调整算法,堆排序,TOP-K问题
  • KUKA 虚拟调试实战——打通Simpro4.1与OfficeLite8.6的通信与实时控制链路
  • 使用Taotoken后我的大模型API延迟与稳定性体感观察
  • RoCEv2网络性能调优笔记:当你的AI训练集群遇到网络拥塞时,PFC和ECN到底谁先干活?
  • MIUI手机管家自动任务还能这么玩?手把手教你用备用机+智能插座实现远程打卡(附详细避坑指南)
  • SAR船舶检测数据集(SSDD)终极指南:从入门到精通
  • 2026年5月最新 30米量程一体式超声波液位计十大品牌评选 - 液体流量液位品牌推荐
  • 为OpenClaw智能体工作流配置Taotoken作为稳定的后端大模型服务提供商
  • VMware Unlocker 4.2.7终极指南:在非苹果硬件上高效运行macOS虚拟机
  • Taotoken API Key管理功能实现团队权限与访问控制
  • Faster-Whisper-GUI日语语音识别优化指南:3个关键技巧解决你的日语转写难题
  • 从AMBA1到AMBA5:20年演进,一文看懂ARM总线如何重塑SoC设计
  • 【天津线下、IEEE出版、连续五届EI检索】第六届控制与智能机器人国际学术会议(ICCIR 2026)
  • 告别杂乱排版!用ArcGIS Desktop布局工具,从零制作一张专业地图海报(附模板)
  • AI教材生成神器,低查重保障,快速产出符合要求的专业教材!
  • 用 NerfStudio 快速重建手办/商品:从手机拍照到 3D 模型的完整流程