DHT11温湿度传感器读写时序及C51单片机程序代码

一:实验原理

       DHT11是一个数字温湿度传感器,可以采集环境中的温度和湿度。单线制串行接口,除了电源以外只需要一根信号线就可以和单片机通信,传输距离可达20米,湿度测量范围:20-90%RH,温度测量范围:0-50℃,实乃居家旅行必备之物。原理图如下:

DHT11

二:读写时序

DHT11温湿度传感器采集,数码管轮流显示温度和湿度,关于代码,就不贴完整的了,直接看DHT11通信部分,按函数块来解释。先来看几个延时函数,使用的是STC12C5A60S2单片机11.0592M晶振。

void Delay25us()	//@11.0592MHz
{
	unsigned char i;

	i = 66;
	while (--i);
}

void Delay1us()		//@11.0592MHz
{
	_nop_();
}

void Delay25ms()	//@11.0592MHz
{
	unsigned char i, j, k;

	i = 2;
	j = 13;
	k = 237;
	do
	{
		do
		{
			while (--k);
		} while (--j);
	} while (--i);
}

这些延时在单片机与DHT11总线通讯时序中会用到,DHT11通信协议是以总线上的高低电平时间来区分的,比如:主机(单片机)发送起始信号,DHT11的响应信号,DHT11输出0和1的信号。总的时序图如下:

DHT11时序图

由上图可知,DHT11的通信时序是这样的:首先,单片机向DHT11发送开始信号,然后DHT11读到后会有个响应输出通知单片机,然后单片机就可以读取数据了,这些时序就是由一系列的高低电平时间组成。

 1.首先来看,单片机向DHT11发送开始信号的时序,时序图如下:

DHT11复位

上图可知,开始信号就是主机(单片机)把总线拉低等待DHT11响应,这个低电平时间要大于18ms,才能确保被DHT11检测到,这样开始信号就发送完了。然后主机再把总线拉高等待20-40us,接下来主机就可以读取DHT11的响应信号了。代码如下:

void MCU_Send_Start()	
{
  DHT=0;
  Delay25ms();//主机至少拉低18MS
//  _nop_();_nop_();_nop_();
  DHT=1;
  Delay25us();//主机拉高20-40us准备等待响应
}

2.再来看,DHT11的响应时序,时序图如下:

DHT11响应

上图可知:响应信号就是DHT11把总线拉低,等待主机读取,这个低电平时间为80us,如果读取到的为低电平,响应成功。DHT11发送完响应信号后会把总线再拉高80us,准备输出数据。代码如下:

uchar MCU_Read_DHT11_Respond()   
{
  uchar retry; 
  DHT=1;
  		//如果DHT11有响应会先拉低80US 用while读取判断电平
  		//如果DHT为高电平即无响应继续等待读取直到超时
  while(DHT&&retry<100) 
  {					
    retry++;	
    Delay1us();
  }					 
  if(retry>=100) return 1; //超时返回1	
  else retry=0;

 		//如果读取到低电平则DHT11有响应,等待80us过去
  while(!DHT&&retry<100)  
  {
    retry++;   
	Delay1us();
  }
  if(retry>=100) return 1; //超时返回1
  return 0; 
}

3.再来看,主机发送开始信号以后DHT11如期响应了,那么主机就可以准备接收数据了,由于是单总线,DHT11的数据只能按位输出,数据0和数据1也是按照高低电平长短来决定的。数据0和数据1的时序图如下:

DHT11低电平

DHT11高电平

上图可知:DHT11的每一位数据都是以50us低电平间隙开始,然后如果高电平是26-28us就表示0,如果高电平是70us表示1。这样主机只要读取等待50us低电平过去然后再判断高电平长短就能收集数据了,代码如下:

//读取一位 每一位数据都以50US低电平间隙开始
//高电平长短决定0和1 26-28US代表0 70US表示1 
uchar DHT11_Read_Bit()	
{						
   uchar retry=0;
  	//判断上一位的0和1的高电平有没有过去
	//确保过去了再读取下一位的低电平间隙
   while(DHT&&retry<100)  
   {					  
     retry++;
	 Delay1us();  
   }
	//等待50US低电平间隙过去 就可以检测高电平长短了
    retry=0;
	while(!DHT&&retry<100)
	{
	   retry++;
	   Delay1us();
	}
		//由于1是70US长度高电平 0是26-28US长度高电平
		//所以延时50US跳过电平0检测当前信号电平是否为1			
	Delay25us(); 
	Delay25us(); 
		//还是高电平说明是1,返回数字1,否则为数字0
	if(DHT) return 1; 
	else return 0;
}

4.再来看,单片机发送一次开始信号后,DHT11响应信号,然后就一连串送出40位数据,如果DHT11没有接收到单片机的开始信号,是不会主动采集温湿度数据的。这40位数据其中包含了,8位的湿度整数数据+8位湿度小数数据+8位的温度整数数据+8位的温度小数数据+8位的效验和。这时我们就要按照DHT11输出的01信号每8位组成一个字节,代码如下:

uchar DHT11_Read_Byte() //主机接收8位数据
{
  uchar i,temp=0;
  for(i=0;i<8;i++)
  {
     temp=temp<<1;
	 temp|=DHT11_Read_Bit();
  }
  return temp;
}

5.通信部分和数据接收部分已经说完了,下面就可以在主函数中处理接收到的数据显示了,首先,单片机发送一个开始信号,然后判断DHT11有没有响应,有响应就直接读取40位的数据,用一个数组DHT11_Buffer[5]缓存,然后拿出DHT11_Buffer[0]就是湿度,DHT11_Buffer[2]就是温度,这两个数值赋给数码管显示就可以了。代码如下:

void main(void)
{
   uchar t,i;
   P4SW=0x70; //P4口打开 默认是关闭的
   P4M1=0x00;
   P4M0=0x00; // 设置为普通IO
   P0M1=0x00;
   P0M0=0xff; //P0口全部设置为推挽输出 见手册87页 IO口模式配置
   while(1)
   {
	 MCU_Send_Start();	//DHT11响应 准备接收数据
	 if(MCU_Read_DHT11_Respond()==0)
	 {
	   for(i=0;i<5;i++)
	   {				//接收到的数据放入缓冲区中
	     DHT11_Buffer[i]=DHT11_Read_Byte();	
	   }
          if(DHT11_Buffer[0]+DHT11_Buffer[1]+DHT11_Buffer[2]
	   	  +DHT11_Buffer[3]==DHT11_Buffer[4])	//校验数据
	   {
		  for(t=0;t<200;t++) //显示一会
		  {
		     Display(DHT11_Buffer[2]);//显示温度 单位°
		  }
		  delay_ms(500); //延时切换成温度
		  for(t=0;t<200;t++) //显示一会
		  {
		     Display(DHT11_Buffer[0]);//显示湿度 单位%
		  }
	   	  delay_ms(500);//延时切换成湿度
	   }
	 }
   }

}

流程就是这么个流程,按照时序图来写程序,多看几遍就晓得了。

版权声明:
作者:wawooo
链接:http://www.wawooo.com/242.html
来源:挖窝网
文章版权归作者所有,未经允许请勿转载。

THE END
分享
二维码
< <上一篇
下一篇>>
文章目录
关闭
目 录