51单片机 + DHT11温湿度 + LCD1602显示
DHT11温湿度相关介绍
DHT11产品概述
DHT11数字温湿度传感器是一款含有已校准数字信号输出的温湿度复合传 感器。它应用专用的数字模块采集技术和温湿度传感技术,确保产品具有极高 的可靠性与卓越的长期稳定性。传感器包括一个电阻式感湿元件和一个NTC测 温元件,并与一个高性能8位单片机相连接。因此该产品具有品质卓越、超快 响应、抗干扰能力强、性价比极高等优点。每个DHT11传感器都在极为精确的 湿度校验室中进行校准。校准系数以程序的形式储存在OTP内存中,传感器内 部在检测信号的处理过程中要调用这些校准系数。单线制串行接口,使系统集 成变得简易快捷。超小的体积、极低的功耗,信号传输距离可达20米以上,使 其成为各类应用甚至最为苛刻的应用场合的最佳选则。产品为 4 针单排引脚 封装。连接方便,特殊封装形式可根据用户需求而提供。
测量范围
型号 | 测量范围 | 测湿精度 | 测温精度 | 分辨力 | 封装 |
---|---|---|---|---|---|
DHT11 | 20-90%RH 0-50℃ | ±5%RH | ±2℃ | 1 | 4 针单排直插 |
接口说明
建议连接线长度短于20米时用5K上拉电阻,大于20米时根据实际情况使 用合适的上拉电阻
电源引脚
DHT11的供电电压为 3-5.5V。传感器上电后,要等待 1s 以越过不稳定状态在此 期间无需发送任何指令。电源引脚(VDD,GND)之间可增加一个100nF 的电容,用以去 耦滤波。
串行接口 (单线双向)
DATA 用于微处理器与 DHT11之间的通讯和同步,采用单总线数据格式,一次 通讯时间4ms左右,数据分小数部分和整数部分,具体格式在下面说明,当前小数 部分用于以后扩展,现读出为零。操作流程如下:一次完整的数据传输为40bit,高位先出。
数据格式:8bit湿度整数数据+8bit湿度小数数据+8bi温度整数数据+8bit温度小数数据+8bit校验和 数据传送正确时校验和数据等于8bit湿度整数数据+8bit湿度小数数据+8bit温度整数数据+8bit温度小数数据”所得结果的末8位。
相关时序及代码
用户MCU发送一次开始信号后,DHT11从低功耗模式转换到高速模式,等待主机开始信号结束后,DHT11发送响应信号,送出40bit的数据,并触发一次信号采集,用户可选择读取部分数据从模式下,DHT11接收到开始信号触发一次温湿度采集,如果没有接收到主机发送开始信号,DHT11不会主动进行温湿度采集,采集数据后转换到低速模式。
总线空闲状态为高电平,主机把总线拉低等待DHT11响应,主机把总线拉低必须大于18毫秒,保证DHT11能检测到起始信号。DHT11接收到主机的开始信号后,等待主机开始信号结束,然后发送80us低电平响应信号主机发送开始信号结束后,延时等待20-40us后,读取DHT11的响应信号,主机发送开始信号后,可以切换到输入模式,或者输出高电平均可,总线由上拉电阻拉高。
用代码实现上述时序图(起始信号):
DHT11_Data = 1; //先高电平维持一小段时间
Delay30us();//维持30us
DHT11_Data = 0; //拉低电平至少18ms
Delay20ms(); //这里给了20ms
DHT11_Data = 1; //拉高电平维持20-40us
Delay30us(); //我这里维持30us
DHT11_Data=1; //拉高电平等待DHT低电平响应
if(DHT11_Data == 0) //判断DHT是否响应
{
while(!DHT11_Data); //等待DHT80us低电平响应信号过去
while(DHT11_Data); //等待DHT80us高电平信号过去
/*然后就开始接收DHT11温湿度数据*/
}
总线为低电平,说明DHT11发送响应信号,DHT11发送响应信号后,再把总线拉高80us,准备发送数据,每一bit数据都以50us低电平时隙开始,高电平的长短决定了数据位是0还是1。格式见下面图示。如果读取响应信号为高电平,则DHT11没有响应,请检查线路是否连接正常。当最后 1bit 数据传送完毕后,DHT11拉低总线 50us,随后总线由上拉电阻拉高进入空闲状态。
总共数据为40位 8位的湿度整数部分,8位的湿度小数部分,8位的温度整数部分,8位的温度小数部分。8位的校验位(检测是否接收的是正确数据)
下面代码是获取每8位的代码
unsigned char DHT11_Rec_Byte()
{
unsigned char i = 0;
unsigned char Data;
for(i=0;i<8;i++)
{
while(!DHT11_data); //等待DHT11 50us低电平过去,
Delay30us(); 延时大概30us 如何还是高电平 则为1
Data<<=1; //左移一位 因为数据是从高位开始传
if(DHT11_data==1)
{
Data+=1;
}
while(DHT11_data); //等待DHT拉低 准备下一位开始
}
return Data;
}
接收每位的代码
void DHT11_Receive()
{
unsigned int R_H,R_L,T_H,T_L;
unsigned char RH,RL,TH,TL,CHECK;
DHT11_Start(); //主机发送信号
DHT11_data = 1; //拉高电平
if(DHT11_data==0) //判断DHT是否进入响应
{
while(DHT11_data==0); //等待从机80us低电平响应信号过去
while(DHT11_data==1); //等待从机80us高电平信号过去
R_H = DHT11_Rec_Byte(); //湿度整数部分
R_L = DHT11_Rec_Byte(); //湿度小数部分
T_H = DHT11_Rec_Byte(); //温度整数部分
T_L = DHT11_Rec_Byte(); //温度小数部分
CHECK = DHT11_Rec_Byte(); //校验位
DHT11_data=0; //当最后一bit数据传送完毕后,DHT11拉低总线 50us
Delay55us(); //这里延时55us
DHT11_data=1; //随后总线由上拉电阻拉高进入空闲状态。
if((R_H+R_L+T_H+T_L) == CHECK) //校验接收到的数据是否正确
{
RH = R_H;
RL = R_L;
TH = T_H;
TL = T_L;
}
}
rec_data[0] = RH;
rec_data[1] = RL;
rec_data[2] = TH;
rec_data[3] = TL;
}
代码整合
DHT11.c
#include <REGX52.H>
#include "DHT11.h"
#include "delay.h"
sbit DHT11_data = P3^6;
unsigned int rec_data[4];
unsigned char rec_data_lcd0[6];
unsigned char rec_data_lcd1[6];
unsigned char rec_data_lcd2[6];
unsigned char rec_data_lcd3[6];
/*
void DHT11_delay_us(unsigned char n)
{
while(--n);
}
void DHT11_delay_ms(unsigned int z)
{
unsigned int i,j;
for(i=z;i>0;i++)
for(j=110;j>0;j--);
}
*/
void DHT11_UART_Init()
{
SCON = 0x40;
REN = 1;
TMOD = 0x20;
TH1 = 0xF3;
TL1 = 0xF3;
TI = 1;
TR1 = 1;
}
void DHT11_Start()
{
DHT11_data = 1;
Delay30us();
DHT11_data = 0;
Delay20ms();
DHT11_data = 1;
Delay30us();
}
unsigned char DHT11_Rec_Byte()
{
unsigned char i = 0;
unsigned char Data;
for(i=0;i<8;i++)
{
while(!DHT11_data);
Delay30us();
Data<<=1;
if(DHT11_data==1)
{
Data+=1;
}
while(DHT11_data);
}
return Data;
}
void DHT11_Receive()
{
unsigned int R_H,R_L,T_H,T_L;
unsigned char RH,RL,TH,TL,CHECK;
DHT11_Start();
DHT11_data = 1;
if(DHT11_data==0)
{
while(DHT11_data==0); //等待从机80us低电平响应信号过去
while(DHT11_data==1);
R_H = DHT11_Rec_Byte();
R_L = DHT11_Rec_Byte();
T_H = DHT11_Rec_Byte();
T_L = DHT11_Rec_Byte();
CHECK = DHT11_Rec_Byte();
DHT11_data=0;
Delay55us();
DHT11_data=1;
if((R_H+R_L+T_H+T_L) == CHECK)
{
RH = R_H;
RL = R_L;
TH = T_H;
TL = T_L;
}
}
rec_data[0] = RH;
rec_data[1] = RL;
rec_data[2] = TH;
rec_data[3] = TL;
}
DHT11.h
#ifndef _DHT11_h_
#define _DHT11_h_
void DHT11_delay_us(unsigned char n);
void DHT11_delay_ms(unsigned int z);
void DHT11_UART_Init(void);
void DHT11_Start(void);
unsigned char DHT11_Rec_Byte(void);
void DHT11_Receive(void);
#endif
LCD1602.c
在51分栏第3篇中可以找到 3. 51——LCD1602显示 字符、字符串、数字
LCD1602.h
在51分栏第3篇中可以找到 3. 51——LCD1602显示 字符、字符串、数字
main.c
#include "regx52.h"
#include "intrins.h"
#include "LCD1602.h"
#include "DHT11.h"
#include <stdio.h>
extern unsigned int rec_data[4];
extern unsigned char rec_data_lcd0[6];
extern unsigned char rec_data_lcd1[6];
extern unsigned char rec_data_lcd2[6];
extern unsigned char rec_data_lcd3[6];
void Delay500ms() //@11.0592MHz
{
unsigned char i, j, k;
_nop_();
i = 4;
j = 129;
k = 119;
do
{
do
{
while (--k);
} while (--j);
} while (--i);
}
void main()
{
DHT11_UART_Init();
LCD_Init();
LCD_ShowString(1,1,"Humi:");
LCD_ShowString(2,1,"Temp:");
while(1)
{
Delay1000ms();;
DHT11_Receive();
sprintf(rec_data_lcd0,"%d",rec_data[0]);
sprintf(rec_data_lcd1,"%d",rec_data[1]);
sprintf(rec_data_lcd2,"%d",rec_data[2]);
sprintf(rec_data_lcd3,"%d",rec_data[3]);
Delay100ms();
LCD_ShowString(1,6,rec_data_lcd0);
LCD_ShowString(1,8,".");
LCD_ShowString(1,9,rec_data_lcd1);
LCD_ShowString(1,15,"%");
LCD_ShowString(2,6,rec_data_lcd2);
LCD_ShowString(2,8,".");
LCD_ShowString(2,9,rec_data_lcd3);
LCD_ShowString(2,15,"C");
// printf("Humi:%d.%d \n",rec_data[0],rec_data[1]); //通过串口
// printf("Temp:%d.%d °C\n",rec_data[2],rec_data[3]);
}
}
效果展示
由于经费不足,没钱买可变电阻接V0,只能从特殊角度观察到!哈哈哈,不好意思!
如果觉得这篇文章对你有用。欢迎大家点赞、评论哈哈哈!!!
需要整个工程代码,欢迎大家打赏,评论区留上你的邮箱 or vx or qq。o( ̄︶ ̄)o