DHT22使用笔记

温湿度模块DHT22详解一:基础篇

 DHT22也称AM2302,是一款含有已校准数字信号输出的温湿度复合传感器,见图1,湿度量程范围0~99.9%RH,精度±2%RH,而温度量程范围是-40℃~80℃,精度±0.5℃。

                                                                  图1

       DHT22是单总线通信的,驱动它只需三根线:电源线、信号线和地线,因此其电路也很简单,见图2:

                                                                        图2

       下面开始根据模块手册一步一步来讲解如何驱动DHT22,我尽可能详细到让初学者看完本文后就能成功驱动DHT22,大神路过勿喷。

       第一步:获取模块的使用手册,我使用的是奥松电子的DHT22,大家可以到官网下载:http://www.aosong.com/products-22.html
       第二步:解读模块使用手册,挑重要的点来讲
       1)在使用DHT22时要注意图3中的点3和点4,读取间隔最好大于2秒。

                                                                               图3

       2)接着是重要的通信协议格式,见图4

                                                                                           图4

       从图4可以看出,向DHT22读取温湿度数据时,DHT22是返回一个40位的数据:bit39-bit31表示湿度高位,bit30-bit23表示湿度低位,bit23-bit16表示温度高位,bit15-bit8表示温度低位,bit7-bit0表示校验位,那么如何将这40bit数据转换为温度和湿度呢?在手册中已经举例说明了,见图5和图6:

                                                                           图5

                                                                           图6

       这里要注意三点:一是无论是湿度还是温度,DHT22传出来的温湿度值是实际温湿度的10倍,所以40bit数据换算后的结果还要除以10才是实际的温湿度值;二是温度和湿度不一样,温度的最高位正负温度,最高位为1时表示负温度,为0时表示正温度,所以真正的温度值只有15位;三是换算时,先将湿度高8位和湿度低8位转换为十六进制后再转换为十进制。

       3)接下来是最重要的时序问题,时序不准确会导致无法读取到正确的数据,见图7:

                                                                       图7

       从图7知道,这里有两个时序问题,分别是起始信号(主机信号)和应答信号(传感器信号),那么起始信号和应答信号是怎样的呢?详见图8:

                                                               图8

       从图8可看出,起始信号(主机信号)是将总线引脚电平拉低1MS,1MS后需释放总线,而应答信号(传感器信号)则是在总线释放后输出80us的低电平和80us的高电平。

       接着还有一个重要问题,总线输出40bit的数据,我们知道输出的数字信号不是'0'就是'1',那么如何区分这40bit里面哪些是'1'哪些是'0'呢?是的,区分0和1也是靠时序,手册中也给出该时序,见图9:

 

                                                                   图9

       当我们检测到IO口输出50us低电平加26us高电平时,就可认为此时DHT22输出的位数据是'0',当检测到IO输出50us低电平加70us高电平时,就可认为此时DHT22输出的位数据是'1'。

       到此可以发现,要成功驱动DHT22,总线时序很重要,官方手册中也给出了每种信号的时序表,见下图10,我们一般使用典型值即可,即图10中红框部分,我们也可以使用最大值来判断是否存在通信超时情况。

                                                                 图10

       第3步:总结驱动DHT22的三个步骤。
        1)DHT22上电后至少要延时2秒,越过不稳定状态后才能开始读取数据。

        2)主机输出起始信号:

        主机与DHT22连接的IO口设置为输出模式并输出1ms的高电平。

       3)主机输出起始信号后需要释放总线:

        如何释放总线?只需主机IO口输出30us高电平即可,但这里推荐直接将IO口设置为输入模式,由于存在上拉电阻,IO口会一直处于高电平,并不需要特定输出高电平,而且后面接收DHT22的应答信号时IO口也要设置为输入。

       4)主机接收DHT22返回的应答信号:

       因为主机释放总线时主机IO口就已设置为输入模式,根据IO口的电平变化判断当前信号是否为应答信号,若IO口检测到先是80us低电平后80us高电平,说明该信号为应答信号,若超过时间超过上图10中的响应最大时间85us,则可以判断为应答超时。

       5)主机接收DHT22返回的40bit数据:

       DHT22发送完应答信号后,随即串行输出40位数据,高位在前,主机根据IO口电平变化来判断当前的数据位是'0'还是'1',若IO口检测到先是50us低电平后是26us高电平,则说明当前数据位是'0',若IO口检测到先是50us低电平后是70us高电平,则说明当前数据位是'1'。因为是40位数据,所以要循环检测IO口电平状态40次。

       6)DHT22输出40位数据后,继续输出50us低电平后自动进入休眠状态,此时DHT22会变为输入模式随时接收主机发来的起始信号,只有接收到主机发来的起始信号才能唤醒,进入工作状态。

       7)校验接收到的40位数据:

       如果(bit39:31)+(bit30:23)+(bit23:16)+(bit15:8)=(bit7:0)则表示接收到的数据正确。

      8)读取DHT22数据的时间间隔至少要2秒。

       DHT22传感器的基础就写到这里,下一篇主要写下DHT22驱动的编程思想以及驱动代码分析。
