驱动国产温湿度探头 DHT11成功 发调试心得

2020-02-01 16:31发布

终于调通DHT11  希望走过的大虾大力拍砖哦!!

DHT的温度精度只有2℃ 湿度是±5%RH



这只东西的引脚以及外形图:
<center>



首先,DHT11是单总线传输数据
数据共40bit,也就是有5个字节:湿度整数+湿度小数+温度整数+温度小数+校验和
数据格式以16进制直接显示 比如 20℃时 温度整数是0x20
(原文件名:40bit数据格式.jpg)

沟通从复位开始,读取DHT11的时序是 复位+40bit数据
复位时序如下:

(原文件名:复位时序.jpg)
复位没什么好说的,把握好时间就是


40bit数据是连续输出的,无论是“数据0”还是“数据1”都是DHT拉低总线然后拉高总线
-_-# 那怎么知道输出1还是输出0 ?
看时序图:
输出数据1的时序:
DHT拉低总线12~14us然后拉高总线116~118us

(原文件名:数据1.jpg)


输出数据0的时序:
DHT拉低总线12~14us然后拉高总线26~28us

(原文件名:数据0.jpg)


不难看出,只要“检测”出高电平维持的时间长短就ok了~~!
一般的做法是等DHT拉高总线后delay40us,如果DHT要返回0,这时候总线已经不是高电平了,因为输出数据0只需拉高总线最多28us而已
无错!!但用这个办法,我却调了两个晚上之久!!可能因为这个位置的延时时间比较严格,不好调。
最后我用
n=0;
while(DHT总线)
{
n++;
}
当高电平信号撤销以后,while循环退出,判断N的大小来推断是属于数据0还是数据1,因为高电平时间越长N越大
当然了,这里不加跳转的话万一DHT接触不良会导致死循环
另外比较高速的单片机需要保证N不会在高电平撤销前溢出


手机拍照不清晰,这是实物图:

(原文件名:室温.jpg)


(原文件名:温度探头.jpg)


(原文件名:哈一口气后.jpg)


(原文件名:哈一口气后.jpg)


(原文件名:哈一口气后.jpg)


DHT 程序:

===================================    头 文 件    ===========================================


#ifndef _DHT11_h_
#define _DHT11_h


/**********************************************/
/*             引  脚  定  义                 */
/**********************************************/
sbit DHT_bus = P1^4        ;


/**********************************************/
/*             函  数  声  明                 */
/**********************************************/
bit start_DHT11(void);          //开始
void read_DHT11(void);          //读取
void delay_20us(void);          //20us延时
void delay_ms(unsigned char m);          //N ms延时
bit check_sum(void);              //和校验

/**********************************************/
/*               宏  定  义                   */
/**********************************************/
#define HIGH 1
#define LOW  0

/**********************************************/
/*             变  量  定  义                 */
/**********************************************/
#define DHT_timeover 5                 //高电平维持时间,用于识别“数据0”和“数据1”


/**********************************************/
/*               结  构  体                   */
/**********************************************/
struct DHT_data
{
unsigned char DH_H;     //湿度整数
unsigned char DH_L;     //湿度小数
unsigned char T_H;      //温度整数
unsigned char T_L;      //温度小数
unsigned char Checksum; //校验和
}DHT_data;



#endif




======================================= DHT驱动 =============================================

#include "DHT11.h"



/**********************************************/
/*           开始 DHT11 温湿度计              */
/* 输入:无                                                             */
/* 输出:应答标志  0:应答失败   1:应答成功  */
/**********************************************/
bit start_DHT11(void)
{
bit DHT_start;
DHT_start = 0;
DHT_bus = HIGH;
DHT_bus = LOW;    //拉低18ms以上
delay_ms(18);
DHT_bus = HIGH;
delay_20us();
delay_20us();     //拉高20~40us
while(!DHT_bus)
{
  DHT_start = 1;
};  //DHT应答,DHT拉低80us后拉高80us,然后开始传输数据
//数据(40bit)=8bit湿度整数+8bit湿度小数+8bit温度整数+8bit温度小数+8bit校验和
while(DHT_bus){};
return(DHT_start); //应答成功返回1
}


/**********************************************/
/*           读取 DHT11 温湿度计              */
/* 读取结果存在DHT_data结构体内               */
/* 输入:无           输出:无                */
/**********************************************/
void read_DHT11(void)
{
unsigned char m,n,timer_dht;
unsigned char *p;
p=&DHT_data.DH_H;
for(m=0;m<5;m++)
{
  for(n=0;n<8;n++)
  {
   while(~DHT_bus);    //DHT拉低12-14us表示1bit数据开始
   timer_dht=0x00;
   while(DHT_bus)          //随后DHT拉高总线,单片机通过高电平维持的时间判断“数据0”还是“数据1”
   {
                     //数据0维持26~28us高电平,数据1维持116~118us高电平
   timer_dht++;          //由于此处对延时时间的长度要求很高,所以采用另一种办法判断

   };
   if(timer_dht>DHT_timeover)
   {
   *p<<=1;
   *p|=0x01;
   }
   else
   {
   *p<<=1;
   *p&=0xfe;
   };
  };
  p++;
};
}

