DHT11温湿度传感器模块简介

在这里插入图片描述

DHT11概述

  数字温湿度传感器是一款含有已校准数字信号输出的温湿度复合传感器。它应用专用的数字模块采集技术和温湿度传感技术,确保产品具有极高的可靠性与卓越的长期稳定性。

  传感器包括一个电阻式感湿元件和一个NTC测温元件,并与一个高性能8位单片机相连接。因此该产品具有品质卓越、超快响应、抗干扰能力强、性价比极高等优点。每个DHT11传感器都在极为精确的湿度校验室中进行校准。校准系数以程序的形式储存在OTP内存中,传感器内部在检测信号的处理过程中要调用这些校准系数。
  单线制串行接口,使系统集成变得简易快捷。超小的体积、极低的功耗,信号传输距离可达20米以上,使其成为各类应用甚至最为苛刻的应用场合的最佳选则。产品为 4 针单排引脚封装。连接方便,特殊封装形式可根据用户需求而提供。

在这里插入图片描述
注意
  (1)避免结露情况下使用。
  (2)长期保存条件:温度10—40℃,湿度60%以下。

技术参数

供电电压: 3.3~5.5V DC  输 出: 单总线数字信号 互 换 性: 可完全互换

测量范围: 湿度20-90%RH, 温度0~50℃  测量精度: 湿度±5%RH, 温度±2℃

分 辨 率: 湿度1%RH, 温度1℃  长期稳定性: 《±1%RH/年

测量时的供电电流为1.0mA,  待机时的供电电流为0.06mA
在这里插入图片描述

应用电路

在这里插入图片描述

引脚说明

在这里插入图片描述

温湿度采集范围

  湿度采集范围5%~ 95%,在环境温度为25℃时,湿度采集精度是±5%。温度采集范围是-20℃~60℃,在环境温度为25℃时,温度采集精度是±2℃。

在这里插入图片描述

应用信息

7.1工作与贮存条件
  超出建议的工作范围可能导致高达3%RH的临时性漂移信号。返回正常工作条后,传感器会缓慢地向校准状态恢复。要加速恢复进程/可参阅7.3小节的“恢复处理”。在非正常工作条件下长时间使用会加速产品的老化过程。
7.2暴露在化学物质中
  电阻式湿度传感器的感应层会受到化学蒸汽的干扰,化学物质在感应层中的扩散可能导致测量值漂移和灵敏度下降。在一个纯净的环境中,污染物质会缓慢地释放出去。下文所述的恢复处理将加速实现这一过程。高浓度的化学污染会导致传感器感应层的彻底损坏。

7.3恢复处理
  置于极限工作条件下或化学蒸汽中的传感器,通过如下处理程序,可使其恢复到校准时的状态。在50-60℃和<10%RH的湿度条件下保持2小时(烘干);随后在20-30℃和>70%RH的湿度条件下保持5小时以上。

7.4温度影响

 气体的相对湿度,在很大程度上依赖于温度。因此在测量湿度时,应尽可能保证湿度传感器在同一温度下工作。如果与释放热量的电子元件共用一个印刷线路板,在安装时应尽可能将DHT11远离电子元件,并安装在热源下方,同时保持外壳的良好通风。为降低热传导,DHT11与印刷电路板其它部分的铜镀层应尽可能最小,并在两者之间留出一道缝隙。

7.5光线
  长时间暴露在太阳光下或强烈的紫外线辐射中,会使性能降低。7.6配线注意事项DATA信号线材质量会影响通讯距离和通讯质量,推荐使用高质量屏蔽线。

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信号表示方法如下图所示
在这里插入图片描述

实验一:温湿度读取

项目要求:

  根据时序图直接测得温湿度。

电路搭建

在这里插入图片描述

参考程序

