DHT11是一款数字温湿度传感器

  • 含有已校准数字信号输出的温湿度复合传感器;
  • 传感器包括一个电阻式感湿元件和一个NTC测温元件,并与一个高性能8位单片机相连接;
  • 单线制串行接口,信号传输距离可达20米以上。

测量范围及精度 :
20-90%RH ±5%RH
0-50℃ ±2℃

DHT11硬件部分

电源引脚:
DHT11的供电电压为3-5.5V。
传感器上电后,要等待1s 以越过不稳定状态,在此期间无需发送任何指令。
电源引脚(VDD,GND)之间可增加一个100nF 的电容,用以去耦滤波。

实物张下图的样子:
在这里插入图片描述
接口:建议连接线长度短于20米时用5K上拉电阻,大于20米时根据实际情况使用合适的上拉电阻。
所以典型的应用电路如下:
在这里插入图片描述
原理图如下:
在这里插入图片描述
综上在仿真里这部分是这样设计的
在这里插入图片描述

DHT11接口部分

上面看完了硬件部分的介绍,下面看使用传感器读取数据的接口部分。

DHT11接口上面介绍了是单线制串行接口

DHT11单总线工作原理:
DATA 输出线用于单片机与DHT11之间的通讯,一次通讯时间4ms左右
单片机发送一次开始信号后,DHT11从低功耗模式转换到高速模式,等待主机开始信号结束后
DHT11发送响应信号,送出40bit的数据,并触发一次信号采集
用户可选择读取数据,采集数据后转换到低速模式
如果没有接收到主机发送的开始信号,DHT11不会主动进行温湿度采集

DHT11数据格式:
一次完整的数据传输为40bit,高位先出
_数据格式_:8bit湿度整数数据+8bit湿度小数数据+8bi温度整数数据+8bit温度小数数据+8bit校验;
DHT11数据分小数部分和整数部分,当前小数部分用于以后扩展,现读出为零; 测量分辨率分别为8bit(温度)、8bit(湿度)
数据传送正确时校验位等于“8bit湿度整数数据+8bit湿度小数数据+8bi温度整数数据+8bit温度小数数据”之和
在这里插入图片描述
一次完整的信号读取如上图所示

开始信号由于上拉电阻,总线空闲状态为高电平,主机发出开始信号,把总线拉低大于18ms,拉高电平延时等待20-40us后, 读取DHT11的响应信号
响应信号: DHT11接收到主机的开始信号后,等待主机开始信号结束,发送80us低电平响应信号,再把总线拉高80us;主机发送开始信号结束后,可以切换到输入模式,总线由上拉电阻拉高或者输出高电平均可。
这两部分的信号如下:深绿色是主机信号,浅绿色是DHT11信号
在这里插入图片描述
数据信号: 每一bit数据都以50us低电平开始,高电平的长短决定数据位是0还是1(26us-28us为0;70us为1),如下图所示:
在这里插入图片描述
在这里插入图片描述
结束信号: 当最后一bit数据传送完毕后,DHT11拉低总线50us,随后总线由上拉电阻拉高进入空闲状态。

了解完接口部分,下面看看代码如何实现读取数据的。

开始信号代码

/*主机(stm32)发送 开始信号*/
void DHT11_Rst(void)   
{                 
    DHT11_IO_OUT(); //stm32的io口设置为输出模式
    DHT11_DQ_High ;//拉高
    DHT11_DQ_Low ;//拉低
    delay(25000);    //延时,拉低至少18ms
    DHT11_DQ_High; //DQ=1 
    delay(55);     //主机拉高20~40us
}

DHT11响应信号代码

