基于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*********************************************************/	

物联沃分享整理
物联沃-IOTWORD物联网 » 基于51单片机的DHT11温湿度传感

发表评论