DHT11温湿度传感器

概述


  DHT11数字温湿度传感器是一款含有已校准数字信号输出的温湿度复合传感器。它应用专用的数字模块采集技术和温湿度传感技术,确保产品具有极高的可靠性与长期的稳定性。传感器包括一个电阻式感湿元件和一个NTC测温元件,并与一个8位单片机相连接。因此该产品具有抗干扰能力强、性价比高等优点。

硬件连接


  DHT11使用1-wire总线与MCU进行半双工通信,当连接线长度短于20米时可用5K的上拉电阻,大于20米时需要根据实际情况选择合适的上拉电阻。

通信过程

  DATA引脚用于MCU与DHT11之间的通讯和同步,采用单总线数据格式,一次通讯时间4ms左右,数据分小数部分和整数部分,一次完整的数据传输为40bit,高位先出(MSB)。数据格式:8bit湿度整数数据+8bit湿度小数数据+8bit温度整数数据+8bit温度小数数据+8bit校验和。数据传送正确时校验和数据等于“8bit湿度整数数据+8bit湿度小数数据+8bit温度整数数据+8bit温度小数数据”所得结果的末8位。

通信的开始


  上图为MCU与DH11通信的开始,MCU拉低总线20ms后拉高,请求DH11响应,DH11收到信号后将总线拉低以此来响应主机,响应后拉高总线开始传输数据,本图来源为DH11的数据手册。需要注意MCUI/O引脚输入输出模式的切换,本人使用的是GPIOG的号引脚与DHT11进行通信。

数据的判断


  上图中可以看出论时数据0还是数据1,数据的开始总线都是被拉低50us,只是在总线被拉高时的时长不一样,于是程序便可以在40us的时候判断引脚的电平,以此来指定当前传输的数据是0是1。

温湿度传感器程序

  以下为温湿度传感器初始化函数和获得温湿度数据的程序,初始化相关引脚后调用read_ht_data(&data),便可以获得所需数据,注意该函数1s钟只能调用一次,不然获取不到数据。还需要保证延迟函数是准确的,参考我之前的系统定时器的相关随笔。

void ht_sensor_init()
{
	GPIO_InitTypeDef GPIO_InitStruct;
	GPIO_InitStruct.GPIO_Pin   = GPIO_Pin_9;
	GPIO_InitStruct.GPIO_Mode  = GPIO_Mode_OUT;
	GPIO_InitStruct.GPIO_Speed = GPIO_High_Speed;
	GPIO_InitStruct.GPIO_OType = GPIO_OType_OD;
	GPIO_InitStruct.GPIO_PuPd  = GPIO_PuPd_NOPULL;

	GPIO_Init(GPIOG,&GPIO_InitStruct);

}

int read_ht_data(uint8_t *p)
{
	uint32_t t=0;//用于计时
	int32_t i=0,j=0;
	uint8_t d=0;
	uint8_t check_sum=0;
	GPIO_InitTypeDef GPIO_InitStruct;

	//保证PG9为输出模式,必须要
	GPIO_InitStruct.GPIO_Pin   = GPIO_Pin_9;
	GPIO_InitStruct.GPIO_Mode  = GPIO_Mode_OUT;
	GPIO_InitStruct.GPIO_Speed = GPIO_High_Speed;
	GPIO_InitStruct.GPIO_OType = GPIO_OType_OD;
	GPIO_InitStruct.GPIO_PuPd  = GPIO_PuPd_NOPULL;
	GPIO_Init(GPIOG,&GPIO_InitStruct);
	
	//PG9输出低电平
	PGout(9)=0;
	
	//延时至少18ms
	delay_ms(18);
	
	//PG9输出高电平
	PGout(9)=1;	
	
	//延时30us
	delay_us(30);
	
	//保证PG9为输入模式
	GPIO_InitStruct.GPIO_Pin   = GPIO_Pin_9;
	GPIO_InitStruct.GPIO_Mode  = GPIO_Mode_IN;
	GPIO_InitStruct.GPIO_Speed = GPIO_High_Speed;
	GPIO_InitStruct.GPIO_OType = GPIO_OType_PP;
	GPIO_InitStruct.GPIO_PuPd  = GPIO_PuPd_NOPULL;
	GPIO_Init(GPIOG,&GPIO_InitStruct);
	//等待低电平出现,添加超时处理
	t=0;//
	while(PGin(9))
	{
		t++;
		
		delay_us(1);
		if(t>=4000)
		{
			printf("Obtion data error1, please try again
");
			delay_ms(1000);
			return -1;
		}
	}
	//通过超时检测低电平的合法性,注意总线电平每跳变一次就需要将t清0
	t=0;/
	while(PGin(9)==0)
	{
		t++;
		delay_us(1);
		
		if(t>=100)
		{
			printf("Obtion data error2, please try again
");
			delay_ms(300);
			return -2;
		}
	}
	//通过超时检测高电平的合法性
	t=0;
	while(PGin(9))
	{
		t++;
		delay_us(1);
		if(t>=100)
		{
			printf("Obtion data error3, please try again
");
			delay_ms(300);
			return -3;
		}
	}
	for(j=0; j<5; j++)
	{
		//接收一个字节,高位优先接收数据,bit7 bit6 ...... bit0
		d=0;
		for(i=7; i>=0; i--)
		{
			//通过超时检测低电平的合法性
			t=0;
			while(PGin(9)==0)
			{
				t++;
				delay_us(1);
				
				if(t>=100)
				{
					printf("Obtion data error4, please try again
");
					delay_ms(300);
					return -4;
				}
			}
			//延时40us~60us左右
			delay_us(40);
			//判断引脚的电平
			if(PGin(9))
			{
				d|=1<<i;
				//等待剩下的高电平持续完毕
				t=0;
				while(PGin(9))
				{
					t++;
					delay_us(1);
					if(t>=100)
					{
						printf("Obtion data error5, please try again
");
						delay_ms(300);
						return -5;
					}
				}			
			}
		}	
		p[j]=d;
	}
	//校验数据
	check_sum = (p[0]+p[1]+p[2]+p[3])&0xFF;
	if(check_sum != p[4])
	{
		printf("Obtion data error6, please try again
");
		delay_ms(300);
		return -6;
	}

	//printf("H:%d.%d	T:%d.%d
",p[0], p[1], p[2], p[3]);
	return 0;
}

总结

  1.获得温湿度数据不可太快;
  2.除了获取温湿度数据出错外,在通信过程中不可使用printf函数不然将超时,导致获取失败。

模块资料

链接:https://pan.baidu.com/s/1RYk_LayvZ0__EaiTVYZxrA 
提取码:vs24 
复制这段内容后打开百度网盘手机App,操作更方便哦
原文地址:https://www.cnblogs.com/ding-ding-light/p/14470818.html