基于51单片机的DHT11温湿度传感
DHT11温湿度传感器—用lcd1602显示出湿度、温度
下图为实际效果图:
为学习DHT11的童鞋提供思路和.c文件参考,希望能给大家一些帮助;觉得不错的话可以三连支持一下。
原理讲解
外设读取步骤(此段讲解可能有点问题,思路清晰的大佬,可以在评论区留言讨论)
主机和从机之间的通信可通过如下几个步骤完成(外设(如微处理器)读取DHT11的数据
步骤一:
DHT11上电后(DHT11上电后要等待1S以越过不稳定状态在此期间不能发送任何指令),测试环境温湿度数据,并记录数据,同时DHT11的DATA数据线由上拉电阻拉高一直保持高电平;此时DHT11的DATA引脚处于输入状态,时刻检测外部信号。
步骤二:
微处理器的I/O设置为输出同时输出低电平,且低电平保持时间不能小于18ms(最大不得超过30ms),然后微处理器的I/O设置为输入状态,由于上拉电阻,微处理器的I/O即DHT11的DATA数据线也随之变高,等待DHT11作出回答信号。
步骤三:
DHT11的DATA引脚检测到外部信号有低电平时,等待外部信号低电平结束,延迟后DHT11的DATA引脚处于输出状态,输出83微秒的低电平作为应答信号,紧接着输出80微秒的高电平通知外设准备接收数据,微处理器的I/O此时处于输入状态,检测到I/O有低电平(DHT11回应信号)
后,等待87微秒的高电平后的数据接收。
步骤四:
由DHT11的DATA引脚输出40位数据,微处理器根据I/O电平的变化接收40位数据,位数据“0”的格式为:54微秒的低电平和23-27微秒的高电平,位数据“1”的格式为:54微秒的低电平加68-74微秒的高电平。
程序编写思路
一. 单片机上点后1s内等待(可有可无)
二. 主机(单片机)发送起始信号:
1.主机先拉高data。
2.拉低data延迟18ms,等待信号的开始。
3.拉高data(通过此操作将单片机引脚设置为输入)。
三. 从机(DHT11)收到起始信号后进行应答:
从机拉低data,主机读取到data线被拉低持续80us后从机拉高data线, 持续80us,直到高电平结束,意味着主机可以开始接受数据。
四. 主机开始接收数据:
1.主机先把data线拉高(io设置为输入)。
2.从机把data线拉低,主机读取data线电平,直到低电平结束(大约50us)
从机拉高data线后,延迟60us左右(28~70us之间)主机再次读取data线电平,如果为低电平,则为“0”,如果为高电平,则为“1”。
3.延时80us左右,接受完所有数据。
五. data线拉低50us代表读取结束
源代码
main.c 主程序
/**
******************************************************************************
*@file main.c
*@author ImmortalZhou
*@date 2022.5.5
*@brief STC89C51 main.c文件
************************************************************************************
*@attention
*温度读取精度不够高,变换慢
*有些配置函数来源于CSDN
*************************************************************************************/
#include "reg52.h"
#include "LCD1602.h"
#include "intrins.h"
#include "stdio.h"
#include "usart.h"
//定义变量
sbit Data=P2^0;
unsigned char g_dht11_temperature=0;
unsigned char g_dht11_humidity=0;
unsigned char g_lcd1602_display1[16]="shid: % Temp: ";
unsigned char g_lcd1602_display2[16]=" ImmortalZhou ";
/*********************************************************************8****
*函数名:void DHT11_delay_us
*函数功能:us级别延时
*输入:n
*输出:无
**********************************************/
void DHT11_delay_us(unsigned char n)//延时不精准,延时时间大于1us
{
while(--n);
}
/*************************************************************************
*函数名:void DHT11_delay_ms
*函数功能:ms级别延时
*输入:z
*输出:无
**********************************************/
void DHT11_delay_ms(unsigned int z)
{
unsigned int i,j;
for(i=z;i>0;i--)
for(j=110;j>0;j--);
}
/************************************************************************************
*函数名:DHT11_start
*函数功能:DHT11开始信号
*输入:无
*输出:无
***********************************/
void DHT11_start(void)
{
Data=1;
DHT11_delay_us(2);
Data=0;
DHT11_delay_ms(20); //延时18ms以上
Data=1;
DHT11_delay_us(30);
}
/****************************************************************************************
*函数名:DHT11_rec_byte
*函数功能:接收8位二进制
*输入:无
*输出:dat
**********************************************/
unsigned char DHT11_rec_byte() //接收一个字节
{
unsigned char i,dat=0;
for(i=0;i<8;i++) //从高到低依次接收8位数据
{
while(!Data); //等待50us低电平过去
DHT11_delay_us(8); //延时60us,如果还为高则数据为1,否则为0
dat<<=1; //移位使正确接收8位数据,数据为0时直接移位
if(Data==1) //数据为1时,使dat加1来接收数据1
dat+=1;
while(Data); //等待数据线拉低
}
return dat;
}
/****一次传送40位数据,高位先出,校验数据*****/
/**************************************************************************************************
*函数名:DHT11_receive
*函数功能:接收40位的数据
*输入:无
*输出:无
**********************************************/
void DHT11_receive(void) //接收40位的数据
{
unsigned char R_H,R_L,T_H,T_L,revise;
DHT11_start();
if(Data==0)
{
while(Data==0); //等待拉高
DHT11_delay_us(60); //把总线拉高80us,准备发送数据
R_H=DHT11_rec_byte(); //接收湿度高八位
R_L=DHT11_rec_byte(); //接收湿度低八位
T_H=DHT11_rec_byte(); //接收温度高八位
T_L=DHT11_rec_byte(); //接收温度低八位
revise=DHT11_rec_byte(); //接收校正位
DHT11_delay_us(25); //拉低总线50us,随后总线由上拉电阻进入空闲状态
g_dht11_temperature=T_H;
g_dht11_humidity=R_H;
}
}
/**************************************************************************************
*函数名:LCD1602_Display
*函数功能:lcd显示字符
*输入:无
*输出:无
***************************/
void LCD1602_Display(void)
{
unsigned char i;
LcdWriteCom(0x80);
for(i=0;i<16;i++)
{
LcdWriteData(g_lcd1602_display1[i]);
}
LcdWriteCom(0x80+0x40);
for(i=0;i<16;i++)
{
LcdWriteData(g_lcd1602_display2[i]);
}
}
/***********************************************************************************
*函数名:main
*函数功能:主函数
*输入:无
*输出:无
***************************/
void main(void)
{
LcdInit();
// USART_Init();
while(1)
{
DHT11_receive();
g_lcd1602_display1[5]=g_dht11_humidity/10+'0';
g_lcd1602_display1[6]=g_dht11_humidity%10+'0';
g_lcd1602_display1[14]=g_dht11_temperature/10+'0';
g_lcd1602_display1[15]=g_dht11_temperature%10+'0';
// printf("g_dht11_humidity = %d g_dht11_temperature = %d \r\n", g_dht11_humidity, g_dht11_temperature);在串口中显示输出数据
LCD1602_Display();
DHT11_delay_ms(10);
}
}
lcd1602.c lcd配置
/**
******************************************************************************
*@file LCD1602.c
*@author ImmortalZhou
*@date 2022.5.5
*@brief lcd1602配置
************************************************************************************
*@attention
*
*************************************************************************************/
#include "LCD1602.h"
/***************************************************************************
*函数名:Lcd1602_Delay1ms
*函数功能:延时函数,延时1ms
*输入:x
*输出:无
**********************************/
void Lcd1602_Delay1ms(uint x) {
uchar i, j;
for (i = x; i > 0; i--)
for (j = 110; j > 0; j--);
}
/*************************************************************************************
*函数名:Lcd1602WriteCom
*函数功能:向LCD写入一个字节的命令
*输入:com
*输出:无
************************************/
#ifndef LCD1602_4PINS//当没有定义这个LCD1602_PINS时
void LcdWriteCom(uchar com) {
LCD1602_E = 0; //使能
LCD1602_RS = 0; //选择发送命令
LCD1602_RW = 0; //选择写入
LCD1602_DATAPINS = com; //放入命令
Lcd1602_Delay1ms(1);//保持时间,等待数据稳定
LCD1602_E = 1; //写入时序
Lcd1602_Delay1ms(5);//保持时间
LCD1602_E = 0;
}
#else
void LcdWriteCom(uchar com) { //写入命令
LCD1602_E = 0; //使能清零
LCD1602_RS = 0; //选择发送命令
LCD1602_RW = 0; //选择写入
LCD1602_DATAPINS = com; //由于4位的接线是接到P1口的高四位,所以传输高四位不用改
Lcd1602_Delay1ms(1);//保持时间
Lcd1602_E = 1; //写入时序
Lcd1602_Delay1ms(5);//保持时间
LCD1602_E = 0;
LCD1602_DATAPINS = com << 4; //发送低四位
Lcd1602_Delay1ms(1);
LCD1602_E = 1; //写入时序
Lcd1602_Delay1ms(5);
LCD1602_E = 0;
}
#endif
/***********************************************************************
*函数名:Lcd1602WriteData
*函数功能:向LCD写入一个字节的数据
*输入:dat
*输出:无
**************************/
#ifndef LCD1602_4PINS
void LcdWriteData(uchar dat) {
LCD1602_E = 0; //使能清零
LCD1602_RS = 1; //选择输入数据
LCD1602_RW = 0; //选择写入
LCD1602_DATAPINS = dat; //写入数据
Lcd1602_Delay1ms(1);
LCD1602_E = 1; //写入时序
Lcd1602_Delay1ms(5);//保持时间,稳定数据
LCD1602_E = 0;
}
#else
void LcdWriteData(uchar dat) {
LCD1602_E = 0; //使能清零
LCD1620_RS = 1; //选择输入数据
LCD1602_RW = 0; //选择写入
LCD1602_DATAPINS = dat; //由于4位的接线是接到P1口的高四位,所以传输高四位不用改
Lcd1602_Delay1ms(1);
LCD1602_E = 1; //写入时序
Lcd1602_Delay1ms(5);//保持时间,稳定数据
LCD1602_E = 0;
LCD1602_DATAPINS = dat << 4; //写入低四位
Lcd1602_Delay1ms(1);
LCD1602_E = 1; //写入时序
Lcd1602_Delay1ms(5);
LCD1602_E = 0;
}
#endif
/*********************************************************************************
*函数名:LcdInit
*函数功能:初始化lcd屏
*输入函数:无
*输出函数:无
**************************/
#ifndef LCD1602_4PINS
void LcdInit() { //LCD初始化子程序
LcdWriteCom(0x38);//开显示
LcdWriteCom(0x0c);//开显示不开光标
LcdWriteCom(0x06);//写一个指针加一
LcdWriteCom(0x01);//清屏
LcdWriteCom(0x80);//设置数据指针起点
}
#else
void LcdInit() {
LcdWriteCom(0x32);//将八位总线转为四位总线
LcdWriteCom(0x28);//在四位总线下的初始化
LcdWriteCom(0x0c);//开显示不开光标
LcdWriteCom(0x06);//写一个指针加一
LcdWriteCom(0x01);//清屏
LcdWriteCom(0x80);//设置数据指针起点
}
#endif
usart.c 串口配置
/**
******************************************************************************
*@file usart.c
*@author ImmortalZhou
*@date 2022.5.5
*@brief 串口
************************************************************************************
*@attention
*
*************************************************************************************/
#include "usart.h"
/****************************
*函数名:USART_Init
*函数功能:串口初始化 波特率9600
*输入:无
*输出:无
********************************/
void USART_Init(void)//使用定时器1作为串口波特率发生器
{
TH1 = 0xfd; //晶振11.0592mhz 波特率设为9600
TL1 = 0xfd;
TMOD |= 0x20; //定时器1方式2
SCON = 0x50; //设置为工作方式1,串口接收使能
ES = 1; //串口中断使能
TR1 = 1; //定时器1使能
TI = 1; //发送中断标记位,必须设置
EA = 1; //开总中断
}
/*****************************
*函数名:UsartRecive
*函数功能:通信中断服务函数
*输入:无
*输出:无
**********************************/
//void UsartRecive(void)interrupt 4
//{
// unsigned char recelveData;
// recelveData=SBUF;
// RI=0;//RI接收中断标志位,清零
// SBUF=recelveData;
// while(!TI);//发送中断标志位
// TI=0;
//}
/*********************************************************************************
*函数名:Delay_ms
*函数功能:延时
*输入:xms
*输出:无
***************************/
void Delay_ms(unsigned int xms)
{
unsigned int x, y;
for (x = 0;x < xms; x++)
{
for (y = 0; y < 112; y++);
}
}
/*****************************************************END OF FILE*********************************************************/