DTH11使用
DTH11总线时序
DTH11与主机通信原理
主机和从机之间的通信可通过如下几个步骤完成(外设(如微处理器)读取DHT11的数据
步骤一:
DHT11上电后(DHT11上电后要等待1S以越过不稳定状态在此期间不能发送任何指令),测试环境温湿度数据,并记录数据,同时DHT11的DATA数据线由上拉电阻拉高一直保持高电平;此时DHT11的DATA引脚处于输入状态,时刻检测外部信号。
步骤二:
微处理器的I/O设置为输出同时输出低电平,且低电平保持时间不能小于18ms(最大不得超过30ms),然后微处理器的I/O设置为输入状态,由于上拉电阻,微处理器的I/O即DHT11的DATA数据线也随之变高,等待DHT11作出回答信号。
步骤三:
DHT11的DATA引脚检测到外部信号有低电平时,等待外部信号低电平结束,延迟后DHT11的DATA引脚处于输出状态,输出83微秒的低电平作为应答信号,紧接着输出87微秒的高电平通知外设准备接收数据,微处理器的I/O此时处于输入状态,检测到I/O有低电平(DHT11回应信号)
后,等待87微秒的高电平后的数据接收。
步骤四:
由DHT11的DATA引脚输出40位数据,微处理器根据I/O电平的变化接收40位数据,位数据“0”的格式为:54微秒的低电平和23-27微秒的高电平,位数据“1”的格式为:54微秒的低电平加68-74微秒的高电平。
DHT11编码步骤
一. 单片机上点后1s内不读取
二. 主机(单片机)发送起始信号:
1.主机先拉高data。
2.拉低data延迟18ms。
3.拉高data(通过此操作将单片机引脚设置为输入)。
三. 从机(DHT11)收到起始信号后进行应答:
从机拉低data,主机读取到data线被拉低持续80us后从机拉高data线, 持续80us,直到高电平结束,意味着主机可以开始接受数据。
四. 主机开始接收数据:
1.主机先把data线拉高(io设置为输入)。
2.从机把data线拉低,主机读取data线电平,直到低电平结束(大约50us)
从机拉高data线后,延迟40us左右(28~70us之间)主机再次读取data线电平,如果为低电平,则为“0”,如果为高电平,则为“1”。
3.继续重复上述1,2步骤累计40次。
五. data线拉低50us代表读取结束
主要问题
在通信时,会发生无法读取(即读取bit时 DTH11无法把信号拉低的问题),这时采取判断error并重新进行发送请求操作.
通信文件
/*
* dht11.c
*
*/
#include <stdio.h>
#include <wiringPi.h>
#include <time.h>
#include <stdlib.h>
#define DTH_sense 24
typedef unsigned char uchar;
int count=0;
typedef struct {
uchar HumInt;
uchar HumFloat;
uchar TemInt;
uchar TemFloat;
}DTH_DATA;
//初始化wiringPi
void wiringPiStart(void)
{
wiringPiSetup();
}
//初始化 开启DTH11
void DHT11_start()
{
pinMode(DTH_sense, OUTPUT);
digitalWrite(DTH_sense,0);
delayMicroseconds(2);
digitalWrite(DTH_sense,1); //发送一个高电平脉冲
delayMicroseconds(2);
digitalWrite(DTH_sense,0); //拉低延时
delay(20); //延时18ms以上
digitalWrite(DTH_sense,1);
delayMicroseconds(30); //主机拉高20~40us
pinMode(DTH_sense, INPUT);
}
//从DTH11接收一个字节
uchar DHT11_rec_byte()
{
uchar i,dat={0};
for(i=0;i<8;i++) //从高到低依次接收8位数据
{ //每个bit之前有50us低电平
while(digitalRead(DTH_sense)==0)
{++count;if(count>=65536){printf("error1\n");return -1;}}; count=0; //等待50us低电平过去
delayMicroseconds(30); //延时30us,如果还为高则数据为1,否则为0
dat<<=1; //移位使正确接收8位数据,数据为0时直接移位
if(digitalRead(DTH_sense)) //数据为1时,使dat加1来接收数据1
{dat+=1;}
while(digitalRead(DTH_sense)==1)
{++count;if(count>=100000){printf("error2\n");return -1;}};count=0; //等待数据线拉低
}
return dat;
}
//接收40位的数据
int DHT11_receive(DTH_DATA* data)
{
uchar H_H=0, H_L=0, T_H=0, T_L=0,revise=0;
DHT11_start();
while(digitalRead(DTH_sense)==1)
{++count;if(count>=65536){printf("error3\n");return 0;}};count=0;
while(digitalRead(DTH_sense)==0); //等待DTH拉高
{++count;if(count>=65536){printf("error4\n");return 0;}};count=0;
while(digitalRead(DTH_sense)==1); //拉高后延时80us,进入数据传输
{++count;if(count>=65536){printf("error5\n");return 0;}};count=0;
if( (H_H=DHT11_rec_byte())==-1) return 0; //接收湿度高八位
if( (H_L=DHT11_rec_byte())==-1) return 0; //接收湿度低八位
if( (T_H=DHT11_rec_byte())==-1) return 0; //接收温度高八位
if( (T_L=DHT11_rec_byte())==-1) return 0; //接收温度低八位
if( (revise=DHT11_rec_byte())==-1) return 0; //接收校正位
if((H_H+H_L+T_H+T_L)==revise) //校正
{
data->HumInt = H_H;
data->HumFloat = H_L;
data->TemInt = T_H;
data->TemFloat = T_L;
}
delayMicroseconds(25); //结束
return 1;
}
int main(int argc, char **argv)
{
DTH_DATA data={0,0};
time_t curtime;
wiringPiStart();
while(1){
delay(2000);
time(&curtime);
printf("当前时间: %s",ctime(&curtime));
if(!DHT11_receive(&data)) continue;
printf("HUM: %d.%d %% RH\n",data.HumInt,data.HumFloat);
printf("TEM: %d.%d ^C\n",data.TemInt,data.TemFloat);
}
return 0;
}
输出
当前时间: Wed Jul 7 20:02:37 2021
HUM: 51.0 % RH
TEM: 27.9 ^C
当前时间: Wed Jul 7 20:02:39 2021
HUM: 51.0 % RH
TEM: 27.9 ^C
当前时间: Wed Jul 7 20:02:41 2021
HUM: 51.0 % RH
TEM: 27.8 ^C