const int dht11Pin = 2;   //连接2号引脚
//定义湿度传感器的几种状态和版本
#define DHTLIB_OK        0
#define DHTLIB_ERROR_CHECKSUM -1
#define DHTLIB_ERROR_TIMEOUT  -2
#define DHT11LIB_VERSION "0.4.1"
int humidity;
int temperature;

//dht11Read函数中的变量
uint8_t bits[5];  //一次完整的数据传输为40bit,每8bit为一个数据,即:数组个数为5
uint8_t cnt = 7; //这个是用来给每一个数据的每一位输入值时计数用的。
uint8_t idx = 0; //这个是给5个数组计数用的。

double Fahrenheit(double celsius) //摄氏温度度转化为华氏温度
{
  return 1.8 * celsius + 32;
}   

double Kelvin(double celsius)     //摄氏温度转化为开氏温度
{
  return celsius + 273.15;
}    

// 露点(点在此温度时,空气饱和并产生露珠)
// 参考: http://wahiduddin.net/calc/density_algorithms.htm
double dewPoint(double celsius, double humidity)
{
  double A0 = 373.15 / (273.15 + celsius);
  double SUM = -7.90298 * (A0 - 1);
  SUM += 5.02808 * log10(A0);
  SUM += -1.3816e-7 * (pow(10, (11.344 * (1 - 1 / A0))) - 1) ;
  SUM += 8.1328e-3 * (pow(10, (-3.49149 * (A0 - 1))) - 1) ;
  SUM += log10(1013.246);
  double VP = pow(10, SUM - 3) * humidity;
  double T = log(VP / 0.61078); // temp var
  return (241.88 * T) / (17.558 - T);
}

// 快速计算露点,速度是5倍dewPoint()
// 参考: http://en.wikipedia.org/wiki/Dew_point
double dewPointFast(double celsius, double humidity)
{
  double a = 17.271;
  double b = 237.7;
  double temp = (a * celsius) / (b + celsius) + log(humidity / 100);
  double Td = (b * temp) / (a - temp);
  return Td;
}

