一、传感器核心特性与技术解析

1. 传感器构成与工作原理

DHT11采用电容式感湿元件+NTC测温元件的复合传感方案,内部集成8位单片机处理模块。其工作流程分为三个阶段:

  1. 采样阶段:NTC热敏电阻通过惠斯通电桥测量温度,湿敏电容通过充放电特性检测湿度
  2. 模数转换:内置14位ADC将模拟信号转换为数字信号
  3. 数据封装:通过单总线协议将40位数据(湿度整数+湿度小数+温度整数+温度小数+校验和)传输至主机

1. 关键参数

项目 参数指标 技术说明
供电电压 3.3-5.5V 支持宽压输入,兼容STM32/51等主流MCU
测量范围 温度:0-50℃ / 湿度:20-90%RH 极端环境需外接保护电路
精度 温度±2℃ / 湿度±5%RH 长期使用需定期校准
采样周期 ≥2s 频繁读取会导致数据错误

二、工作原理与通信协议

1. 单总线通信时序

DHT11通过单根数据线实现双向通信,关键时序包括:

  • 起始信号:主机拉低总线18-30ms后释放
  • 响应信号:DHT11拉低总线83±5ms后拉高响应
  • 数据传输:每bit以50μs低电平开始,高电平长度区分0/1(26-28μs为0,70μs为1)

原理图补充:

图一: 主机发送起始信号

图二:从机相应信号

2. 数据发送方式:

        由DHT11的DATA引脚输出40位数据,微处理器根据I/O电平的变化接收40位数据,位数据 “0”的格式为:54微秒的低电平和23-27微秒的高电平,位数据“1”的格式为:54微秒的低 电平加68-74微秒的高电平。

3. 数据格式解析

40位数据结构:

8bit湿度整数 | 8bit湿度小数 | 8bit温度整数 | 8bit温度小数 | 8bit校验和

校验和=前4字节之和的末8位,需验证数据有效性

三、硬件连接示例

典型电路连接(以STM32为例):

DHT11引脚定义:
1: VCC   2: DATA   3: GND
  • DATA引脚接STM32的GPIO(如PA6)
  • 供电电压建议稳定在3.3-5.0V

四、代码实现(基于STM32 HAL库)

//DHT11.c

#include "stm32f10x.h"                  // Device header
#include "Delay.h"
#include "DHT11.h"
 
//配置DHT11为输出模式
void DHT11_Output_Mode(void)
{
	GPIO_InitTypeDef GPIO_InitStructure;
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
	GPIO_InitStructure.GPIO_Pin   = DHT11_GPIO_PIN; 	
	GPIO_InitStructure.GPIO_Mode  = GPIO_Mode_Out_PP;	//推挽输出
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(DHT11_GPIO_PORT,&GPIO_InitStructure);
}

//配置DHT11为输入模式
void DHT11_Input_Mode(void)
{
	GPIO_InitTypeDef GPIO_InitStructure;
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
	GPIO_InitStructure.GPIO_Pin   = DHT11_GPIO_PIN; 	
	GPIO_InitStructure.GPIO_Mode  = GPIO_Mode_IN_FLOATING;//浮空输入
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(DHT11_GPIO_PORT,&GPIO_InitStructure);
}
 
//输出电平0/1
void DHT11_DQ_OUT(uint8_t BitValue)
{
	GPIO_WriteBit(DHT11_GPIO_PORT,DHT11_GPIO_PIN,(BitAction)BitValue);
}
 
//读取输入电平0/1
uint8_t DHT11_DQ_IN(void)
{
	return GPIO_ReadInputDataBit(DHT11_GPIO_PORT,DHT11_GPIO_PIN);
}
 
 
//DHT11复位信号
void DHT11_Reset(void)
{
	DHT11_Output_Mode();
	DHT11_DQ_OUT(1);//拉高电平 保证待会是低电平
	Delay_ms(25);//随便值
	DHT11_DQ_OUT(0);//拉低DQ,复位信号的开始
	Delay_ms(20);//拉低至少18ms
	DHT11_DQ_OUT(1);// 将DHT11的DQ引脚拉高,结束复位信号
	Delay_us(25); //在拉高DQ之后,DHT11会开始其内部复位过程,拉高20-40us
}
 
