MCU单片机 - STM32F103C8T6 驱动 DHT11 温湿度传感器详解
DHT11 是一种数字温湿度传感器,采用单总线协议通信,结构简单,易于使用,非常适合STM32微控制器进行学习和开发。本文基于STM32F103C8T6单片机,使用PB3口连接DHT11,详细讲解硬件连接、GPIO配置、单总线通信时序、数据接收与校验,并配备超详细注释代码和自定义延时函数。
一、硬件连接
- DHT11数据线连接STM32的PB3引脚
- VCC接5V或3.3V,GND接地
- 注意:数据线上最好加一个4.7kΩ的上拉电阻,确保总线空闲时处于高电平
二、单总线通信协议简介
DHT11的数据通信只有一根数据线,采用开漏结构,主机和从机通过电平的高低及持续时间传递信息:

三、关键代码详解(含自定义延时)
DHT11数据时序图如下:

1. 微秒延时函数(基于SysTick)
/*****************************************
函数功能:微秒级延时函数
参 数:xus - 延时的微秒数
返 回 值:无
备 注:使用SysTick计数器,时钟为72MHz/8=9MHz
计数器每个tick约0.111us,LOAD=9*xus-1实现xus微秒延时
******************************************/
void delay_us(u32 xus)
{
SysTick->CTRL &= ~(1 << 2); // 选择内部时钟HCLK/8(9MHz)
SysTick->LOAD = 9 * xus - 1; // 设定重装载值,计数9*xus个tick
SysTick->VAL = 0; // 清空当前计数值
SysTick->CTRL &= ~(1 << 1); // 禁止SysTick中断
SysTick->CTRL |= (1 << 0); // 启动SysTick计数器
while (!(SysTick->CTRL & (1 << 16))); // 等待计数器计数到0,自动清标志
SysTick->CTRL &= ~(1 << 0); // 关闭计数器
}
/*****************************************
函数功能:毫秒级延时函数
参 数:xms - 延时的毫秒数
返 回 值:无
备 注:循环调用delay_us实现毫秒延时
******************************************/
void delay_ms(u32 xms)
{
while (xms--)
{
delay_us(1000); // 1ms = 1000us
}
}
2. GPIO初始化及模式切换
#include "stm32f10x.h" // STM32F10x 标准库头文件
/*****************************************
函数功能:配置PB3为开漏输出模式(主机驱动数据线)
参 数:无
返 回 值:无
备 注:开漏输出允许总线被多个设备共享,未驱动时线被上拉
******************************************/
void DHT11_SetOutput(void)
{
GPIO_InitTypeDef GPIO_InitStruct = {0}; // 初始化结构体清零
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_3; // 选择PB3引脚
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_OD; // 开漏输出模式
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz; // 最高输出速度50MHz
GPIO_Init(GPIOB, &GPIO_InitStruct); // 初始化GPIOB口
}
/*****************************************
函数功能:配置PB3为浮空输入模式(接收数据线电平)
参 数:无
返 回 值:无
备 注:用于检测DHT11拉低或拉高状态,浮空输入避免内部上拉影响电平
******************************************/
void DHT11_SetInput(void)
{
GPIO_InitTypeDef GPIO_InitStruct = {0}; // 初始化结构体清零
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_3; // 选择PB3引脚
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IN_FLOATING; // 浮空输入模式
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz; // 速度参数无实际意义
GPIO_Init(GPIOB, &GPIO_InitStruct); // 初始化GPIOB口
}
3. DHT11初始化函数
/*****************************************
函数功能:DHT11初始化,开启GPIO时钟,配置PB3引脚,默认拉高总线
参 数:无
返 回 值:无
备 注:禁用JTAG复用,释放PB3,保证引脚可用
使用开漏输出,延时1秒,等待DHT11稳定
******************************************/
void DHT11_Init(void)
{
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE); // 使能GPIOB时钟
// 禁用JTAG复用,保留SWD调试,释放PB3引脚,避免复用冲突
GPIO_PinRemapConfig(GPIO_Remap_SWJ_JTAGDisable, ENABLE);
DHT11_SetOutput(); // 配置PB3为开漏输出
GPIO_SetBits(GPIOB, GPIO_Pin_3); // 拉高数据线,释放总线
delay_ms(1000); // 延时1秒,等待传感器稳定
}
4. 发送起始信号
/*****************************************
函数功能:主机发送起始信号,通知DHT11开始传输
参 数:无
返 回 值:无
备 注:拉低至少18ms,然后拉高,等待DHT11响应
******************************************/
void DHT11_StartSignal(void)
{
DHT11_SetOutput(); // 配置为开漏输出
GPIO_ResetBits(GPIOB, GPIO_Pin_3); // 拉低数据线,主机驱动
delay_ms(20); // 保持20ms以上,满足18ms最低要求
GPIO_SetBits(GPIOB, GPIO_Pin_3); // 释放总线,拉高数据线
delay_us(30); // 等待20~40us,为DHT11响应做准备
}
5. 等待DHT11响应信号
/*****************************************
函数功能:等待DHT11拉低再拉高响应信号
参 数:无
返 回 值:0 - 响应成功
1 - 无响应(拉低超时)
2 - 拉低持续超时(等待低电平超时)
3 - 拉高持续超时(等待高电平超时)
备 注:防止程序死循环卡死
******************************************/
u8 DHT11_WaitResponse(void)
{
u16 timeout = 0;
DHT11_SetInput(); // 切换为输入,监听数据线
// 等待DHT11拉低开始响应,低电平持续约80us
while (GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_3))
{
delay_us(1);
if (++timeout > 100) return 1; // 超时,未检测到拉低信号
}
timeout = 0;
// 等待DHT11释放低电平,开始拉高
while (!GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_3))
{
delay_us(1);
if (++timeout > 100) return 2; // 低电平持续超时
}
timeout = 0;
// 等待DHT11拉高结束
while (GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_3))
{
delay_us(1);
if (++timeout > 100) return 3; // 高电平持续超时
}
return 0; // 响应成功
}
6. 接收40位数据(5字节)
/*****************************************
函数功能:接收DHT11传来的40位数据
参 数:data - 长度为5的数组,用于存放接收的5字节数据
返 回 值:无
备 注:通过高电平宽度判别0或1,高电平持续时间长为1,短为0
高位优先传输,循环按字节和位读取
******************************************/
void DHT11_ReceiveData(u8* data)
{
u8 i, j;
for (i = 0; i < 5; i++) // 5字节循环
{
u8 byte = 0;
for (j = 0; j < 8; j++) // 8位循环
{
// 等待低电平结束(确保是新一位开始)
while (!GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_3));
delay_us(40); // 延时40us判断电平持续时间
// 判断当前高电平状态
if (GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_3))
{
// 高电平持续时间长,认为是1
byte |= (1 << (7 - j)); // 按位设置,高位先传
// 等待高电平结束,防止干扰下一位
while (GPIO\_ReadInputDataBit(GPIOB, GPIO\_Pin\_3));
}
// 若40us后低电平,认为0,不需设置位
}
data[i] = byte; // 存入对应字节
}
}
7. 读取温湿度数据
/*****************************************
函数功能:读取温湿度数据(整数部分)
参 数:temp_int - 指向温度整数变量指针
humi_int - 指向湿度整数变量指针
返 回 值:0 - 读取成功
1 - 无响应
2 - 校验失败
备 注:忽略小数部分和负温度,可根据需要扩展
******************************************/
u8 DHT11_Read(u8* temp_int, u8* humi_int)
{
u8 buf[5];
u8 sum;
DHT11_StartSignal(); // 主机发送起始信号
if (DHT11_WaitResponse()) // 等待DHT11响应,非0为失败
return 1;
DHT11_ReceiveData(buf); // 接收5字节数据
sum = buf[0] + buf[1] + buf[2] + buf[3]; // 计算校验和
if (sum != buf[4]) // 校验和错误
return 2;
*humi_int = buf[0]; // 湿度整数部分
*temp_int = buf[2]; // 温度整数部分
return 0; // 成功
}
四、主函数示例:串口实时打印温湿度,2秒刷新
#include "stm32f10x.h"
#include "dht11.h"
#include <stdio.h>
// 重定向printf到串口1
int fputc(int ch, FILE *f)
{
while(USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET);
USART_SendData(USART1, (uint8_t)ch);
return ch;
}
int main(void)
{
u8 ret;
u8 temperature = 0, humidity = 0;
SystemInit();
delay_init(); // 初始化延时函数
DHT11_Init(); // 初始化DHT11
USART1_Init(115200); // 初始化串口1
printf("System Init Complete, Starting DHT11 Reading...\r\n");
while (1)
{
ret = DHT11_Read(&temperature, &humidity);
if (ret == 0)
{
printf("Temperature: %d C, Humidity: %d%%\r\n", temperature, humidity);
}
else if (ret == 1)
{
printf("DHT11 no response!\r\n");
}
else if (ret == 2)
{
printf("DHT11 checksum error!\r\n");
}
delay_ms(2000); // 2秒刷新一次
}
}
五、总结
- DHT11的通信关键是开漏单线双向控制和严格的时序。
- GPIO模式切换为开漏输出与浮空输入,实现总线控制与监听。
- 延时函数保证微秒级准确延时,避免数据传输错误。
- 采用超时机制防止函数死循环。
- 校验和验证保证数据正确性。
- 主函数通过串口实时打印读取结果,方便调试和监控。
这套代码适合STM32F103C8T6开发板,用PB3口接DHT11,实测稳定可靠,代码注释详细,欢迎读者复制粘贴调试
(完)
相关推荐
基于STM32的智能家居控制系统设计.pdf
基于STM32的智能家居控制系统设计.pdf
STM32F103c8t6驱动DHT11温湿度在串口上打印温湿度(其它f103系列都可以用,直接移植这个库,修改下引脚就行)STM32驱动DHT11的库,可以直接移植
在物联网和嵌入式系统开发中,温湿度监测是常见的基础功能需求。本文将详细介绍如何使用STM32F103c8t6单片机驱动DHT11数字温湿度传感器,并提供完整的代码解析,源码每条都进行了注释。资源链接包含了整个代码工程和DHT11的数据手册,需要自行下载单总线数字信号输出湿度测量范围:20-90%RH(±5%RH)温度测量范围:0-50℃(±2℃)供电电压:3.3-5.5V典型功耗:0.5mA(测量时)
STM32宿舍防火防盗系统[项目源码]
本文介绍了一个基于STM32单片机的宿舍防火防盗控制系统设计,该系统通过STM32单片机结合LCD1602显示屏、DHT11温湿度传感器、电机、电位器、蜂鸣器、LED和开关等组件实现多功能监控。系统能够实时监测烟雾浓度(通过电位器模拟),当浓度超过设定阈值(如50)时,触发声光报警并自动启动灭火水泵。同时,布防开关可模拟红外人体检测,检测到入侵时同样触发报警并在LCD上显示状态。此外,系统还能采集并显示宿舍的实时温湿度数据。设计使用C语言编程,Keil5编写代码,Proteus进行仿真,适合新手学习。资料包含仿真视频、源程序(含中文注释)及相关软件包,方便用户下载和使用。
32单片机温湿度光敏检测系统[项目代码]
本文介绍了一个基于STM32单片机的温湿度光敏检测系统设计。系统通过DHT11温湿度传感器和光敏传感器实时检测环境参数,并通过LCD1602显示模块展示数据。系统具备温湿度阈值设置功能,当温度或湿度超过设定上限时,启动降温除湿模块并触发报警;低于下限时,启动升温增湿模块并报警。光照强度低于阈值时自动开灯,高于阈值则关灯。硬件部分包括32单片机核心模块、按键模块、传感器模块、蜂鸣器模块、继电器模块和LCD显示模块。软件设计部分详细介绍了外部中断处理、数据显示、阈值设置和报警功能的具体实现。系统通过仿真验证了其功能,能够有效监测和控制环境参数。
stm32单片机项目资料课程设计文档C语言程序代码原理图电路PCB实例无线数据传输系统的设计与实现
stm32单片机项目资料课程设计文档C语言程序代码原理图电路PCB实例无线数据传输系统的设计与实现