————————————————
版权声明:本文为CSDN博主「壹二叁」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/k1ang/article/details/98789397


线上DHT22与DHT11的性能对比:
DHT11:


DHT22:


对比可以发现,DHT22在分辨率和精度上都有很大的提升。

同时采样率也变成了每秒2次。


而且最重要的在于,通讯开始信号仅需要500us,与18us相差了接近20倍!
虽然获取的是上1次的的值,但是如果1秒采样两次,和11的同步性能是一样的。


由于精度提高,所以数据格式还是有变化的,相比于DHT11只用了整数部分,22的数据是全部用了的,直接是16bit数据,换算成16进制再乘以0.1就是实际的温度值和湿度值。


这里为了得到和DHT11相同的结果,我舍去小数值,同时复位时间也改成500us,代码如下:

void DHT11_Rst(void)       
{                 
    DHT11_IO_OUT();     //SET OUTPUT
      DHT11_DQ_OUT=0;     //拉低DQ
      delay_us(500);    //拉低至少18ms
      DHT11_DQ_OUT=1;     //DQ=1 
    delay_us(30);     //主机拉高20~40us
}

u8 DHT11_Read_Data(u8 *temp,u8 *humi)    
{        
     u8 buf[5];
    u8 i;
    DHT11_Rst();
    if(DHT11_Check()==0)
    {
        for(i=0;i<5;i++)//读取40位数据
        {
            buf[i]=DHT11_Read_Byte();
        }
        if((buf[0]+buf[1]+buf[2]+buf[3])==buf[4])
        {
            *humi=(buf[0]*256+buf[1])/10;
            *temp=(buf[2]*256+buf[3])/10;
        }
    }else return 1;
    return 0;        
}

显示结果如下:

using time:    4639 us    temperature:25    humidity:58
using time:    4686 us    temperature:25    humidity:58
using time:    4638 us    temperature:25    humidity:58
using time:    4638 us    temperature:25    humidity:58
using time:    4638 us    temperature:25    humidity:58
using time:    4639 us    temperature:25    humidity:58
using time:    4662 us    temperature:25    humidity:58
using time:    4637 us    temperature:25    humidity:58
using time:    4686 us    temperature:25    humidity:58
using time:    4732 us    temperature:25    humidity:58
using time:    4733 us    temperature:25    humidity:58
using time:    4734 us    temperature:25    humidity:58
using time:    4733 us    temperature:25    humidity:58
using time:    4733 us    temperature:25    humidity:58
using time:    4765 us    temperature:25    humidity:58
using time:    4637 us    temperature:25    humidity:58
using time:    4638 us    temperature:25    humidity:58
using time:    4638 us    temperature:25    humidity:58
using time:    4638 us    temperature:25    humidity:58
using time:    4639 us    temperature:25    humidity:58
using time:    4734 us    temperature:25    humidity:58
using time:    4733 us    temperature:25    humidity:58
using time:    4670 us    temperature:25    humidity:58
using time:    4686 us    temperature:25    humidity:58
using time:    4638 us    temperature:25    humidity:58
————————————————
版权声明:本文为CSDN博主「小盼你最萌哒」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/qq_27508477/article/details/83662194


