【物联网项目】DHT11温湿度传感器——学习记录

由于近期有个物联网项目,之前又没调试过DHT11温湿度传感器,因此记录下学习的过程以便以后遗忘后查看。

DHT11是一款特别常见的温湿度传感器,其价格十分便宜,可靠性和稳定性强,体积小,功耗低,信号传输距离可达20米以上。

测量范围:20~90%RH      ±5%RH

                  0~50℃             ±2℃

如果你的测量环境大于或者小于该范围的话就需要另外用别的传感器了。

接口说明:

为了确保数据稳定,在连接线长度短于20米的时候用5K的上拉电阻(如果买的模块人家已经给你加好电阻了,直接接线就行!)

传感器外观:

我们可以从上图发现除了简单的接电源和地外,关键在于DATA接口!接下来分析DATA的代码编写!

DATA用于MCU与DHT11之间的通讯,采用单总线数据格式,数据分为整数部分小数部分,一次完整的通讯时间大约4ms左右。

一个完整的数据格式为:(40bit)

8bit湿度整数数据 + 8bit湿度小数数据 + 8bit温度整数数据 + 8bit温度小数数据 + 8bit数据检验和

数据传输成功:

数据检验和 = 8bit湿度整数数据 + 8bit湿度小数数据 + 8bit温度整数数据 + 8bit温度小数数据

通讯过程如图所示:

主机拉低发送开始信号后,将总线拉高延时等待DHT11,DHT11发送响应信号,并将总线拉高准备输出,然后输出40bit的数据,这就是一次数据传输。

开始分析:

我们从上图可以发现,总线空闲状态为高电平,这是我们一开始将IO上拉导致的。当总线高电平拉低至少18ms后,发出开始信号,这时让DHT11知道已经开始了!这时再将总线拉高20~40us左右(我选择30us),读取DHT11的响应信号,这时判断DHT11低电平状态即说明DHT11发出响应信号了。然后再等待80us低电平结束,再等待80us高电平结束,这时就可以开始采集数据了!

代码如下:

注意:我们通过上面分析知道总线需要具有输入和输出的功能,因此在代码上应该设置总线又推挽输出和上拉输入两种状态

①将总线设置为推挽输出状态,由于一开始是上拉至高电平,因此将总线拉低并延时18ms表示发出开始信号!

②将总线拉高并延时30us表示开始信号结束等待DHT11发出响应信号

③将总线设置为上拉输入状态,判断从机的响应信号,当为低电平时则表示开始发出响应信号。则通过while循环等待80us的响应信号结束,然后再通过while循环等待80us的DHT11高电平信号结束。

④高电平结束后开始传送数据,这时候就可以开始采集数据了。数据分为湿度整数,湿度小数,温度整数,温度小数,校验和。

⑤读取结束后将总线重新设置为推挽输出状态,并将总线拉高,表示空闲状态等待下一次数据采集。

⑥每次结束后可以判断一下数据的正确性,通过

数据检验和 = 8bit湿度整数数据 + 8bit湿度小数数据 + 8bit温度整数数据 + 8bit温度小数数据

即可判断!

typedef struct
{
	uint8_t  humi_int;		//湿度的整数部分
	uint8_t  humi_deci;	 	//湿度的小数部分
	uint8_t  temp_int;	 	//温度的整数部分
	uint8_t  temp_deci;	 	//温度的小数部分
	uint8_t  check_sum;	 	//校验和
		                 
}DHT11_Data_TypeDef;
u8 Read_DHT11(DHT11_Data_TypeDef *DHT11_Data)
{
	//输出模式
	DHT11_DIR_OUT();
	
	//总线拉低
	DHT11_DATA_OUT(0);
	
	//延时18ms
	delay_ms(18);
	
	//总线拉高,主机延时30us
	DHT11_DATA_OUT(1);
	delay_us(30);//延时30us
	
	//主机设为输入,判断从机响应信号
	DHT11_DIR_IN();
	
	//判断从机是否有低电平响应信号,如果不响应则跳出,响应则向下运行
	if(DHT11_DATA_IN() == 0){
		//循环遍历直到从机发出80us的低电平,标志信号结束
		while(DHT11_DATA_IN() == 0);
		
		//循环遍历直到从机发出80us的高电平,标志信号结束
		while(DHT11_DATA_IN() == 1);
		
		//开始接收数据
		DHT11_Data->humi_int = DHT11_Read_Byte();
		DHT11_Data->humi_deci = DHT11_Read_Byte();
		
		DHT11_Data->temp_int = DHT11_Read_Byte();
		DHT11_Data->temp_deci = DHT11_Read_Byte();
		
		DHT11_Data->check_sum = DHT11_Read_Byte();
		
		//读取结束,引脚改为输出模式
		DHT11_DIR_OUT();
		
		//主机拉高
		DHT11_DATA_OUT(1);
		
		//检查读取的数据是否正确
		if(DHT11_Data->check_sum == DHT11_Data->humi_int + DHT11_Data->humi_deci + DHT11_Data->temp_int+ DHT11_Data->temp_deci)
			return 1;
		else 
			return 0;
			
	}
	
	else return 0;
	
}

