产品概述

DHT11数字温湿度传感器是一款含有已校准数字信号输出的温湿度 复合传感器。应用专用的数字模块采集技术和温湿度传感技术,可以将获取到的环境温湿度信号通过单总线传输;信号中携带有校验码,一定程度上保证了数据的准确性。

性能指标

参数最小最大
温度范围-20℃60℃
湿度范围5%RH95%RH
电压3.3V5.5V
电流0.06mA1.0mA
参数精确度
温度±2℃
湿度±5%RH

引脚说明:

  1. VDD 供电3.3~5.5V DC
  2. DATA 串行数据,单总线
  3. NC 空脚
  4. GND 接地,电源负极

工作原理

数据时序图

image-20220318152411531

  • 起始信号:微处理器把数据总线(SDA)拉低一段时间至少 18ms(最大不得超过 30ms),在拉高20us-40us,通知传感器准备数据。
  • 响应信号:传感器把数据总线(SDA)拉低 83µs,再拉高 87µs 以响应主机的起始信号。
  • 数据格式:收到主机起始信号后,传感器一次性从数据总线(SDA)串出 40 位数据,高位先出

    image-20221126205849766

    image-20221126205921333

    当检测到这一位数据的高电平后,我们要看这段高电平究竟会持续多长时间,0信号的高电平持续26-28us,1信号则持续70us。所以在上一步检测到高电平之后我们不妨等一等,等个30us看看高电平是不是还是存在,若还是高电平,那这一位信号就是1信号,若已经变低了,就是0信号,将这个1或0赋值给一个变量。

  • 温度:温度高位为温度整数部分数据,温度低位为温度小数部分数据,且温度低位 Bit8 为 1 则表示负温度,否则 为正温度
  • 湿度:湿度高位为湿度整数部分数据,湿度低位为湿度小数部分数
  • 校验位:校验位=湿度高位+湿度低位+温度高位+温度低位

以上内容来自奥松电子DHT11官方文档,详细内容请查看文档

代码实例

树莓派Python3代码实例

#!/usr/bin/python3  coding=utf-8
import RPi.GPIO as GPIO
import time

data = 18   # DHT11的data引脚连接到的树莓派的GPIO引脚,使用BCM编号
tmp=[]      # 用来存放读取到的数据
a,b=0,0

def delayMicrosecond(t):    # 微秒级延时函数
    start,end=0,0           # 声明变量
    start=time.time()       # 记录开始时间
    t=(t-3)/1000000     # 将输入t的单位转换为秒,-3是时间补偿
    while end-start<t:  # 循环至时间差值大于或等于设定值时
        end=time.time()     # 记录结束时间

def DHT11():
    GPIO.setmode(GPIO.BCM)      # 设置为BCM编号模式
    GPIO.setwarnings(False)
    del tmp[0:]                 # 删除列表
    time.sleep(1)               # 延时1秒
    GPIO.setup(data, GPIO.OUT)  # 设置GPIO口为输出模式
    #GPIO.output(data,GPIO.HIGH) # 设置GPIO输出高电平
    #delayMicrosecond(10*1000)   # 延时10毫秒
    GPIO.output(data,GPIO.LOW)  # 设置GPIO输出低电平
    delayMicrosecond(25*1000)   # 延时25毫秒      
    GPIO.output(data,GPIO.HIGH) # 设置GPIO输出高电平
    GPIO.setup(data, GPIO.IN)   # 设置GPIO口为输入模式   
    a=time.time()           # 记录循环开始时间
    while GPIO.input(data): # 一直循环至输入为低电平
        b=time.time()       # 记录结束时间
        if (b-a)>0.1:       # 判断循环时间是否超过0.1秒,避免程序进入死循环卡死
            break           # 跳出循环
        
    a=time.time()
    while GPIO.input(data)==0:  # 一直循环至输入为高电平
        b=time.time()
        if (b-a)>0.1:
            break
                
    a=time.time()
    while GPIO.input(data): # 一直循环至输入为低电平
        b=time.time()
        if (b-a)>=0.1:
            break   
            
    for i in range(40):         # 循环40次,接收温湿度数据
        a=time.time()
        while GPIO.input(data)==0:  #一直循环至输入为高电平
            b=time.time()
            if (b-a)>0.1:
                break
                       
        delayMicrosecond(28)    # 延时28微秒
            
        if GPIO.input(data):    # 超过28微秒后判断是否还处于高电平
            tmp.append(1)       # 记录接收到的bit为1
                
            a=time.time()
            while GPIO.input(data): # 一直循环至输入为低电平
                b=time.time()
                if (b-a)>0.1:
                    break
        else:
            tmp.append(0)       # 记录接收到的bit为0
          
            humidity_bit=tmp[0:8]       # 分隔列表,第0到7位是湿度整数数据
    humidity_point_bit=tmp[8:16]# 湿度小数
    temperature_bit=tmp[16:24]  # 温度整数
    temperature_point_bit=tmp[24:32]    # 温度小数
    check_bit=tmp[32:40]        # 校验数据
 
    humidity_int=0
    humidity_point=0
    temperature_int=0
    temperature_point=0
    check=0

    for i in range(8):          # 二进制转换为十进制
        humidity_int+=humidity_bit[i]*2**(7-i)
        humidity_point+=humidity_point_bit[i]*2**(7-i)
        temperature_int+=temperature_bit[i]*2**(7-i)
        temperature_point+=temperature_point_bit[i]*2**(7-i)
        check+=check_bit[i]*2**(7-i)
  
    humidity=humidity_int+humidity_point/10
    temperature=temperature_int+temperature_point/10
  
    check_tmp=humidity_int+humidity_point+temperature_int+temperature_point
  
    if check==check_tmp and temperature!=0 and temperature!=0:  # 判断数据是否正常
        print("Temperature is ", temperature,"℃\nHumidity is ",humidity,"%")# 打印温湿度数据
    else:
        print("error")
