基于51单片机的温湿度显示到LCD1602

基于STC89C52单片机的DHT11实时显示温湿度到LCD1602

前言

这个项目是本人学习的一个记录,项目主要功能就是利用DHT11模块实时显示温度湿度到LCD1602上面,并且串口也可以实时收到温湿度数据。

模块介绍与使用

LCD1602模块

LCD1602(Liquid Crystal Display)是一种工业字符型液晶,能够同时显示 16×02 即 32 字符(16列两行
在这里插入图片描述
第 1 脚: VSS 为电源地VO
第 2 脚: VDD 接 5V 正电源
第 3 脚: VL (VO)为液晶显示器对比度调整端,接正电源时对比度最弱,接地时对比度最高,对比度
过高时会产生“鬼影”,使用时可以通过一个 10K 的电位器调整对比度。
第 4 脚:RS 为寄存器选择,高电平时选择数据寄存器、低电平时选择指令寄存器。
第 5 脚:R/W 为读写信号线,高电平时进行读操作,低电平时进行写操作。当 RS 和 R/W 共
同为低电平时可以写入指令或者显示地址,当 RS 为低电平 R/W 为高电平时可以读忙信号,
当 RS 为高电平 R/W 为低电平时可以写入数据。
第 6 脚:E 端为使能端,当 E 端由高电平跳变成低电平时,液晶模块执行命令。
第 7~14 脚:D0~D7 为 8 位双向数据线。
第 15 脚:背光源正极。
第 16 脚:背光源负极。
在这里插入图片描述
指令 1:清显示,指令码 01H,光标复位到地址 00H 位置。
指令 2:光标复位,光标返回到地址 00H。
指令 3:光标和显示模式设置。I/D:光标移动方向,高电平右移,低电平左移。实际上就是
控制从左到右写入还是从右至左的写入顺序。S:屏幕上所有文字是否左移或者右
移。高电平表示有效,低电平则无效。S=1 当写一个字符,整屏显示左移(ID=1)或
者右移(I/D=0),以得到光标不移动而屏幕移动的效果。S=0 当写一个字符,整屏显
示不移动。
指令 4:显示开关控制。D:控制整体显示的开与关,高电平表示开显示,低电平表示关显
示. C:控制光标的开与关,高电平表示有光标,低电平表示无光标. B:控制光
标是否闪烁,高电平闪烁,低电平不闪烁。
指令 5:光标或显示移位 S/C:高电平时移动显示的文字,低电平时移动光标。R/L:文字或
者光标移动方向,R 表示右移,L 表示左移。
指令 6:功能设置命令 DL:高电平时为 8 位总线,低电平时为 4 位总线。N:低电平时为单
行显示,高电平时双行显示。F:低电平时显示 5×8 的点阵字符,高电平时显示 5×10
的点阵字符。
指令 7:字符发生器 RAM 地址设置。
指令 8:DDRAM 地址设置。
指令 9:读忙信号和光标地址。BF:为忙标志位,高电平表示忙,此时模块不能接收命令或
者数据,如果为低电平表示不忙。
指令 10:写数据。
指令 11:读数据。

代码部分

在这里插入图片描述
RS为0或者1是选择写指令还是写数据,所以写指令函数与写数据函数区别就只有RS为不同
根据时序图RW在操作中为低电平,所以全程配置0,E在数据建立前先置0,然后等待一个数据建立时间(tsp2)和E说升沿时间(tr)后置1。

void Write_Cmd(char cmd)
{
check_busy();//检测忙信号
   RS=0;//写指令
   RW=0;
    E=0;
   _nop_();//延迟一个空函数时间,约为1.085us
   P0=cmd; //我这里D1~D7连接P0口,在E使能前写入指令
   _nop_();
   E=1;   
   _nop_();
   _nop_();//E脉冲宽度至少150us
   E=0;
   _nop_();
 
}
void Write_Data(char c_data)
{
check_busy();
   RS=1;//写数据
   RW=0;
   E=0;
   _nop_();
   P0=c_data;
   _nop_();
   E=1;
   _nop_();
   _nop_();
   E=0;
   _nop_();
   
}

在这里插入图片描述
在这里插入图片描述
检测忙信号,RS需要置0,RW需置1
然后根据D7位判断忙还是不忙
这里E先置0然后在tsp1时间后置1,E置1后才开始数据建立,与读操作是相反的

#include"reg52.h"
#include"intrins.h"
#include"Delay.h"

sbit RS=P1^0;
sbit E=P1^1;
sbit RW=P1^4;

void check_busy()//检测忙信号函数
{
char tmp=0x80;
     P0=0x80;
	while(tmp&0x80)//一开始就需要While成立,所以tmp与P0都为0x80
	{
	RS=0;
	RW=1;
	E=0;
	_nop_();
	E=1;
	_nop_();
	_nop_();
	tmp=P0;//检测D7位,一旦D7=0,则while不成立,表示不忙
	E=0;
	_nop_();
	}

}

根据LCD1602手册的初始化函数

void LCD1602_Init()
{
//(1)延时 15ms
     Delay(15);
//(2)写指令 38H(不检测忙信号)
     Write_Cmd(0x38);
//(3)延时 5ms
     Delay(5);
//(4)以后每次写指令,读/写数据操作均需要检测忙信号
//(5)写指令 38H:显示模式设置
	  Write_Cmd(0x38);
	  
//(6)写指令 08H:显示关闭
      Write_Cmd(0x08);
	  
//(7)写指令 01H:显示清屏
      Write_Cmd(0x01);
	  
//(8)写指令 06H:显示光标移动设置
      Write_Cmd(0x06);
	  
//(9)写指令 0CH:显示开及光标设置
      Write_Cmd(0x0C);
	  
}

显示字符串函数

void Write_show(char hang,char lie,char* c_str)
{
 
  char add;
  switch(hang)//选择1还是2行
  {
	   case 1 :add=0x00+0x80+lie; Write_Cmd(add);//1行地址为00+0x80+显示在第几列
	                                             //0x80是因为D7为在写入过程中恒为1
	                                             //1602不需要发送每一列的地址,模块会自动偏移
	   while(*c_str)//数据不为空一直循环
	   {
		Write_Data(*c_str);//写数据
		c_str++;//偏移
	   }
	   break;
	   case 2 :add=0x40+0x80+lie;Write_Cmd(add);//2行启示地址为0x40 
	   while(*c_str)
	   {	
		Write_Data(*c_str);
		c_str++;
	   }
	   break;
  }
}

LCD模块函数头文件

#ifndef __LCD1602__H_
#define __LCD1602__H_

void check_busy();
void Write_Cmd(char cmd);
void Write_Data(char c_data);
void LCD1602_Init();
void Write_show(char hang,char lie,char* c_str);

#endif

DHT11模块

在这里插入图片描述
总共三根线,VCC,GND和DATA
DATA 用于微处理器与 DHT11之间的通讯和同步,采用单总线数据格式,一次
通讯时间4ms左右,数据分小数部分和整数部分,具体格式在下面说明,当前小数
部分用于以后扩展,现读出为零.操作流程如下:
一次完整的数据传输为40bit,高位先出。
数据格式:8bit湿度整数数据+8bit湿度小数数据
+8bi温度整数数据+8bit温度小数数据
+8bit校验和
在这里插入图片描述
根据时序图配置主机发送信号函数

#include"reg52.h"
#include"intrins.h"
#include"Delay.h"
sbit DHT=P3^4;  /DATA线与此口连接
extern humidity;//外部声明,humidity为char 字符数组8位
extern Temp;//外部声明,temp为char 字符数组8位

void Dht11_Init()	//主机发送信号部分
{
  /*根据时序主机先给dht拉高 后拉低至少18ms这里给25ms
  然后拉高Dht 模块得到响应会拉低DHT信号等待DHT被拉低
  DHT信号会被拉低80us,等待DHT信号拉升,DHT信号会被拉高80us
  等待DHT信号被拉低,DHT信号拉低后,开始接收数据*/
 DHT=1; 
 DHT=0;
 Delay(25);
 DHT=1;
 while(DHT);
 while(!DHT);
 while(DHT);
}

在这里插入图片描述

void Getdata_Dht(char* str)
{
 char i;		//扫描几轮
 char j;	    //每轮多少次
 char flag;		//数据位0or1
 char tmp;		
 Dht11_Init();
 for(i=0;i<5;++i)
  {
	for(j=0;j<8;++j)
	{
	 while(!DHT);  //等待拉高
	 Delay40us();  //DHT信号26~28us为高电平则为0,70us为高电平则为1	
	               //40us后若依然是1则发过来是高电平反之低电平
	 if(DHT==1)
	 {
	  flag=1;
	  while(DHT);  //等待剩下30us
	 }else{
	  flag=0;
	 }
	 tmp<<=1;	   //循环8次,每次左移1位,并且与1bit,则能提取模块发过来的40bit
	 tmp|=flag;
	}
	*str++=tmp;
	tmp=0x00;
  }
}

DHT函数头文件函数

#ifndef __LCD1602__H_
#define __LCD1602__H_

void check_busy();
void Write_Cmd(char cmd);
void Write_Data(char c_data);
void LCD1602_Init();
void Write_show(char hang,char lie,char* c_str);

#end

串口函数

#include"reg52.h"
sfr AUXR=0x8e;
void UartInit(void)		//9600bps@11.0592MHz
{
	PCON &= 0x7F;		//波特率不倍速
	SCON = 0x50;		//8位数据,可变波特率
	AUXR &= 0xBF;		//定时器时钟12T模式
	AUXR &= 0xFE;		//串口1选择定时器1为波特率发生器
	TMOD &= 0x0F;		//设置定时器模式
	TMOD |= 0x20;		//设置定时器模式
	TL1 = 0xFD;			//设置定时初始值
	TH1 = 0xFD;			//设置定时重载值
	ET1 = 0;			//禁止定时器中断
	TR1 = 1;			//定时器1开始计时
	EA=1;//开启总中断
	ES=1;//开启串口中断
}

 void sendByte(char c_data)
 {
   SBUF=c_data;
   while(!TI);
   TI=0;
 }

 void sendString(char* str)
 {
 while(*str!='\0'){
   sendByte(*str);
   str++;
 	}
 }

头文件

#ifndef    __UART__H_
#define	   __UART__H_
void UartInit(void);
void sendByte(char c_data);
void sendString(char* str);
#endif

延迟函数代码

#include"reg52.h"
#include"intrins.h"
 void Delay(int sj)		//@11.0592MHz
{
	unsigned char i, j;

	while(sj--)
	{
	_nop_();
	i = 2;
	j = 199;
	do
	{
		while (--j);
	} while (--i);
	}
}
void Delay40us()		//@11.0592MHz
{
	unsigned char data i;

	_nop_();
	i = 15;
	while (--i);
}

延迟函数头文件

#ifndef   __DELAY__H_
#define	  __DELAY__H_


void Delay(int sj);
void Delay40us();

#endif

主函数代码

#include"reg52.h"
#include"Delay.h"
#include"intrins.h"
#include"Dht11.h"
#include"Uart.h"
#include"LCD1602.h"
sbit DHT=P3^4;	 //dht11模块data总线
sbit D5=P3^7;	 //led2
char str[5];
char c_str[12];
char humidity[8];
char Temp[8];

void T_H_data()	 //将DHT传来的数据调整
{
  Getdata_Dht(str);
  humidity[0]= 'H';
  humidity[1]= str[0]/10+0x30;	 //除法取整数,取余取小数,+0x30变为ASCII码的数字
  humidity[2]= str[0]%10+0x30;	 //湿度整数部分
  humidity[3]= '.';
  humidity[4]= str[1]/10+0x30;
  humidity[5]= str[1]%10+0x30;	 //湿度小数部分
  humidity[6]= '%';
  humidity[7]= '\0';
  Temp[0]= 'T';
  Temp[1]= str[2]/10+0x30;		 //温度
  Temp[2]= str[2]%10+0x30;
  Temp[3]= 	'.';
  Temp[4]= str[3]/10+0x30;
  Temp[5]= str[3]%10+0x30;
  Temp[6]= 'C';
  Temp[7]= '\0';
}

void main()
{
  D5=1;
  Delay(2000);//模块上电到稳定需要至少1s这里给2s
  UartInit();
  Dht11_Init();
  LCD1602_Init();
  while(1)
  {
  T_H_data();
  sendString(humidity);
  sendString("\r\n");
  sendString(Temp);			 //串口发送温度湿度
  sendString("\r\n");
  Write_show(1,3,humidity);	//LCD显示湿度
  Write_show(2,3,Temp);		// LCD显示温度
  Delay(2000);
  }
}
void UART_interrupt() interrupt 4
 {
 static char i;	  //静态变量,被初始化一次
 if(RI)			  //这里中断函数未做处理
 {
        RI=0;
	    c_str[i]=SBUF;
	   	i++;
		if(i==12)
		{
		i=0;
		}
	    
 }
  if(TI);
 }

根据这些函数就可以实现实时检测温湿度的功能了。

  • 2
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
从头开始设计一个基于51单片机温湿度报警器的lcd1602液晶仿真控制系统,需要以下全套资料: 1.硬件设计资料: - 51单片机选型和Datasheet:选择适合的51单片机型号,并收集该型号的Datasheet,以查看引脚定义和使用说明。 - 温湿度传感器选型和Datasheet:选择适合的温湿度传感器以测量温度和湿度,并收集传感器的Datasheet,了解工作原理和使用方法。 - LCD1602液晶屏选型和Datasheet:选择适合的LCD1602液晶屏,并收集液晶屏的Datasheet,以了解液晶屏的接口定义和使用方法。 - 报警器设计和Datasheet:设计报警器电路,用于报警显示。 - 电路图和PCB设计:绘制硬件电路图,并设计Printed Circuit Board(PCB)。 2.软件设计资料: - Keil C编译器:下载和安装Keil C编译器,用于编写和调试单片机程序。 - 汇编语言和C语言参考手册:学习51单片机的汇编语言和C语言编程,以编写程序。 - 温湿度传感器驱动程序:编写温湿度传感器的驱动程序,以读取传感器数据。 - LCD1602液晶屏驱动程序:编写LCD1602液晶屏的驱动程序,以显示温湿度数据和报警信息。 - 报警器控制程序:编写报警器的控制程序,以触发报警操作。 - 系统整合程序:将以上所有程序整合到一个单片机程序中,实现完整的温湿度报警器功能。 3.测试和调试资料: - 电源电压和电流要求:记录温湿度报警器系统的电源需求,包括电压和电流。 - 仿真软件和工具:选择合适的仿真软件和工具,用于测试和调试单片机程序。 以上是设计一个基于51单片机温湿度报警器lcd1602液晶仿真控制系统时所需的全套资料。这些资料将帮助你完成硬件设计、软件设计、测试和调试,最终实现一个功能完备的温湿度报警器系统。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值