本程序由主函数main,和DHT11.c和DHT.h,这三个文件组成。关于DHT11的函数全部定义在.C文件中。.h文件为函数声明。LCD1602和DELAY的头文件在此就不展示了(太常见啦)
1.主函数
#include <REGX52.H>
#include "DHT11.H"
#include "LCD1602.H"
unsigned char Humidity_H,Humidity_L,Temprature_H,Temprature_L,check;
void main()
{
LCD_Init();
DHT11_Init(); //该初始化只是一个延时1秒的函数,DHT11在开始一秒为不稳定状态,此间不能通信
LCD_ShowString(1,1,"Humidity:");//湿度显示
LCD_ShowString(2,1,"Temprature:");//温度显示
LCD_ShowString(1,12,"%");//湿度后要追加显示百分号
LCD_ShowString(2,14,".");//显示温度的小数点
while(1)
{
DHT11_start();
Humidity_H=DHT11_receiveByte();
Humidity_L=DHT11_receiveByte();//此版本的DHT11,湿度小数部分始终为0,以下不予以显示
Temprature_H=DHT11_receiveByte();
Temprature_L=DHT11_receiveByte();
check=DHT11_receiveByte();
LCD_ShowNum(1,10,Humidity_H,2);
LCD_ShowNum(2,12,Temprature_H,2);
LCD_ShowNum(2,15,Temprature_L,1);
LCD_ShowNum(1,14,check,3); //check 为校验位,其值为前四个数据之和
}
}
敲重点啦!!! 以下为结合时序图的代码分析
步骤一:
微处理器的I/O设置为输出同时输出低电平,且低电平保持时间不能小于18ms(最大不得
超过30ms),然后微处理器的I/O设置为输入状态,由于上拉电阻,微处理器的I/O即DHT11的
DATA数据线也随之变高,等待DHT11作出回答信号。
DHT11_DATA=1; //其实可以省略,但保险起见,还是加一下吧
DHT11_DATA=0;
Delay(20); //主机需要拉低总线18毫秒以上
DHT11_DATA=1;
步骤二:
DHT11的DATA引脚检测到外部信号有低电平时,等待外部信号低电平结束,延迟后DHT11的
DATA引脚处于输出状态,输出83微秒的低电平作为应答信号,紧接着输出87微秒的高电平通知
外设准备接收数据,微处理器的I/O此时处于输入状态,检测到I/O有低电平(DHT11回应信号)
后,等待87微秒的高电平后的数据接收。
while(DHT11_DATA); //此循环为了等待来自DHT11的拉低信号
while(!DHT11_DATA); //此循环为了度过上一个拉低信号,并等待来自DHT11的拉高信号
while(DHT11_DATA); //此循环为了度过上一个拉高信号,并等待来自DHT11的数据信号(因为开始发送数据都是先拉低的)
本人一开始看见了时序图上面有好多具体的时间,就想着要用延时函数,(呜~呜~呜~当时好蠢)但是这样有一个问题,因为时序每次的时间肯定都会有些许的误差,整个系统在运作的情况下,随着时间的延长,误差肯定会有所积累,所以用while就可以很好的解决这个问题,并且使得程序更加简洁。
步骤三:
由DHT11的DATA引脚输出40位数据,微处理器根据I/O电平的变化接收40位数据,位数据
“0”的格式为:54微秒的低电平和23-27微秒的高电平,位数据“1”的格式为:54微秒的低
电平加68-74微秒的高电平。
while(!DHT11_DATA); //等待来自DHT11的拉高信号
i = 22;while (--i); //延时50微秒,只要延时在合理的区间使得可以区分0和1就行
if(DHT11_DATA==1)
{
Bit=DHT11_DATA;
while(DHT11_DATA);//等待高电平的结束
}
else
Bit=DHT11_DATA;
完整程序详见下面
2.DHT.c文件
#include <REGX52.H>
#include "DELAY.H"
sbit DHT11_DATA=P3^7;//DHT11通信端口定义
void DHT11_Init(void)
{
Delay(1000);
}
void DHT11_start(void)
{
DHT11_DATA=1;
DHT11_DATA=0;
Delay(20);
DHT11_DATA=1;
while(DHT11_DATA);
while(!DHT11_DATA);
while(DHT11_DATA);
}
bit DHT11_receiveBit(void) //此为接受bit位的函数,只被下面的接受字节函数调用
{
bit Bit;
unsigned char i;
while(!DHT11_DATA);
i = 22;while (--i);
if(DHT11_DATA==1)
{
Bit=DHT11_DATA;
while(DHT11_DATA);
}
else
{
Bit=DHT11_DATA;
}
return Bit;
}
unsigned char DHT11_receiveByte(void)
{
unsigned char Byte=0x00,i;
for(i=0;i<8;i++)
{
if(DHT11_receiveBit())
Byte|=(0x80>>i); //DHT11先给高位,所以要右移
}
return Byte;
}
3.DHT.h文件
#ifndef __DHT11_H__
#define __DHT11_H__
void DHT11_Init(void);
void DHT11_start(void);
unsigned char DHT11_receiveByte(void);
#endif
以上为头文件声明,一共有三个函数:初始化(延时),开始函数,接收字节函数。可为外部调用。
注意事项!!!由于DHT11每次都一定会返回40bit(5字节)的数据,所以在主函数中如果不想要显示某一项数据,也要考虑那一段时间(可以使用一个延时函数,时间由省略的字节数量决定)
还有,看懂数据手册,啥芯片都不怕(~_~)(藐视一切)!!!