while True:   
    DHT11()
    GPIO.cleanup()
    time.sleep(5)

树莓派C语言代码实例

//
//mydht11.c
//gcc dht11.c -o dht11 -lwiringPi
//代码非原创,已经找不到原作者了,感谢大佬
//
#include <wiringPi.h>
#include <stdio.h>
#include <stdlib.h>
 
typedef unsigned char uint8;
typedef unsigned int  uint16;
typedef unsigned long uint32;
 
#define HIGH_TIME 32
 
int pinNumber = 1;  //use gpio1 to read data
uint32 databuf;
 
uint8 readSensorData(void)
{
    uint8 crc; 
    uint8 i;
 
    pinMode(pinNumber,OUTPUT); // set mode to output
    digitalWrite(pinNumber, 1); // output a low level
    delayMicroseconds(4);
    digitalWrite(pinNumber, 0); // output a high level 
    delay(25);
    digitalWrite(pinNumber, 1); // output a low level
    delayMicroseconds(60); 
    pinMode(pinNumber, INPUT); // set mode to input
    pullUpDnControl(pinNumber,PUD_UP);
 
    if(digitalRead(pinNumber)==0) //SENSOR ANS
    {
        while(!digitalRead(pinNumber)); //wait to high
        delayMicroseconds(80);
        for(i=0;i<32;i++)
        {
          while(digitalRead(pinNumber)); //data clock start
          while(!digitalRead(pinNumber)); //data start
          delayMicroseconds(HIGH_TIME);
          databuf*=2;
          if(digitalRead(pinNumber)==1) //1
          {
            databuf++;
          }
        }
 
        for(i=0;i<8;i++)
        {
          while(digitalRead(pinNumber)); //data clock start
          while(!digitalRead(pinNumber)); //data start
          delayMicroseconds(HIGH_TIME);
          crc*=2;  
          if(digitalRead(pinNumber)==1) //1
          {
            crc++;
          }
        }
      return 1;
    }
    else
    {
      return 0;
    }
}
 
int main (void)
{
    if (-1 == wiringPiSetup()) {
      //printf("Setup wiringPi failed!");
      return 1;
    }
 
    pinMode(pinNumber, OUTPUT); // set mode to output
    digitalWrite(pinNumber, 1); // output a high level 
 
    //while(1) 
    //{
    pinMode(pinNumber,OUTPUT); // set mode to output
    digitalWrite(pinNumber, 1); // output a high level 
    //delay(3000);
    if(readSensorData())
    {
      printf("OK!\n");
      printf("RH:%d.%d\n",(databuf>>24)&0xff,(databuf>>16)&0xff); 
      printf("TMP:%d.%d\n",(databuf>>8)&0xff,databuf&0xff);
      databuf=0;
    }
    else
    {
      printf("Error!\n");
      databuf=0;
    }
    //}
  return 0;
}

ESP32C语言代码实例(ESP-IDF官方编译烧写工具)

#include <stdio.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "driver/gpio.h"
#include "sdkconfig.h"
#define DHT11_PIN (15) //可通过宏定义,修改引脚
#define DHT11_CLR gpio_set_level(DHT11_PIN, 0) //设为低电平
#define DHT11_SET gpio_set_level(DHT11_PIN, 1) //设为高电平
#define DHT11_IN gpio_set_direction(DHT11_PIN, GPIO_MODE_INPUT) //设为输入模式
#define DHT11_OUT gpio_set_direction(DHT11_PIN, GPIO_MODE_OUTPUT) //设为输出模式
uint8_t DHT11Data[4] = {0};
uint8_t Temp, Humi;
// us延时函数,误差不能太大
void DelayUs(uint32_t nCount)
{
    ets_delay_us(nCount);
}
//DHT11初始化
void DHT11_Start(void)
{
    /***************************
     * 
     * 主机发送给DHT11复位信号
     * 
     * 首先主机拉低总线至少 18ms,然后再拉高总线,延时 20~40us,取中间值 30us,此时复位信号发送完毕。 
     * 
     * **********************************/
    DHT11_OUT; //设置端口方向 
    DHT11_CLR; //拉低端口
    DelayUs(19 * 1000);
    //   vTaskDelay(19 * portTICK_RATE_MS); //持续最低18ms;
    DHT11_SET;   //主机拉高端口
    DelayUs(30); //总线由上拉电阻拉高,主机延时30uS;
    /********************************
     * DHT11发送响应信号
     * 
     * DHT11 检测到复位信号后,触发一次采样,
     * 并拉低总线 80us 表示响应信号,告诉主机数据已经准备好了;
     * 然后 DHT11 拉高总线 80us,
     * 之后开始传输数据。如果检测到响应信号为高电平,
     * 则 DHT11 初始化失败,
     * 请检查线路是否连接正常。
     * 
     *******************************/
    DHT11_IN;    //设置端口方向
    while (!gpio_get_level(DHT11_PIN))
        ; // DHT11等待80us低电平响应信号结束
    while (gpio_get_level(DHT11_PIN))
        ; // DHT11   将总线拉高80us
}
uint8_t DHT11_ReadValue(void)
{
    uint8_t i, sbuf = 0;
    for (i = 8; i > 0; i--)
    {
        sbuf <<= 1;
        while (!gpio_get_level(DHT11_PIN))
            ;
        DelayUs(40); // 延时 30us 后检测数据线是否还是高电平
        if (gpio_get_level(DHT11_PIN))
        {
            sbuf |= 1;
        }
        else
        {
            sbuf |= 0;
        }
        while (gpio_get_level(DHT11_PIN))
            ;
    }
    return sbuf;
}
uint8_t DHT11_ReadTemHum(uint8_t *buf)
{
    uint8_t check;
    buf[0] = DHT11_ReadValue();
    buf[1] = DHT11_ReadValue();
    buf[2] = DHT11_ReadValue();
    buf[3] = DHT11_ReadValue();
    check = DHT11_ReadValue();
    if (check == buf[0] + buf[1] + buf[2] + buf[3])
        return 1;
    else
        return 0;
}
void app_main(void)
{
    // printf("ESP32 DHT11 TEST:%s,%s!\r\n", __DATE__, __TIME__);
    gpio_pad_select_gpio(DHT11_PIN);
    while (1)
    {
        DHT11_Start();
        if (DHT11_ReadTemHum(DHT11Data))
        {
            Temp = DHT11Data[2];
            Humi = DHT11Data[0];
            printf("ESP32 DHT11 TEST:%s,%s!\r\n", __DATE__, __TIME__);
            printf("Temp=%d.%d, Humi=%d.%d\r\n", Temp,DHT11Data[3],Humi,DHT11Data[1]);
        }
        else
        {
            printf("DHT11 Error!\r\n");
        }
        vTaskDelay(5000 / portTICK_PERIOD_MS);
    }
}
  • 附录:

    树莓派GPIO

    树莓派GPIO

最后修改:2024 年 05 月 12 日
如果觉得我的文章对你有用,请随意赞赏