数据采集部分:

以26-28us的高电平表示0,以70us高电平表示1

 代码如下:

思路如下:

通过一个for循环采集8位数据,先while循环等待50us低电平结束,通过延时大于表示0的时间,比如延时40us大于表示0的时间,然后通过while循环等待高电平结束,然后把高位数据置1,否则的话置0

u8 DHT11_Read_Byte()
{
	u8 i,temp = 0;
	for(i=0;i<8;i++){
		while(DHT11_DATA_IN() == 0);//等待50us低电平结束
		
		//DHT11 以26-28us的高电平表示0,以70us高电平表示1
		//通过检测x us 后的电平即可区别这两个状态
		
		delay_us(40);//延时x us,这个延时需要大于数据0持续的时间即可
		
		if(DHT11_DATA_IN() == 1){
			while(DHT11_DATA_IN() == 1);//等待数据1的高电平结束
			temp|=(u8)(0x01<<(7-i));//把第7-i位置1,MSB先行
		}
		else{
			temp&=(u8)~(0x01<<(7-i));//把第7-i位置0,MSB先行
		}
		
	}
	return temp;
}

 具体封装好的代码我已上传github!如果觉得好记得给我个小star哦!

GitHub - 1136958879/DHT11: This repository is DHT11 code!

版权声明:本文为CSDN博主「Q小鑫」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/qq_42108414/article/details/122613867

由于近期有个物联网项目,之前又没调试过DHT11温湿度传感器,因此记录下学习的过程以便以后遗忘后查看。

DHT11是一款特别常见的温湿度传感器,其价格十分便宜,可靠性和稳定性强,体积小,功耗低,信号传输距离可达20米以上。

测量范围:20~90%RH      ±5%RH

                  0~50℃             ±2℃

如果你的测量环境大于或者小于该范围的话就需要另外用别的传感器了。

接口说明:

为了确保数据稳定,在连接线长度短于20米的时候用5K的上拉电阻(如果买的模块人家已经给你加好电阻了,直接接线就行!)

传感器外观:

我们可以从上图发现除了简单的接电源和地外,关键在于DATA接口!接下来分析DATA的代码编写!

DATA用于MCU与DHT11之间的通讯,采用单总线数据格式,数据分为整数部分小数部分,一次完整的通讯时间大约4ms左右。

一个完整的数据格式为:(40bit)

8bit湿度整数数据 + 8bit湿度小数数据 + 8bit温度整数数据 + 8bit温度小数数据 + 8bit数据检验和

数据传输成功:

数据检验和 = 8bit湿度整数数据 + 8bit湿度小数数据 + 8bit温度整数数据 + 8bit温度小数数据

通讯过程如图所示:

主机拉低发送开始信号后,将总线拉高延时等待DHT11,DHT11发送响应信号,并将总线拉高准备输出,然后输出40bit的数据,这就是一次数据传输。

开始分析:

我们从上图可以发现,总线空闲状态为高电平,这是我们一开始将IO上拉导致的。当总线高电平拉低至少18ms后,发出开始信号,这时让DHT11知道已经开始了!这时再将总线拉高20~40us左右(我选择30us),读取DHT11的响应信号,这时判断DHT11低电平状态即说明DHT11发出响应信号了。然后再等待80us低电平结束,再等待80us高电平结束,这时就可以开始采集数据了!

代码如下:

注意:我们通过上面分析知道总线需要具有输入和输出的功能,因此在代码上应该设置总线又推挽输出和上拉输入两种状态

①将总线设置为推挽输出状态,由于一开始是上拉至高电平,因此将总线拉低并延时18ms表示发出开始信号!

②将总线拉高并延时30us表示开始信号结束等待DHT11发出响应信号

