bigfanofloT 发表于 2017-5-11 20:05:48

DHT11温湿度传感器驱动

本帖最后由 bigfanofloT 于 2017-5-16 19:44 编辑

一、DHT11介绍
DHT11是一款有已校准数字信号输出的温湿度传感器。它应用专用的数字模块采集技术和温湿度传感技术,确保产品具有极高的可靠性和卓越的长期稳定性。传感器包括一个电阻式感湿元件和一个NTC测温元件,并与一个高性能8位单片机相连接。因此该产品具有品质卓越、超快响应、抗干扰能力强、性价比极高等优点。每个DHT11传感器都在极为精确的湿度校验室中进行校准。校准系数以程序的形式存在OTP内存中,传感器内部在检测信号的处理过程中要调用这些校准系数。单线制串行接口,使系统集成变得简易快捷。超小的体积、极低的功耗,使其成为该类应用中,在苛刻应用场合的最佳选择。产品为4针单排引脚封装,连接方便。
主要性能指标如下:
测量范围:湿度20-90%RH, 温度0~50℃
分辨率:湿度1%RH, 温度1℃
精度:湿度+/-5%RH, 温度+/-2℃
量程:湿度20-90%RH, 温度0~50℃
供电电压 :3.3~5.5V DC
输 出:单总线数字信号
长期稳定性: <±1%RH/年


图1 DHT11实物图

DHT11输出单总线数字信号,可以十分方便的与MCU连接,典型使用方法如图2所示:

图2 DHT11典型应用电路
二、硬件连线
对于Gokit V2.3扩展板,板载DHT11的数字输出IO连接到了Arduino UNO接口的D3,如图3所示:

图3 Gokit V2.3扩展板DHT11原理图
根据Nucleo-F767ZI的原理图,图4可以知道,STM32F767ZIT6的GPIO PE13连接到了Arduino UNO接口的D3,因此在后面我们将配置PE13与DHT11通信,根据DHT11时序编写驱动。

图4 Nucleo-F767ZI的Arduino UNO接口原理图

三、DHT11时序
DATA 用于微处理器与 DHT11之间的通讯和同步,采用单总线数据格式,一次通讯时间4ms左右,数据分小数部分和整数部分,具体格式在下面说明,当前小数部分用于以后扩展,现读出为零。
操作流程如下:
一次完整的数据传输为40bit,高位先出。
数据格式:8bit湿度整数数据+8bit湿度小数数据+8bi温度整数数据+8bit温度小数数据+8bit校验和
数据传送正确时校验和数据等于“8bit湿度整数数据+8bit湿度小数数据+8bi温度整数数据+8bit温度小数数据”所得结果的末8位。

用户MCU发送一次开始信号后,DHT11从低功耗模式转换到高速模式,等待主机开始信号结束后,DHT11发送响应信号,送出40bit的数据,并触发一次信号采集,用户可选择读取部分数据.从模式下,DHT11接收到开始信号触发一次温湿度采集,如果没有接收到主机发送开始信号,DHT11不会主动进行温湿度采集.采集数据后转换到低速模式。
通讯过程如下图:


总线空闲状态为高电平,主机把总线拉低等待DHT11响应,主机把总线拉低必须大于18毫秒,保证DHT11能检测到起始信号。DHT11接收到主机的开始信号后,等待主机开始信号结束,然后发送80us低电平响应信号.主机发送开始信号结束后,延时等待20-40us后, 读取DHT11的响应信号,主机发送开始信号后,可以切换到输入模式,或者输出高电平均可, 总线由上拉电阻拉高。


总线为低电平,说明DHT11发送响应信号,DHT11发送响应信号后,再把总线拉高80us,准备发送数据,每一bit数据都以50us低电平时隙开始,高电平的长短定了数据位是0还是1.格式见下面图示.如果读取响应信号为高电平,则DHT11没有响应,请检查线路是否连接正常.当最后一bit数据传送完毕后,DHT11拉低总线50us,随后总线由上拉电阻拉高进入空闲状态。      
数字0信号表示方法如下图:


数字1信号表示方法.如下图:

四、完整程序
如下是DHT11驱动的完整代码,用户可以十分方便的移植到其它型号STM32或者MCU,只需修改GPIO定义、GPIO读写即可。Hal_temp_hum.h文件如下:
#ifndef _HAL_HEMP_HUM_H
#define _HAL_HEMP_HUM_H