DHT22模块的单片机例程 

http://www.51hei.com/bbs/dpj-139722-1.html

DHT11数字传感器概述:是一款含有已校准数字信号输出的温湿度复合传感器 。它应用专用的数字模块采集技术和温湿度传感技术 ,确保产品具有极 高的可靠性与卓越的长期稳定性。
 
技术参数
  供电电压: 3.3~5.5V DC
  输 出: 单总线数字信号
  测量范围: 湿度20-90%RH, 温度0~50℃
  测量精度: 湿度+-5%RH, 温度+-2℃
  分 辨 率: 湿度1%RH, 温度1℃
  互 换 性: 可完全互换 ,
  长期稳定性: <±1%RH/年

所有资料51hei提供下载:
 DHT.zip (19.89 KB, 下载次数: 18)

51 单片机源程序如下:

//****************************************************************//
//DHT21使用范例
//单片机 AT89S52 或 STC89C52RC
//功能   串口发送温湿度数据 晶振 11.0592M 波特率 9600
//硬件   P2.0口为通讯口连接DHT22,DHT22的电源和地连接单片机的电源和地,单片机串口加MAX232连接电脑
//****************************************************************//

#include <reg51.h>
#include <intrins.h>
//
typedef unsigned char  U8;       /* defined for unsigned 8-bits integer variable           无符号8位整型变量  */
typedef signed   char  S8;       /* defined for signed 8-bits integer variable                  有符号8位整型变量  */
typedef unsigned int   U16;      /* defined for unsigned 16-bits integer variable           无符号16位整型变量 */
typedef signed   int   S16;      /* defined for signed 16-bits integer variable           有符号16位整型变量 */
typedef unsigned long  U32;      /* defined for unsigned 32-bits integer variable           无符号32位整型变量 */
typedef signed   long  S32;      /* defined for signed 32-bits integer variable           有符号32位整型变量 */
typedef float          F32;      /* single precision floating point variable (32bits) 单精度浮点数(32位长度) */
typedef double         F64;      /* double precision floating point variable (64bits) 双精度浮点数(64位长度) */
//
#define uchar unsigned char
#define uint unsigned int
#define   Data_0_time    4

//----------------------------------------------//
//----------------IO口定义区--------------------//
//----------------------------------------------//
sbit  P2_0  = P2^0 ;

