用户工具

站点工具


侧边栏

抱歉,您没有权限增加页面
4.单片机入门教程:13.dht11温湿度传感器

单片机入门之DHT11温湿度传感器

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

二:实验现象与代码解释
DHT11温湿度传感器采集,数码管轮流显示温度和湿度.

关于代码,就不贴完整的了,直接看DHT11通信部分,按函数块来解释,本代码完整工程文件在stc51 discovery【实验例程】【进阶实验】【实验三十八】。

1.先来看几个延时函数:

//延时25微秒在晶振为11.0592MHz,不同晶振需作修改
void Delay25us() 
{
	unsigned char i;

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

//延时1微秒在晶振为11.0592MHz,不同晶振需作修改
void Delay1us()	
{
	_nop_();
}

//延时25毫秒在晶振为11.0592MHz,不同晶振需作修改
void Delay25ms()
{
	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读到后会有个响应输出通知单片机,然后单片机就可以读取数据了,这些时序就是由一系列的高低电平时间组成。

1.首先来看,单片机向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把总线拉低,等待主机读取,这个低电平时间为80us,如果读取到的为低电平,响应成功。DHT11发送完响应信号后会把总线再拉高80us,准备输出数据。代码如下:

//MCU读取DHT11响应信号,返回0,主机和DHT11通信成功。
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的每一位数据都是以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输出的0和1信号每8位组成一个字节,代码如下:

//主机接收DHT11八位数据
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]就是温度,这两个数值赋给数码管显示就可以了。代码如下:

   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);//延时切换成湿度
	   }
	 }
   }

啊,大海啊,你为什么那么大。啊,黄河,你为什么那么黄。啊,流程就是这么个流程,按照时序图来写程序,看第一遍会感觉有些山路十八弯,多看几遍就顿悟了,骚年,我看你骨骼惊奇,是万中无一的练武奇才,秘籍已经传授给你了,为夫只能帮你到这了……

4.单片机入门教程/13.dht11温湿度传感器.txt · 最后更改: 2017/03/07 21:43 由 wawooo