#include <stdio.h>
#include "stm32f7xx_hal.h"<font color="#008000">//若用户使用了其它MCU,需要修改此处MCU相关头文件</font>

<font color="#008000">//Set GPIO Direction,若用户使用不同的GPIO请修改此处</font>
#define DHT11_DIN_Pin GPIO_PIN_13
#define DHT11_DIN_GPIO_Port GPIOE
      <font color="#008000">//控制GPIO输出高低电平宏</font>
#define      DHT11_DQ_OUT_1         HAL_GPIO_WritePin(DHT11_DIN_GPIO_Port, DHT11_DIN_Pin, GPIO_PIN_SET)
#define      DHT11_DQ_OUT_0          HAL_GPIO_WritePin(DHT11_DIN_GPIO_Port, DHT11_DIN_Pin, GPIO_PIN_RESET)
<font color="#008000">//读取GPIO电平</font>
#define      DHT11_DQ_IN            HAL_GPIO_ReadPin(DHT11_DIN_GPIO_Port, DHT11_DIN_Pin)

#define MEAN_NUM            10

typedef struct
{
    uint8_t curI;
    uint8_t thAmount;
    uint8_t thBufs;
}thTypedef_t;

/* Function declaration */
uint8_t dht11Init(void); //Init DHT11
uint8_t dht11Read(uint8_t *temperature, uint8_t *humidity); //Read DHT11 Value
static uint8_t dht11ReadData(uint8_t *temperature, uint8_t *humidity);
static uint8_t dht11ReadByte(void);//Read One Byte
static uint8_t dht11ReadBit(void);//Read One Bit
static uint8_t dht11Check(void);//Chack DHT11
static void dht11Rst(void);//Reset DHT11   
void dht11SensorTest(void);

#endif /*_HAL_HEMP_HUM_H*/

Hal_temp_hum.c文件如下:
/**
******************
*
* @file      Hal_temp_hum.c
* @author    Gizwtis
* @version   V03010100
* @date      2016-07-05
*
* @brief   机智云.只为智能硬件而生
*            Gizwits Smart Cloudfor Smart Products
*            链接|增值ֵ|开放|中立|安全|自有|自由|生态
*            www.gizwits.com
*
******************/
#include "hal_temp_hum.h"
#include <string.h>

thTypedef_t temphumTypedef;

void delayUs(uint32_t nus)
{
uint8_t i=0;
while(nus--)
{
                i=100;<font color="#008000">//自己定义,需根据系统时钟调整</font>
                while(i--) ;   
}
}


void DHT11_IO_OUT(void)
{
                GPIO_InitTypeDef myGPIO_InitStruct;
                myGPIO_InitStruct.Pin = DHT11_DIN_Pin;
                myGPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
                myGPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
                HAL_GPIO_Init(DHT11_DIN_GPIO_Port, &myGPIO_InitStruct);
}

void DHT11_IO_IN(void)
{
                GPIO_InitTypeDef myGPIO_InitStruct;
                myGPIO_InitStruct.Pin = DHT11_DIN_Pin;
          myGPIO_InitStruct.Pull = GPIO_PULLUP;
                myGPIO_InitStruct.Mode = GPIO_MODE_INPUT;
                myGPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
                HAL_GPIO_Init(DHT11_DIN_GPIO_Port, &myGPIO_InitStruct);
}
//Reset DHT11
static void dht11Rst(void)
{
    DHT11_IO_OUT();                                     //SET OUTPUT
    DHT11_DQ_OUT_0;                                     //GPIOA.0=0
    HAL_Delay(20);                                        //Pull down Least 18ms
    DHT11_DQ_OUT_1;                                     //GPIOA.0=1
    delayUs(30);                                       //Pull up 20~40us
}

static uint8_t dht11Check(void)
{
    uint8_t retry=0;
    DHT11_IO_IN();                                              //SET INPUT
    while (DHT11_DQ_IN && (retry<100))                        //DHT11 Pull down 40~80us
    {
      retry++;
      delayUs(1);
    }

    if(retry >= 100)
    {
      return 1;
    }
    else
    {
      retry=0;
    }

    while (!DHT11_DQ_IN&& (retry < 100))                  //DHT11 Pull up 40~80us
    {
      retry++;
      delayUs(1);
    }

    if(retry >= 100)
    {
      return 1;                              //check error
    }      

    return 0;
}