③将总线设置为上拉输入状态,判断从机的响应信号,当为低电平时则表示开始发出响应信号。则通过while循环等待80us的响应信号结束,然后再通过while循环等待80us的DHT11高电平信号结束。

④高电平结束后开始传送数据,这时候就可以开始采集数据了。数据分为湿度整数,湿度小数,温度整数,温度小数,校验和。

⑤读取结束后将总线重新设置为推挽输出状态,并将总线拉高,表示空闲状态等待下一次数据采集。

⑥每次结束后可以判断一下数据的正确性,通过

数据检验和 = 8bit湿度整数数据 + 8bit湿度小数数据 + 8bit温度整数数据 + 8bit温度小数数据

即可判断!

typedef struct
{
	uint8_t  humi_int;		//湿度的整数部分
	uint8_t  humi_deci;	 	//湿度的小数部分
	uint8_t  temp_int;	 	//温度的整数部分
	uint8_t  temp_deci;	 	//温度的小数部分
	uint8_t  check_sum;	 	//校验和
		                 
}DHT11_Data_TypeDef;
u8 Read_DHT11(DHT11_Data_TypeDef *DHT11_Data)
{
	//输出模式
	DHT11_DIR_OUT();
	
	//总线拉低
	DHT11_DATA_OUT(0);
	
	//延时18ms
	delay_ms(18);
	
	//总线拉高,主机延时30us
	DHT11_DATA_OUT(1);
	delay_us(30);//延时30us
	
	//主机设为输入,判断从机响应信号
	DHT11_DIR_IN();
	
	//判断从机是否有低电平响应信号,如果不响应则跳出,响应则向下运行
	if(DHT11_DATA_IN() == 0){
		//循环遍历直到从机发出80us的低电平,标志信号结束
		while(DHT11_DATA_IN() == 0);
		
		//循环遍历直到从机发出80us的高电平,标志信号结束
		while(DHT11_DATA_IN() == 1);
		
		//开始接收数据
		DHT11_Data->humi_int = DHT11_Read_Byte();
		DHT11_Data->humi_deci = DHT11_Read_Byte();
		
		DHT11_Data->temp_int = DHT11_Read_Byte();
		DHT11_Data->temp_deci = DHT11_Read_Byte();
		
		DHT11_Data->check_sum = DHT11_Read_Byte();
		
		//读取结束,引脚改为输出模式
		DHT11_DIR_OUT();
		
		//主机拉高
		DHT11_DATA_OUT(1);
		
		//检查读取的数据是否正确
		if(DHT11_Data->check_sum == DHT11_Data->humi_int + DHT11_Data->humi_deci + DHT11_Data->temp_int+ DHT11_Data->temp_deci)
			return 1;
		else 
			return 0;
			
	}
	
	else return 0;
	
}

数据采集部分:

以26-28us的高电平表示0,以70us高电平表示1

 代码如下:

思路如下:

通过一个for循环采集8位数据,先while循环等待50us低电平结束,通过延时大于表示0的时间,比如延时40us大于表示0的时间,然后通过while循环等待高电平结束,然后把高位数据置1,否则的话置0

u8 DHT11_Read_Byte()
{
	u8 i,temp = 0;
	for(i=0;i<8;i++){
		while(DHT11_DATA_IN() == 0);//等待50us低电平结束
		
		//DHT11 以26-28us的高电平表示0,以70us高电平表示1
		//通过检测x us 后的电平即可区别这两个状态
		
		delay_us(40);//延时x us,这个延时需要大于数据0持续的时间即可
		
		if(DHT11_DATA_IN() == 1){
			while(DHT11_DATA_IN() == 1);//等待数据1的高电平结束
			temp|=(u8)(0x01<<(7-i));//把第7-i位置1,MSB先行
		}
		else{
			temp&=(u8)~(0x01<<(7-i));//把第7-i位置0,MSB先行
		}
		
	}
	return temp;
}

 具体封装好的代码我已上传github!如果觉得好记得给我个小star哦!

GitHub - 1136958879/DHT11: This repository is DHT11 code!

版权声明:本文为CSDN博主「Q小鑫」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/qq_42108414/article/details/122613867

生成海报
点赞 0

Q小鑫

我还没有学会写个人说明!

暂无评论

发表评论

相关推荐

【物联网项目】OLED改造

如何把7ping的SPI通信的OLED改造为IIC通信? 之前买OLED的时候发现有两款OLED。 一款是直接IIC通信的OLED只有4Pin管脚。 分别是GND VCC SCL SDA 另一款是支持SPI通信和IIC通信的