//根据时序图定义函数,用来读取具体数值
int dht11Read(int pin){
  pinMode(dht11Pin, OUTPUT);//引脚设置为输出模式
  digitalWrite(dht11Pin, LOW);//由于空闲时为高电平状态,需拉低等待DHT11相应
  delay(18);  //需要拉低必须大于18毫秒
  digitalWrite(dht11Pin, HIGH);//再拉高
  delayMicroseconds(40);//需要等待20~40微秒后
  pinMode(dht11Pin, INPUT);//这时DHT11开始接收主机的开始信号,故需设置为输入模式

//确认或超时
  unsigned int loopCnt = 10000;
  while (digitalRead(dht11Pin) == LOW)//从时序图中可以看出,接受数据一开始首先要读取80微秒的低电平,这里是一个等待,要把这80微秒等过去,但是有时候也有可能是传感器出现了故障,他一直发低电平,如果你持续等待不就相当于死机了,所以在这里要设置一个超时,也就是说要等待,但时间长了,就认为出问题了,返回一个异常信息。
    if (loopCnt-- == 0) return DHTLIB_ERROR_TIMEOUT;
  loopCnt = 10000;
  while (digitalRead(dht11Pin) == HIGH)//从时序图中可以看出,在80微秒的低电平之后是80微秒的高电平,这里仍然要等待,超时的原理与上面的低电平一样。
    if (loopCnt-- == 0) return DHTLIB_ERROR_TIMEOUT;
//从下面开始读取数据,因为40位,所以要循环40次,每次一位
  for (int i = 0; i < 40; i++)
  {
    loopCnt = 10000;
    while (digitalRead(dht11Pin) == LOW)//这句是等待低电平过去.根据时序图,可以看出,对于每一个bite位数据,都是由一个低电平和一个高电平组成,区分这一位数据是1还是0取决于高电平的时常,如果高电平的时常为70微秒则表示1,如果高电平的时常为26~28微秒则表示0,因此读取每一位数据时,都是先等待把50微秒的低电平等过去,然后判断高电平的时常,根据这个时常来判断这bite的数据是1还是0.
      if (loopCnt-- == 0) return DHTLIB_ERROR_TIMEOUT;	//同样有可能超时失效。
    unsigned long t = micros(); //micros()记录板子上电的时间(微秒)
    loopCnt = 10000;
    while (digitalRead(dht11Pin) == HIGH)	//这里就把高电平读出来了
      if (loopCnt-- == 0) return DHTLIB_ERROR_TIMEOUT;
    if ((micros() - t) > 40) bits[idx] |= (1 << cnt);//然后再次使用micros()函数获取当前时间,减去读取高电平之前的时间点,也就是这个高电平的时常了,然后看这个时常是否大于40微秒,如果大于就认为是1,否则就认为这位是0.那么这里又是怎么运算的呢?分析下:bits[idx]表示一个8位的数组,假设他是0000 0000,运算符“|=”表示按位进行或运算,然后再把运算的结果赋给运算符左边的变量。而(1 << cnt)表示把数字1的二进制表示法向左移动cnt位,移动后的空位用0来填充。因此,对于一个八位的1可以表示为:0000 0001,刚才的初始化过程中我们知道cnt的值为7,所以,把这个0000 0001左移七位就变成了:1000 0000.然后将这个数与0000 0000进行|=运算,之后bits[idx]中的值就是1000 0000。可见这段代码实现的功能就是如果的到的这位数据是1,就将他存储到bits[idx]相应的位上去。
    if (cnt == 0)   //cnt为0表示一个8位的数组已经装满了,要换到下一个八位的数组上去,于是就把cnt复原为7,idx++让idx直到bits的下一个八位的数组上去。
    {
      cnt = 7;    // restart at MSB
      idx++;      // next byte!
    }
    else cnt--;
    //如果cnt不为0就表示这个八位的数据还没有读完,这时只需要让cnt-1,来填充下一位数据就可以了。
		//注意,在初始化的过程中我们把这40位的数据都初始化为0了,所以只有当有1出现时才需要进行改变。
  }
  humidity    = bits[0];  //湿度,第1个8位是湿度的整数部分
  temperature = bits[2];  //温度,第3个8位是温度的整数部分
  uint8_t sum = bits[0] + bits[2];//总和
  if (bits[4] != sum) return DHTLIB_ERROR_CHECKSUM;
  return DHTLIB_OK;
}

void setup() {
  Serial.begin(9600);
  Serial.println("DHT11 TEST PROGRAM ");
  Serial.print("LIBRARY VERSION: ");
  Serial.println(DHT11LIB_VERSION);
  Serial.println();

}

void loop() {
  Serial.println("\n");
  int chk = dht11Read(dht11Pin);
  Serial.print("Read sensor: ");
  switch (chk)
  {
    case DHTLIB_OK:
      Serial.println("OK");
      break;
    case DHTLIB_ERROR_CHECKSUM:
      Serial.println("Checksum error");
      break;
    case DHTLIB_ERROR_TIMEOUT:
      Serial.println("Time out error");
      break;
    default:
      Serial.println("Unknown error");
      break;
  }

  Serial.print("Humidity (%): ");
  Serial.println((float)humidity, 2);

  Serial.print("Temperature (oC): ");
  Serial.println((float)temperature, 2);

  Serial.print("Temperature (oF): ");
  Serial.println(Fahrenheit(temperature), 2);

  Serial.print("Temperature (K): ");
  Serial.println(Kelvin(temperature), 2);

  Serial.print("Dew Point (oC): ");
  Serial.println(dewPoint(temperature, humidity));

  Serial.print("Dew PointFast (oC): ");
  Serial.println(dewPointFast(temperature, humidity));

  delay(2000);
}

实验结果

在这里插入图片描述

原理图

在这里插入图片描述