static uint8_t dht11ReadBit(void)
{
    uint8_t retry=0;
    while(DHT11_DQ_IN && (retry<100))                           //wait become Low level
    {
      retry++;
      delayUs(1);
    }

    retry = 0;
    while(!DHT11_DQ_IN && (retry < 100))                  //wait become High level
    {
      retry++;
      delayUs(1);
    }

    delayUs(30);//wait 40us

    if(DHT11_DQ_IN)
    {
      return 1;
    }
    else
    {
      return 0;
    }
}

static uint8_t dht11ReadByte(void)
{
    uint8_t i,dat;
    dat=0;
    for (i=0; i<8; i++)
    {
      dat<<=1;
      dat |= dht11ReadBit();
    }

    return dat;
}

static uint8_t dht11ReadData(uint8_t *temperature, uint8_t *humidity)
{
    uint8_t buf;
    uint8_t i;
    dht11Rst();
    if(0 == dht11Check())
    {
      for(i=0; i<5; i++)
      {
            buf = dht11ReadByte();
      }
      if(buf == (buf+buf+buf+buf))
      {
            *humidity = buf;
            *temperature = buf;
      }
    }
    else
    {
      return 1;
    }

    return 0;
}

uint8_t dht11Read(uint8_t *temperature, uint8_t *humidity)
{
    uint8_t curTem = 0, curHum = 0;
    uint16_t temMeans = 0, humMeans = 0;
    uint8_t curI = 0;
    uint8_t ret = 0;

    ret = dht11ReadData(&curTem, &curHum);

    if(1 != ret)
    {
      //Cycle store ten times stronghold
      if(MEAN_NUM > temphumTypedef.curI)
      {
            temphumTypedef.thBufs = curTem;
            temphumTypedef.thBufs = curHum;

            temphumTypedef.curI++;
      }
      else
      {
            temphumTypedef.curI = 0;

            temphumTypedef.thBufs = curTem;
            temphumTypedef.thBufs = curHum;

            temphumTypedef.curI++;
      }
    }
    else
    {
      return (1);
    }
   
    if(MEAN_NUM <= temphumTypedef.curI)
    {
      temphumTypedef.thAmount = MEAN_NUM;
    }

    if(0 == temphumTypedef.thAmount)
    {
      //Calculate Before ten the mean
      for(curI = 0; curI < temphumTypedef.curI; curI++)
      {
            temMeans += temphumTypedef.thBufs;
            humMeans += temphumTypedef.thBufs;
      }

      temMeans = temMeans / temphumTypedef.curI;
      humMeans = humMeans / temphumTypedef.curI;
      
      *temperature = temMeans;
      *humidity = humMeans;
    }
    else if(MEAN_NUM == temphumTypedef.thAmount)
    {
      //Calculate After ten times the mean
      for(curI = 0; curI < temphumTypedef.thAmount; curI++)
      {
            temMeans += temphumTypedef.thBufs;
            humMeans += temphumTypedef.thBufs;
      }

      temMeans = temMeans / temphumTypedef.thAmount;
      humMeans = humMeans / temphumTypedef.thAmount;
      
      *temperature = (uint8_t)temMeans;
      *humidity = (uint8_t)humMeans;
    }

    return (0);
}

uint8_t dht11Init(void)
{
      GPIO_InitTypeDef GPIO_InitStruct;
    /* Migrate your driver code */
__HAL_RCC_GPIOE_CLK_ENABLE();
      /*Configure GPIO pin Output Level */
HAL_GPIO_WritePin(GPIOE, DHT11_DIN_Pin, GPIO_PIN_RESET);
/*Configure GPIO pins : PBPin PBPin PBPin */
GPIO_InitStruct.Pin = DHT11_DIN_Pin;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
HAL_GPIO_Init(GPIOE, &GPIO_InitStruct);
    dht11Rst();
   
    memset((uint8_t *)&temphumTypedef, 0, sizeof(thTypedef_t));
   
    printf("dh11Init \r\n");
   
    return dht11Check();
}


本系列帖子目录:
http://club.gizwits.com/thread-6544-1-1.html

zhin 发表于 2017-5-23 15:53:37

有f103c8t6的温湿度驱动吗

bigfanofloT 发表于 2017-5-23 18:38:53

zhin 发表于 2017-5-23 15:53
有f103c8t6的温湿度驱动吗

有啊。你查看我其他帖子

阿赞不会烧录 发表于 2019-3-15 17:13:24

大佬你好,有红外传感器驱动和MQ-2烟雾传感器吗?
页: [1]
查看完整版本: DHT11温湿度传感器驱动