一、接线
VCC接3.3V
DATA 接任意可配置输入输出的引脚(下文以P18为例)
二、流程
1、起始信号
配置为输出引脚,保持18ms低电平后拉高,再配置为输入引脚
2、 读取40bits数据
保持低电平50us后保持高电平。1位的高低由高电平保持时长决定(0则保持27us左右,1则保持70us左右)。
高位先接收。
数据接收结束,DHT11释放数据线,由上拉电阻保持高电平。
3、 校验和
只需将前4byte加起来
“8bit 湿度整数数据 + 8bit 湿度小数数据+8bit 温度整数数据 + 8bit 温度小数数据”8bit 校验位等于所 得结果的末 8 位。
4、 结果
由于DHT11温度测量范围在-20~+60℃,湿度为5~95%RH。需要判断温度为负的情况。
三、代码
#include <Arduino.h>
uint16_t time_outs;//时间计数存储器
unsigned char DHT11_buff[5];//5字节buff
uint8_t timesss[100];//每一状态值保持时长,用于测试
uint8_t timeindex;//时长数组的索引,用于测试
float Temperature, Humi;
void setup() {
// put your setup code here, to run once:
Serial.begin(115200);
delay(2000);//通电延迟,手册要求通电1S后才初始化完成
}
void delay_us(int uss)
{
delayMicroseconds(uss);//可直接用于下面代码
}
//holdpin需要检测的pin值
//waitstate 等该状态变化至另一状态
//timeouts 微秒次数,超过该次数则故障 返回0,否则返回等待时长
//timeout_code如果超时,打印的故障码
int wait_pin(int holdpin, int waitstate, uint16_t timeouts, int timeout_code)
{
time_outs = 0;
while(digitalRead(holdpin)==waitstate)//直到状态改变
{
time_outs++;
if(time_outs>timeouts)//超过timeouts了
{
Serial.printf("timeout %d\r\n",timeout_code);//打印故障码
return 0;//时间不能为0,以0为错误码返回
}
delay_us(10);//也可以写成1,请和timeouts配合使用。
}
timesss[timeindex++] = time_outs;//保存保持时长
return time_outs;
}
//读取一个byte
uint8_t get_dht11_byte()
{
uint8_t buf8=0x00;
uint8_t times_us;
for(uint8_t i=0;i<8;i++)
{
buf8<<=1;
times_us = wait_pin(18,0,6,-5);//50us,timeouts设为6,即不能超过60us
if(times_us == 0)
return 0xff;//byte不存在0xff的情况,作为错误码返回
times_us = wait_pin(18,1,10,-6);//70us,等高电平,不能超过100us
if(times_us == 0)
return 0xff;
if(times_us<4)
buf8+=0;
else
buf8+=1;
}
return buf8;
}
//测量的完整流程
void dht_()
{
uint8_t get_buff;//字节buff
uint8_t isNegative;
uint8_t checksum = 0;
//起始信号
pinMode(18,OUTPUT);
digitalWrite(18,HIGH);
digitalWrite(18,LOW);
delay(19);//19ms低
digitalWrite(18,HIGH);//上升沿
pinMode(18,INPUT);//输入,悬浮(电路已有上拉电阻)
delay_us(30);//设太长会超过低电平时间
if(digitalRead(18))//判断有没有被DHT11拉低
{
if(wait_pin(18,1,10,400) == 0)//等DHT11响应
{
Serial.printf("err 1\r\n");//线路不对
return;//超时退出
}
}
//起始信号 -_____----_ 80+80
if(wait_pin(18,0,20,-1) == 0)//拉低是否过长,80us
{
Serial.printf("err 2\r\n");//超时
return;//超时退出
}
if(digitalRead(18))
{
if(wait_pin(18,1,11,-2) == 0)//拉高是否过长,80us
{
Serial.printf("err 3\r\n");
return;//超时退出
}
//开始发送数据 1: ___---- 50+70 ; 0: ___-- 50+27
for(uint8_t i=0;i<5;i++)//5字节
{
get_buff = get_dht11_byte();
if(get_buff!=0xff)
DHT11_buff[i] = get_buff;
checksum +=get_buff;
}
Serial.printf("bytes:%d,%d,%d,%d,%d\n",DHT11_buff[0],DHT11_buff[1],
DHT11_buff[2],DHT11_buff[3],DHT11_buff[4]);
}
if(checksum == DHT11_buff[4])
{
isNegative = (( DHT11_buff[3] & 0x80 ) >> 7) ;//温度低字节的最高位为1时温度为负
if ( 1 == iIsNegative )
{
Temperature = - ( (float)DHT11_buff[2] + ( (float)(DHT11_buff[3] & 0x7F)*0.1) );
}
else
{
Temperature = (float)DHT11_buff[2] + (float)DHT11_buff[3]*0.1;
}
Humi = DHT11_buff[0];
}
}
void loop() {
// put your main code here, to run repeatedly:
timeindex =0;
dht_();
//打印各时段的时间
for(uint8_t i=0;i<timeindex;i++)
Serial.printf("%d :%d ,",i,timesss[i]);
delay(1000);
}
代码未涉及中断、定时器,请放心食用。
四、 实验结果
温度变化比较缓慢,湿度变化比较灵敏。