概述
目录
1.模块简介
2.判断DHT11模块是否存在
3.DHT11数据的时序分析
4.将温湿度数据上传到电脑中
1.模块简介
DHT11数字温湿度传感器是一款含有已校准数字信号输出的温湿度复合传感器,应用领域:暖通 空调;汽车;消费品;气象站;湿度调节器;除湿器;家电;医疗;自动控制
特点 :相对湿度和温度测量 全部校准,数字输出 长期稳定性 超长的信号传输距离:20米 超低能耗:休眠 4 引脚安装:可以买封装好的 完全互换 : 直接出结果,不用转化。
数据传送逻辑 :只有一根数据线DATA,单片机发送序列指令给DHT11模块,模块一次完整的数据传输为40bit,高位先出。
数据格式:8bit湿度整数数据+8bit湿度小数数据+8bi温度整数数据+8bit温度小数数据+8bit校验和。
2.判断DHT11模块是否存在
下图是手册给出的时序图,为了方便讲解我在手册上标注以下几个a,b,c,d,e点便于分析。
使用DHT11时,第一步单片机必须要根据图中所给的时序给DHT11发送一段信号,DHT11接收到单片机发来的信号后才可以进行后续的工作。图中的主机信号也就是单片机给出的信号,单片机在开始的时候需要在a点拉高,然后再b点拉低至少18ms(不放心的话也可以再拉长一点),在c点再变回高电平持续20-40us到了d点。单片机给dht11的初始化信号就发送完毕了。单片机发送完成后,dht11也会随之响应,由时序图可以看出dht11有一段80us的低电平,我们可以利用这一段低电平来检测dht11模块是否存在,也可以判断出来你的模块是否损坏,以免后续因为模块损坏的问题查找半天错误,得不偿失。
判断DHT11模块是否存在
因此我们可以在拿d点来进行判断,在c点拉高60us后我们检测d点是否为低电平,如果为低电平则dht11存在,反之则不存在。如果d点位低电平可以点亮开发板上的一个led便于我们观察。
在编程之前还需一点需要注意,dht11的手册上给出了这样一段话,为了避免上电初始状态不稳定,因此我们要在单片机上电的时候延时1s左右(我本人延时了3s,我自己在做实验的时候延时1s和2s都没有接收到的数据,延时3s后才接收的到,这个大家可以根据自己的实际情况调整,在没有接收到dht11的数据时可以考虑一下这个原因)。代码如下:
#include "reg52.h"
#include "intrins.h"
sbit LED_Check = P3^7;
sbit DHT = P3^3;
void Delay30ms() //@11.0592MHz
{
unsigned char i, j;
i = 54;
j = 199;
do
{
while (--j);
} while (--i);
}
void Delay60us() //@11.0592MHz
{
unsigned char i;
i = 25;
while (--i);
}
void Delay1000ms() //@11.0592MHz
{
unsigned char i, j, k;
_nop_();
i = 8;
j = 1;
k = 243;
do
{
do
{
while (--k);
} while (--j);
} while (--i);
}
void Check_DHT()
{
DHT = 1;
DHT = 0;
Delay30ms();
DHT = 1;
Delay60us();//在60s后读取DHT电平状态,如果是低电平则模块存在
if(DHT==0)
{
LED_Check=0;
}
}
void main()
{
LED_Check=1; //上电时先灭灯
Delay1000ms();
Delay1000ms();
Check_DHT();
while(1);
}
3.DHT11数据的时序分析
DHT11传输0的时序分析
DHT11传输1的时序分析
检测完模块存在之后,我们现在进行时序分析。从时序图可以看出在f点和g点之间的时候就已经开始传输数据了,那么我们现在就需要找到具体从哪里开始传输数据才可以进行后续的编程。在时序图中可以看出在c点之后有一段拉高20us-40us,我们给他拉高的30us,但还是无法得出程序会运行在时序图中具体的哪个电上。因此我们用“卡点法”进行分析。
卡d点:用while(dht1),如果是高电平就一直是死循环,当过了高电平那一段时程序才会继续往下执行,所以我们就找到了d点具体的位置。
卡e点:时序图中得出过80us后到达e点然后拉高,我们不需要关心80us这件事,只需要用
while(!dht1)就可以得出e点的位置。
卡f点:while(dht1)
卡g点:while(dht1)。g点之后必然是高电平,dht11的设计很奇怪,无论传输的是“0”还是“1”都是通过高电平进行传输,只不过是高电平的时间不同。
下图中蓝色部分是相同的时序段,由此可以看出在g点之后开始传输第一个“数据‘0’”.
紧接着g点,我们可以看出如果在g点之后26us-28us之间如果为高电平则表示0,在70us间如果为高电平则表示1。那么我们可以判断g点之后50us的状态,如果为低电平则表示0,为高电平则表示1。
代码如下:
void DHT11_Start()//DHT11初始化
{
DHT = 1;
DHT = 0;
Delay30ms();
DHT = 1;
while(DHT); //卡d点
while(!DHT); //卡e点
while(DHT); //卡f点
}
4.将温湿度数据上传到电脑中
分析完时序之后,我们可以开始编程。首先我们要获取DHT11的温湿度数据,手册中提到DHT11的数据构成是8bit湿度整数数据+8bit湿度小数数据+8bi温度整数数据+8bit温度小数数据+8bit校验和。大体来看就是读取5个字节的数据,如果我们按位来读取的话就是一共读五轮数据,每轮读八次,这样读下来正好是40位数据,接下来我们开始编程。
代码如下:
char datas[5];
/*
8bit湿度整数数据+8bit湿度小数数据
+8bi温度整数数据+8bit温度小数数据
*/
void Read_Data_From_DHT() //从dht11中获取温湿度数据
{
int i;//读五轮
int j;//每轮读八次
char flag; //定义一共标志位用来判断dht11发送的数据是“1”还是“0”
char tmp; //存放dht11的数据
DHT11_Start();
for(i=0;i<5;i++){
for(j=0;j<8;j++){
while(!DHT); //卡g点,等待dht11发送数据
Delay40us();
if(DHT==1){
flag = 1; //40us后如果读到的是高电平则位“1”,是低电平则为“0”
while(DHT);
}else{
flag = 0;
}
tmp = tmp<<1; //通过移位的操作把数据存放到tmp中
tmp |= flag;
}
datas[i] = tmp; //最后把40位数据存放到我们定义的数组中
}
}
接下来我们就把获取的温湿度数据通过串口上传。
通过串口上传我们需要注意一个很重要的事情,举个例子比如我们得到的温度是30,那么我们是不能直接将30上传到电脑中的,我们得到的30是十进制的30不是字符型的30,十进制的30的ASCLL码如下图,并不是我们想要的结果。因此我们需要先获取温度的十位数3,然后再获取各位,再获取小数后一位,在获取小数后两位,并且每次获取的时候都需要加上0x30转换成字符类型。
代码如下:
//串口发送相关代码
void UartInit(void) //9600bps@11.0592MHz
{
AUXR = 0x01;
SCON = 0x40; //配置串口工作方式1,REN不使能接收
TMOD &= 0xF0;
TMOD |= 0x20;//定时器1工作方式位8位自动重装
TH1 = 0xFD;
TL1 = 0xFD;//9600波特率的初值
TR1 = 1;//启动定时器
}
void SendByte(char data_msg)//发送字符
{
SBUF = data_msg;
while(!TI);
TI=0;
}
void SendString(char*str)//发送字符串
{
while(*str != '