//----------------------------------------------//
//----------------定义区--------------------//
//----------------------------------------------//
U8  U8FLAG,k;
U8  U8count,U8temp;
U8  U8T_data_H,U8T_data_L,U8RH_data_H,U8RH_data_L,U8checkdata;
U8  U8T_data_H_temp,U8T_data_L_temp,U8RH_data_H_temp,U8RH_data_L_temp,U8checkdata_temp;
U8  U8comdata;
U8  outdata[5];  //定义发送的字节数           
U8  indata[5];
U8  count, count_r=0;
U8 str[5]={"RS232"};
U16 U16temp1,U16temp2;
SendData(U8 *a)
{
        outdata[0] = a[0];
        outdata[1] = a[1];
        outdata[2] = a[2];
        outdata[3] = a[3];
        outdata[4] = a[4];
        count = 1;
        SBUF=outdata[0];
}

       void Delay(U16 j)
    {      U8 i;
            for(;j>0;j--)
          {         
                for(i=0;i<27;i++);

          }
    }
      void  Delay_10us(void)
      {
        U8 i;
        i--;
        i--;
        i--;
        i--;
        i--;
        i--;

       }
        
        void  COM(void)
      {
     
                U8 i;
         
       for(i=0;i<8;i++)           
            {
               
                       U8FLAG=2;        
                   while((!P2_0)&&U8FLAG++);
                        Delay_10us();
            Delay_10us();                                
            Delay_10us();
                          U8temp=0;
             if(P2_0)U8temp=1;
                    U8FLAG=2;
                 while((P2_0)&&U8FLAG++);
                   //超时则跳出for循环                  
                    if(U8FLAG==1)break;
                   //判断数据位是0还是1         
                     
                // 如果高电平高过预定0高电平值则数据位为 1
                    
                   U8comdata<<=1;
                      U8comdata|=U8temp;        //0
             }//rof
           
        }

        //--------------------------------
        //-----湿度读取子程序 ------------
        //--------------------------------
        //----以下变量均为全局变量--------
        //----温度高8位== U8T_data_H------
        //----温度低8位== U8T_data_L------
        //----湿度高8位== U8RH_data_H-----
        //----湿度低8位== U8RH_data_L-----
        //----校验 8位 == U8checkdata-----
        //----调用相关子程序如下----------
        //---- Delay();, Delay_10us();,COM();
        //--------------------------------

        void RH(void)
        {
          //主机拉低18ms
       P2_0=0;
           Delay(180);
           P2_0=1;
         //总线由上拉电阻拉高 主机延时20us
           Delay_10us();
           Delay_10us();
       Delay_10us();
           Delay_10us();            
         //主机设为输入 判断从机响应信号
           P2_0=1;
         //判断从机是否有低电平响应信号 如不响应则跳出,响应则向下运行         
           if(!P2_0)                 //T !         
           {
           U8FLAG=2;
         //判断从机是否发出 80us 的低电平响应信号是否结束         
           while((!P2_0)&&U8FLAG++);
           U8FLAG=2;
         //判断从机是否发出 80us 的高电平,如发出则进入数据接收状态
           while((P2_0)&&U8FLAG++);
         //数据接收状态                 
           COM();
           U8RH_data_H_temp=U8comdata;
           COM();
           U8RH_data_L_temp=U8comdata;
           COM();
           U8T_data_H_temp=U8comdata;
           COM();
           U8T_data_L_temp=U8comdata;
           COM();
           U8checkdata_temp=U8comdata;
           P2_0=1;
         //数据校验
         
           U8temp=(U8T_data_H_temp+U8T_data_L_temp+U8RH_data_H_temp+U8RH_data_L_temp);
           if(U8temp==U8checkdata_temp)
           {
                     U8RH_data_H=U8RH_data_H_temp;
                     U8RH_data_L=U8RH_data_L_temp;
                  U8T_data_H=U8T_data_H_temp;
                     U8T_data_L=U8T_data_L_temp;
                     U8checkdata=U8checkdata_temp;
           }//fi
           }//fi

        }
        
//----------------------------------------------
//main()功能描述:  AT89C51  11.0592MHz         串口发
//送温湿度数据,波特率 9600
//----------------------------------------------
void main()
{        
        //uchar str[6]={"RS232"};
        /* 系统初始化 */
        TMOD = 0x20;          //定时器T1使用工作方式2
        TH1 = 253;        // 设置初值
        TL1 = 253;
        TR1 = 1;          // 开始计时
        SCON = 0x50;          //工作方式1,波特率9600bps,允许接收   
        ES = 1;
        EA = 1;           // 打开所以中断   
        TI = 0;
        RI = 0;
        SendData(str) ;   //发送到串口
        Delay(10);         //延时100US(12M晶振)
        while(1)
        {  

           //------------------------
           //调用温湿度读取子程序
           RH();
           //串口显示程序
           //--------------------------

           str[0]=U8RH_data_H;
           str[1]=U8RH_data_L;
           str[2]=U8T_data_H;
           str[3]=U8T_data_L;
           str[4]=U8checkdata;
      
       SendData(str) ;  //发送到串口  
           //读取模块数据周期不宜小于 2S
           Delay(20000);
        }//elihw
        
}// main

void RSINTR() interrupt 4 using 2
{
        U8 InPut3;
        if(TI==1) //发送中断         
        {
                TI=0;
                if(count!=5) //发送完5位数据         
                {
                        SBUF= outdata[count];
                        count++;
                }
        }

        if(RI==1)         //接收中断                  
        {        
                InPut3=SBUF;
                indata[count_r]=InPut3;
                count_r++;
                RI=0;                                                                 
                if (count_r==5)//接收完4位数据
                {
                //数据接收完毕处理。
                        count_r=0;
                str[0]=indata[0];
                 str[1]=indata[1];
                   str[2]=indata[2];
                         str[3]=indata[3];
                                 str[4]=indata[4];
                                 P0=0;
                }
        }
}

 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值