//等待DHT11的回应  DHT的响应信号 先拉低80us,在拉高80us
//返回1:未检测到DHT11的存在
//返回0:存在
u8 DHT11_Check(void)    
{   
    u8 retry=0;//定义临时变量
    DHT11_IO_IN();    //stm32的io口设置为输入模式
    if (GPIO_ReadInputDataBit(GPIO_DHT11,IO_DHT11)==1)//DHT11会拉低40~80us  如果是高则DHT11没有响应信号则判断没有DHT11
        {
            return 0 ;//如果是高则DHT11没有响应信号则判断没有DHT11
        }else
        {
            while(GPIO_ReadInputDataBit(GPIO_DHT11,IO_DHT11)==0 && (retry < 200))//DHT11拉低了持续200个循环 DHT11会拉低80us
                retry++ ;
        }
        delay(40) ;
        delay(40) ;
        return 1 ;
}

在使用DHT11的时候,肯定要初始化,那么就可以先调用开始信号函数,然后接受响应函数,判断DHT11是否存在,存在则初始化完成

//初始化DHT11的IO口 DQ 同时检测DHT11的存在  
void DHT11_Init(void)
{     
 RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);//使能PA口时钟
 DHT11_Rst();  //复位DHT11
 DHT11_Check();//等待DHT11的回应
}
//从DHT11读取一个位
//返回值:1/0
u8 DHT11_Read_Bit(void)  

{
        u8 retry=0;

        while((GPIO_ReadInputDataBit(GPIO_DHT11,IO_DHT11)==1)&&retry<100)//等待变为低电平 每一bit数据都以50us低电平开始
        {
            retry++;
            delay(2);
        }

        retry=0;

        while((GPIO_ReadInputDataBit(GPIO_DHT11,IO_DHT11)==0)&&retry<100)//等待变高电平  然后的高电平持续时间决定了该位是0还是1
        {
            retry++;
            delay(2);
        }

        delay(40);//等待40us   26us-28us为0;70us为1  所以等待40us后,是高则为1 是低则为0

        if(GPIO_ReadInputDataBit(GPIO_DHT11,IO_DHT11)==1)//判断是高还是低
        return 1;

        else 
        return 0;   
}

从DHT11读取一个位
首先等待变为低电平 每一bit数据都以50us低电平开始
然后等待变高电平 然后的高电平持续时间决定了该位是0还是1
等待40us 26us-28us为0;70us为1 所以等待40us后,是高则为1 是低则为0
最后判断是高还是低

有了读取位的函数则可以将8位组成一个字节

//从DHT11读取一个字节(8位)
//返回值:读到的数据
u8 DHT11_Read_Byte(void)    

{        
    u8 i,dat;
    dat=0;//数据清0
        for (i=0;i<8;i++) //循环8次,组成一个字节
        {
            dat<<=1; //左移一位 ,高位在前
            dat|=DHT11_Read_Bit();//或与及把最后1位置成了读取的1位
    }    
    return dat;//返回数据
}

然后一帧数据有40位,及5个字节,最后一个字节是校验位,其它字节代表已在前面描述

//从DHT11读取一次数据
//temp:温度值(范围:0~50°)
//humi:湿度值(范围:20%~90%)
//返回值:0,正常;1,读取失败
u8 DHT11_Read_Data(u8 *temp,u8 *humi)    
{        
     u8 buf[5];//5个字节 一帧数据
     u8 i;
     DHT11_Rst();//开始信号
        if(DHT11_Check()==0)//DHT11拉高准备输出
        {
            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];//赋值湿度
                *temp=buf[2];//赋值温度
            }
        }
        else return 1;
        return 0;    
}

上的代码把DHT11的驱动代码写完了,在main函数中调用也很简单,下面给个例程

int main(void)
{
    //配置系统时钟
    。。。
    //初始化DHT11
    DHT11_Init();
    u8 temperature,humidity;//声明温度及湿度
    while(1)
    {
        DHT11_Read_Data(&temperature,&humidity) ;//读取一次数据
    }
}

DHT11 protues测试

在protues中加入lcd1602的显示代码,则可以显示读取的数据和传感器本身的数据是否一致
在这里插入图片描述