//检测是否有DHT11存在,0存在,1不存在
uint8_t DHT11_Check(void)
{
	uint8_t retry = 0;//初始为0,用来重复计次
	DHT11_Input_Mode();//设置PA9为输入模式,接收DHT11信号
	// 等待DHT11拉低DQ引脚,这通常发生在复位信号之后的40-80微秒内
   
	while(DHT11_DQ_IN() && retry < 100)//DHT拉低40-80us
	{
		retry++;//每次循环计次加一
		Delay_us(1);
	}
	
	//如果在计次100次内没有被拉低,返回1则认为DHT11没有响应,否则重置计次变量为0,
	//为下一次等待阶段做准备
	if(retry >= 100) return 1; 
	else 
	{
		retry = 0;
	}
		
	// 等待DHT11拉高DQ引脚,在拉低之后的40-80微秒内
    // 如果DQ在100次重试内没有被拉高,同样认为DHT11没有正确响应
	while(!DHT11_DQ_IN() && retry < 100)//DHT会再拉高40-80us
	{
		retry++;
		Delay_us(1);
	}
	if(retry >= 100) return 1;
	return 0;
	
	
}
//检测DHT11是否响应
uint8_t DHT11_Init(void)
{
	DHT11_Output_Mode();
	DHT11_Reset();
	return DHT11_Check();
}
 
//读取一个位
uint8_t DHT11_Get_Bit(void)
{
	uint8_t retry = 0;
	while(DHT11_DQ_IN() && retry < 100)
	{
		retry++;
		Delay_us(1);
	}
	retry = 0;
	while(!DHT11_DQ_IN() && retry < 100)
	{
		retry++;
		Delay_us(1);
	}
	Delay_us(40);
	if(DHT11_DQ_IN()) return 1;
	else return 0;
}

//读取一个字节
uint8_t DHT11_GetByte(void)
{
	uint8_t i,Dat = 0;
	for(i = 0; i < 8; i++)
	{
		Dat <<= 1;
		Dat |= DHT11_Get_Bit();//Dat某一位或运算上1必定为1,或上0位不变
	}
	return Dat;
}

//指针temperature和humidity存储数据
uint8_t DHT11_GetData(uint8_t * temperature,uint8_t *humidity)
{
	uint8_t H_H,H_L,T_H,T_L;
	uint8_t HH,HL,TH,TL,CHECK;

	uint8_t i;
	
	DHT11_Reset();
	
	if(DHT11_Check() == 0)
	{
		H_H = DHT11_GetByte();
		H_L = DHT11_GetByte();
		T_H = DHT11_GetByte();
		T_L = DHT11_GetByte();
		CHECK = DHT11_GetByte();
		
		if((H_H+H_L+T_H+T_L)==CHECK)
		{
			*temperature = T_H;
			*humidity = H_H;		
		}
	}
	else
	{
		return 1;//读取失败
	}
	return 0;//存在DHT11
}
//DHT11.h

#ifndef  __DHT11_H__
#define	 __DHT11_H__
 
#define DHT11_GPIO_PORT  GPIOA
#define DHT11_GPIO_PIN   GPIO_Pin_6
 
uint8_t DHT11_Init(void);
void DHT11_Input_Mode(void);
void DHT11_Output_Mode(void);
void DHT11_DQ_OUT(uint8_t BitValue);
uint8_t DHT11_DQ_IN(void);
void DHT11_Reset(void);
uint8_t DHT11_Check(void);
uint8_t DHT11_Get_Bit(void);
uint8_t DHT11_GetByte(void);
uint8_t DHT11_GetData(uint8_t * temperature,uint8_t *humidity);

#endif
//main.c

#include "stm32f10x.h"
#include "Delay.h"
#include "OLED.h"
#include "DHT11.h"

uint8_t temperature,humidity;

int main()
{
	OLED_Init();
	while(DHT11_Init())//如果没有DHT11设备
	{
		OLED_ShowString(2,5,"NO DHT11");
		Delay_ms(500);
		OLED_ShowString(2,5,"        "); //刷新界面
	}
	while(1)//如果读取到数据
	{	
		if(!DHT11_GetData(&temperature,&humidity))
		{
			OLED_ShowString(2,5,"temp:");
			OLED_ShowString(3,5,"humi:  %");
			OLED_ShowNum(2,10,temperature,2);
			OLED_ShowNum(3,10,humidity,2);
		}
		Delay_ms(1000);
	}
}

五. 实验演示:

1.当没有连接DHT11模块时:

2.当正确连接DHT11模块时:

Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