/**********************************************/
/*           20us 精 确 延 时                 */
/* 51用在12Mhz晶振下                          */
/* 调用函数使用LCALL和RET指令,共花费4个周期  */
/* 因此只有16个NOP                            */
/**********************************************/
void delay_20us(void)
{
_nop_ ();
_nop_ ();
_nop_ ();
_nop_ ();
_nop_ ();
_nop_ ();
_nop_ ();
_nop_ ();
_nop_ ();
_nop_ ();
_nop_ ();
_nop_ ();
_nop_ ();
_nop_ ();
_nop_ ();
_nop_ ();
}


/**********************************************/
/*                 N ms 延 时                 */
/* while()额外占用约5周期                     */
/* 因此内层while(40--)20us 大约1ms            */
/* Nms延时函数(未测试)                        */
/**********************************************/
void delay_ms(unsigned char m)
{
unsigned char n = 38;
while(m--)
{
while(n--)
{
  delay_20us();
};
};
}



/**********************************************/
/*           校  验  和  判 断                */
/* 校验位 = 湿度整数位+湿度小数位+温度整数位+温度小数位 之和 */
/* 校验正确返回:1          失败返回:0        */
/**********************************************/
bit check_sum(void)
{
if(DHT_data.Checksum==(DHT_data.DH_H+DHT_data.DH_L+DHT_data.T_H+DHT_data.T_L))
return(1); //校验正确
else
return(0); //校验失败
}

(居中了..怎么左对齐这段文字?)

===================================================================================================================================
规格书ourdev_603049Q9F28W.pdf(文件大小:585K) (原文件名:DHT11规格书.pdf)
完整程序ourdev_603050D0DKZG.rar(文件大小:575K) (原文件名:DHT11.rar)
友情提示: 此问题已得到解决,问题已经关闭,关闭后问题禁止继续编辑,回答。
该问题目前已经被作者或者管理员关闭, 无法添加新回复
82条回答
brahen
1楼-- · 2020-02-09 02:34
 精彩回答 2  元偷偷看……
Pioneermcu
2楼-- · 2020-02-09 06:07
刚刚有需要!
newhand1991
3楼-- · 2020-02-09 07:41
呵呵,程序写复杂了。我上一段:
#include<reg52.h>
#include<intrins.h>
#include "lcm1602.h"

#define uchar unsigned char
#define uint  unsigned int

sbit IO=P2^0;
sbit beep=P2^1;

void delay30ms()
{
         uchar i,j;
         for(i=60;i>0;i--)
         for(j=500;j>0;j--);
}

void main()
{  
        uchar i,j,test,number=0,a,b,c,d,temp;
        uchar code num[]="0123456789";

        init_1602();
while(1)
{       
        IO=1;  
    _nop_();_nop_();_nop_();_nop_();_nop_();
    IO=0;  // 开始信号
    delay30ms();
    IO=1;          //开始信号结束
           for(i=20;i>0;i--);
        if(IO==0)
                beep=0;                   
        while(!IO);
          while(IO);        //等待开始传送信号       

        for(j=0;j<40;j++)
        {
                while(!IO);
                for(i=14;i>0;i--);
                if(IO==1)
                        temp|=0x01;
                while(IO);               
                number++;
                if(number==8)
                        {
                                a=temp;
                                temp=0;
                        }
                else if(number==16)
                        {
                                b=temp;
                                temp=0;
                        }
                else if(number==24)
                        {
                                c=temp;
                                temp=0;
                        }
                else if(number==32)
                        {
                                d=temp;
                                temp=0;
                        }
                else if(number==40)
                        {
                                test=temp;
                                temp=0;
                                number=0;
                        }               
                temp<<=1;                                                                       
        }       

         if(a+b+c+d==test)
         {          
          write_com(0x80+0x00);
          write_data(num[a/10]);
          write_data(num[a%10]);
          write_data(num);
          write_com(0x80+0x40);
          write_data(num[c/10]);
          write_data(num[c%10]);
          write_data(num[d]);
          beep=1;
         }
         
         IO=1;
         delay_50us(1000);
}  
}



其中的beep我是做测试指示的,就是说如果有采集,蜂鸣器就响一下。lcm1602.h是液晶1602的驱动程序a  b c  d 分别是第一、第二···个8位数据。看了资料的应该会很清楚。
myhonour
4楼-- · 2020-02-09 13:17
mark
charles310
5楼-- · 2020-02-09 15:22
mark
bingshuihuo888
6楼-- · 2020-02-09 17:25
 精彩回答 2  元偷偷看……

一周热门 更多>