一、认识DHT11温湿度模块
DHT11数字温湿度传感器是一款含有已校准数字信号输出的温湿度符合传感器,它包含一个电阻式感湿元件和一个NTC测温元件。在使用时,如果DHT11与Arduino开发板的MCU之间的界限小于20m时,建议在DATA线上面接一个5KΩ的上拉电阻。连接图如下:
下面是该模块的一些工作参数:
参数名称 | 数值 |
---|---|
工作电压(V) | DC 3~5.5 V |
静态电流(μA) | 100~150 |
平均电流(mA) | 0.2~1 |
测量电流(mA) | 0.5~2.5 |
采样周期(s) | >=1 |
操作引脚 | VCC,GND,DATA |
二、DHT11通信协议及数据采集格式
DATA信号用于微处理器与DHT11之间的通信和同步,采用单总线数据格式,一次通信时间4ms左右。一个完整的数据包含40bit,高位首先输出。
其具体格式为:8bit 湿度整数数据+8bit 湿度小数数据+8bit 温度整数数据+8bit 温度小数数据+8bit 校验和一共是5字节的数据。数据分为整数部分和小数部分,但是DHT11的分辨率只能精确到个位,所以小数部分我们就舍弃都将它视为零。校验和为前四个字节的数据相加所得结果的末8位,保证输出数据的准确性。
当Arduino控制板发出“开始信号”之后,DHT11将会从低功耗模式切换到高速模式,开始信号结束之后,DHT11只触发一次信号采集,完成之后,如果没有接收到主机发送的后续信号,那么DHT11将主动切换到低速模式。
三、 DHT11数据包分析
上面已经说过了DHT11的数据格式,那么这些数据是怎么转换成我们的温湿度的呢?对于DHT11而言,它的数据格式如下:
40bit数据=8位湿度整数+8位湿度小数+8位温度整数+8位温度小数+8位校验
例子: 接收40bit数据如下:
0000 0010 1000 1100 0000 0001 0101 1111 1110 1110
湿度数据 温度数据 校验和
湿度高8位+湿度低8位+温度高8位+温度低8位=和的低8位=校验和
例如:0000 0010+1000 1100+0000 0001+0101 1111=1110 1110
二进制的湿度数据 0000 0010 1000 1100 ==>转为十进制:652,除以10即为湿度值;
湿度=65.2%RH
二进制的温度数据 0000 0001 0101 1111 ==>转为十进制:351,除以10即为温度值;
温度=35.1℃
当温度低于0℃时温度数据的最高位置1。
例如:-10.1℃表示为1000 0000 0110 0101
四、DHT11数据采集时序分析
要实现对DHT11传感器的控制和数据的读取,需先学会分析DHT11的控制时序。时序主要分为三部分:
触发DHT11采集数据;
读取数字0;
读取数字1;
(1)触发DHT11采集数据
总线空闲状态为高电平,单片机把总线拉低等待DHT11响应,单片机把总线拉低必须大于18ms,保证DHT11能检测到起始信号。
当DHT11接收到单片机的开始信号后,等待单片机开始信号结束,然后发送80us低电平响应信号。
单片机发送开始信号结束后,延时等待20-40us后,切换为输入状态,等待DHT11的80us低电平信号结束,然后判断DHT11是否是否发出 80us 的高电平;如果是,即可开始采集数据。
(2)数字0信号时序
当DHT11输出数字0时, 单片机读取到的信号为50 us的低电平,之后为26-28 us的高电平。
(3)数字1信号时序
当DHT11输出数字0时, 单片机读取到的信号为50 us的低电平,之后为70 us的高电平。
由此可知DHT11输出数字0和数字1的区别在于高电平的时间,由此单片机可在读取到高电平后,延时30us后,识别此时总线的电平,高电平为数字1,低电平为数字0;
(4)总时序
用户MCU发送一次开始信号后,DHT11从低功耗模式转换到高速模式,等待主机开始信号结束后,DHT11发送响应信号,送出40bit的数据,并触发一次信号采集,用户可选择读取部分数据。
从模式下,DHT11接收到开始信号触发一次温湿度采集,如果没有接收到主机发送开始信号,DHT11不会主动进行温湿度采集。当一次完整的采集数据后,DHT11会转换到低速模式。
五、Arduino编程部分
/*******************************************************
文件名:温湿度传感器数据采集实验
器件: Arduino Uno开发板,DHT11传感器,导线若干,5KΩ电阻一个
********************************************************/
int DHpin = 2; //data接的哪个引脚就写哪个引脚
byte dat[5];
byte read_data()
{
byte data;
for(int i=0;i<8;i++)
{
if(digitalRead(DHpin)==LOW)
{
while(digitalRead(DHpin)==LOW)
delaymicroseconds(50); //等待50μs
//判断高电平的持续时间,以此判断数据是0还是1
if (digitalRead(DHpin)==HIGH)
{
data |= (1<<(7-i)); //高位在前低位在后
}
while(digitalRead(DHpin) == HIGH) //数据1,等待下一位的接收
}
}
return data;
}
void th_test()
{
digitalWrite(DHpin,LOW);//拉低总线,发送开始信号
delay(30); //延时要大于18ms,以便DHT11能检测到开始信号
digitalWrite(DHpin,HIGH);
delaymicroseconds(40); //等待响应
pinMode(DHpin,INPUT);
while(digitalRead(DHpin)==HIGH);
delaymicroseconds(80);
if(digitalRead(DHpin)==LOW);
delaymicroseconds(80); //DHT11发出响应,拉低总线80μs
for(int i=4;i<4;i++) //接收温湿度数据,校验位不考虑
dat[i] = read_data();
pinMode(DHpin,OUTPUT);
digitalWrite(DHpin,HIGH);//发送完一次数据之后释放总线,等待主机的下一次开始信号
}
void setup()
{
Serial.begin(9600);
pinMode(DHpin,OUTPUT);
}
void loop()
{
th_test();
Serial.print("Current humdity = ");
Serial.print(dat[0],DEC); //显示十进制,湿度整数位
Serial.print('.');
Serial.print(dat[1],DEC); //显示十进制,湿度小数位
Serial.print('%');
Serial.print("Current Temperature = ");
Serial.print(dat[2],DEC);
Serial.print('.');
Serial.print(dat[3],DEC);
Serial.print('C');
delay(700);
}