目录
一、产品概述
1、接线方式
2、特点
3、数据传送逻辑
二、发送时序检测模块是否存在
1、C51单片机(主机)时序分析
2、编写代码检测模块是否存在
3、读取DHT11数据的时序分析
三、温湿度通过串口传到PC显示
四、温湿度检测小系统——使数据显示在LCD1602液晶板上
DHT11温湿度传感器是一款含有已校准数字信号输出的温湿度复合传感器,应用领域:暖通空调、汽车、消费品、气象站、温度调节器、除湿器、家电、医疗、自动控制等
VCC:接供电的正极
GND:接地
DAT:接数据
相对湿度和温度的测量
全部校准、数字输出
长期稳定性
超长的信号传输距离:20米
4引脚安装:可以买封装好的
完全互换:直接出结果,不用转化
只有一根数据线DATA,上官一号发送序列指令给DHT11模块,模块一次完整的数据传输为40bit高位先出
40bit的数据格式
8bit湿度整数数据+8bit湿度小数数据+8bit温度整数数据+8bit温度小数数据+8bit校验合
对于主机来说:发送时序的开始在a点,结束在d点
a:dht=1;
b:dht=0;
b、c之间延时30ms;
c:dht=1;
开始读DHT模块有无信号,在40-100μs之间读,比如在60μs的时候读,如果在60μs的时候是低电平,说明模块存在
那怎么看模块是否有回应呢,请看上图中的de段,C51单片机发送完时序信号是处于高电平的状态,当DHT这边有信号过来时,会把信号从高电平状态拉到低电平状态,所以当de=0时,说明DHT模块有数据显示了
那对于单片机来说怎么获取到这个低电平状态呢,那就得去读取de段的数据了,读上面的引脚是否为低电平
从c点到e点共有两种情况:
第一种:cd之间的延时最短时间是20μs,de之间的延时时间是80μs,那么从c点到e点,所需要的延时时间就是20-100μs
第二种:cd之间的延时最长时间是40μs,de之间的延时时间是80μs,那么从c点到e点,所需要的延时时间就是40-120μs
综上述情况, 我们要读取它们重合的时间,才能把以上两点都包括在内,重合的时间是40-100μs
#include "reg52.h"
#include "intrins.h"
sbit dht = P3^3;
sbit ledOne = P3^7;
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 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 check_DHT(){
//a:dht=1;
dht = 1;
//b:dht=0;
dht = 0;
//b、c之间延时30ms;
Delay30ms();
//c:dht=1;
dht = 1;
//开始读DHT模块有无信号,在40-100μs之间读,比如在60μs的时候读,如果在60μs的时候是低电平,说明模块存在
Delay60us();
if(dht == 0){
ledOne = 0; //亮灯,说明DHT模块存在
}
}
void main()
{
ledOne = 1; //灭灯
Delay1000ms(); //上电后稳定DHT11的供电
Delay1000ms();
check_DHT(); //看模块是否存在
while(1); //一直循环,不让main退出
}
执行结果:
当单片机接温湿度传感器的时候,单片机的P3^7小灯就会亮,单片机不接温湿度传感器的时候,小灯就不亮
a:dht=1;
b:dht=0;
b、c之间延时30ms;
c:dht=1;
由于c点到d点之间有个20-40μs的延时时间,所以不太好找d点的位置,那么怎么找d点的位置呢
采用卡点的方法:
卡d点:while(dht);这时dht=1,当dht=1时,说明一直是高电平信号,当dht不等于1时,条件不满足时,说明信号从高电平下降到低电平了,也就是说找到d点了
卡e点:while(!dht); 这时dht=0,一直处于低电平状态,当dht不等于0时,条件不满足,说明信号从低电平上升到高电平了,也就是找到e点了
卡f点:while(dht);这时dht=1,当dht=1时,说明一直是高电平信号,当dht不等于1时,条件不满足时,说明信号从高电平下降到低电平了,也就是说找到f点了
卡g点:while(!dht); 这时dht=0,一直处于低电平状态,当dht不等于0时,条件不满足,说明信号从低电平上升到高电平了,也就是找到g点了
表示0时,高电平持续的时间是26-28μs
表示1时,高电平持续的时间是70μs
怎么读取DHT11传送的数据
从g点以后延时一段时间去读数据,比如延时50μs后,如果读到的信号是低电平,说明是数据是0,读到是信号是高电平,说明数据是1,然后读40bit,也是就是读40次,40次分5轮来读,每轮读8次(8bit=1个char)8次形成一个数据
数字0信号表示方法
1、环境准备:C51单片机连接DHT11温湿度传感器;VCC-5V、GND-GND、DAT-接/发数据引脚
2、编写代码
#include "reg52.h"
#include "intrins.h"
sbit dht = P3^3;
sbit ledOne = P3^7;
sfr AUXR = 0x8E;
char datas[5];
void UartInit(void) //[email protected]
{
AUXR = 0x01; //降低时钟对外界的辐射
SCON = 0x40; //串行口寄存器工作模式选择方式1,RNE=0,为串行禁止接收状态
TMOD &= 0x0F; //定时器1工作方式位8位自动重装
TMOD |= 0x20;
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 != '\0'){
sendByte(*str);
str++;
}
}
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 Delay30ms() //@11.0592MHz
{
unsigned char i, j;
i = 54;
j = 199;
do
{
while (--j);
} while (--i);
}
void DHT11_Start(){
dht = 1;
dht = 0;
Delay30ms();
dht = 1;
while(dht); //卡d点
while(!dht); //卡e点
while(dht); //卡f点
}
void Delay40us() //@11.0592MHz
{
unsigned char i;
_nop_();
i = 15;
while (--i);
}
void Read_Data_From_DHT(){
int i;
int j;
char tmp; //用来进行移位,用来获得最低位
char flag; //标志位
DHT11_Start();
for(i=0;i<5;i++){
for(j=0;j<8;j++){
while(!dht); //卡g点
Delay40us(); //延时40us
if(dht == 1){
flag = 1;
while(dht);
}else{
flag = 0;
}
tmp = tmp << 1;
tmp |= flag;
}
datas[i] = tmp;
}
}
void main()
{
ledOne = 1; //灭灯
UartInit(); //初始化一个串口
Delay1000ms(); //上电后稳定DHT11的供电
Delay1000ms();
while(1){
Delay1000ms();
Read_Data_From_DHT(); //获取DHT数据
sendString("H:"); //发送字符串
sendByte(datas[0]/10 + 0x30); //发送第1个bit字节,获取湿度的整数位
sendByte(datas[0]%10 + 0x30);
sendByte('.');
sendByte(datas[1]/10 + 0x30); //发送第2个bit字节,获取湿度的小数位
sendByte(datas[1]%10 + 0x30);
sendString("\r\n"); //自动换行
sendString("T:");
sendByte(datas[2]/10 + 0x30); //发送第3个bit字节,获取温度的整数位
sendByte(datas[2]%10 + 0x30);
sendByte('.');
sendByte(datas[3]/10 + 0x30); //发送第4个bit字节,获取温度的小数位
sendByte(datas[3]%10 + 0x30);
sendString("\r\n"); //自动换行
}
}
3、执行结果:
1、环境准备:C51单片机连接DHT11温湿度传感器和LCD1602液晶板
下面的链接里有C51单片机和LCD1602液晶板的连接方式
初识LCD1602及编程实现字符显示_Love小羽的博客-CSDN博客
2、编写代码
#include "reg52.h"
#include "intrins.h"
#define databuffer P0 //定义8位数据线,P0端口组
sbit dht = P3^3;
sbit ledOne = P3^7;
sfr AUXR = 0x8E;
sbit RS = P1^0;
sbit RW = P1^1;
sbit EN = P1^4;
sbit fengshan = P1^6; //继电器引脚
char datas[5];
char temp[8]; //定义一个温度类型
char huma[8]; //定义一个湿度类型
void check_busy(){
char tmp = 0x80;
databuffer = 0x80;
while(tmp & 0x80){
RS = 0;
RW = 1;
EN = 0;
_nop_();
EN = 1;
_nop_();
_nop_();
tmp = databuffer; //读取数据
_nop_();
EN = 0;
_nop_();
}
}
void Write_Cmd_Func(char cmd){
check_busy();
RS = 0; //指令寄存器,接收地址
RW = 0;
EN = 0;
_nop_();
databuffer = cmd; //发送指令
_nop_();
EN = 1;
_nop_();
_nop_();
EN = 0;
_nop_();
}
void Write_Data_Func(char dataShow){
check_busy();
RS = 1; //数据寄存器,接收内容
RW = 0;
EN = 0;
_nop_();
databuffer = dataShow; //发送数据
_nop_();
EN = 1;
_nop_();
_nop_();
EN = 0;
_nop_();
}
void Delay15ms() //@11.0592MHz
{
unsigned char i, j;
i = 27;
j = 226;
do
{
while (--j);
} while (--i);
}
void Delay5ms() //@11.0592MHz
{
unsigned char i, j;
i = 9;
j = 244;
do
{
while (--j);
} while (--i);
}
void UartInit(void) //[email protected]
{
AUXR = 0x01; //降低时钟对外界的辐射
SCON = 0x40; //串行口寄存器工作模式选择方式1,RNE=0,为串行禁止接收状态
TMOD &= 0x0F; //定时器1工作方式位8位自动重装
TMOD |= 0x20;
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 != '\0'){
sendByte(*str);
str++;
}
}
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 Delay30ms() //@11.0592MHz
{
unsigned char i, j;
i = 54;
j = 199;
do
{
while (--j);
} while (--i);
}
void DHT11_Start(){
dht = 1;
dht = 0;
Delay30ms();
dht = 1;
while(dht); //卡d点
while(!dht); //卡e点
while(dht); //卡f点
}
void Delay40us() //@11.0592MHz
{
unsigned char i;
_nop_();
i = 15;
while (--i);
}
void Read_Data_From_DHT(){
int i;
int j;
char tmp; //用来进行移位,用来获得最低位
char flag; //标志位
DHT11_Start();
for(i=0;i<5;i++){
for(j=0;j<8;j++){
while(!dht); //卡g点
Delay40us(); //延时40us
if(dht == 1){
flag = 1;
while(dht);
}else{
flag = 0;
}
tmp = tmp << 1;
tmp |= flag;
}
datas[i] = tmp;
}
}
void LCD1602_INIT(){
//(1)延时 15ms
Delay15ms();
//(2)写指令 38H(不检测忙信号)
Write_Cmd_Func(0x38);
//(3)延时 5ms
Delay5ms();
//(4)以后每次写指令,读/写数据操作均需要检测忙信号
check_busy();
//(5)写指令 38H:显示模式设置
Write_Cmd_Func(0x38);
//(6)写指令 08H:显示关闭
Write_Cmd_Func(0x08);
//(7)写指令 01H:显示清屏
Write_Cmd_Func(0x01);
//(8)写指令 06H:显示光标移动设置
Write_Cmd_Func(0x06);
//(9)写指令 0CH:显示开及光标设置
Write_Cmd_Func(0x0c);
}
void LCD1602_showLine(char row,char col,char *string){
switch(row){
case 1:
Write_Cmd_Func(0x80+col); //选择要显示的地址
while(*string){
Write_Data_Func(*string); //发送要显示内容
string++;
}
break;
case 2:
Write_Cmd_Func(0x80+0x40+col);
while(*string){
Write_Data_Func(*string);
string++;
}
break;
}
}
void Build_Datas(){
huma[0] = 'H'; //温度
huma[1] = datas[0]/10 + 0x30;
huma[2] = datas[0]%10 + 0x30;
huma[3] = '.';
huma[4] = datas[1]/10 + 0x30;
huma[5] = datas[1]%10 + 0x30;
huma[6] = '%';
huma[7] = '\0';
temp[0] = 'T'; //湿度
temp[1] = datas[2]/10 + 0x30;
temp[2] = datas[2]%10 + 0x30;
temp[3] = '.';
temp[4] = datas[3]/10 + 0x30;
temp[5] = datas[3]%10 + 0x30;
temp[6] = 'C';
temp[7] = '\0';
}
void main()
{
Delay1000ms();
UartInit(); //初始化一个串口
LCD1602_INIT(); //初始化LCD1602液晶显示
Delay1000ms(); //上电后稳定DHT11的供电
Delay1000ms();
ledOne = 0;
while(1){
Delay1000ms();
Read_Data_From_DHT(); //获取DHT数据
if(datas[2] > 29 ){
fengshan = 0;
}
Build_Datas();
sendString(huma); //发送湿度字符串
sendString("\r\n");
sendString(temp); //发送温度字符串
sendString("\r\n");
LCD1602_showLine(1,3,temp); //第一行显示湿度
LCD1602_showLine(2,3,huma); //第二行显示温度
}
}
执行结果: