使用LCD1602显示温度或切换显示时间

项目名称:测温过温报警系统及时钟系统

    此系统主要由AT89C51、DS18B20温度模块LCD1602喇叭组成大致的原理是DS18B20温度采集到的数据传送给AT89C51的P3.4,最后通过LCD1602显示当前的实时温度根据中断按键判断显示时间还是温度。

复习使用

(1) DS18B20简介

1.传感器参数

(1)测温范围为-55℃到+125℃,在-10℃到+85℃范围内误差为±0.4°。

(2)返回16位二进制温度数值。

(3)主机和从机通信使用单总线,即使用单线进行数据的发送和接收。

(4)在使用中不需要任何外围元件,独立芯片即可完成工作。

(5)掉电保护功能 DS18B20 内部含有 EEPROM ,通过配置寄存器可以设定数字转换精度和报警温度,在系统掉电以后,它仍可保存分辨率及报警温度的设定值。

(6)每个DS18B20都有独立唯一的64位-ID,此特性决定了它可以将任意多的DS18b20挂载到一根总线上,通过ROM搜索读取相应DS18B20的温度值。

(7)宽电压供电,电压2.5V~5.5V

2.DS18B20内部结构:

主要由4部分组成:64 位ROM、温度传感器、非挥发的温度报警触发器TH和TL、配置寄存器。ROM中的64位序列号是出厂前被光刻好的,它可以看作是该DS18B20的地址序列码,每个DS18B20的64位序列号均不相同。64位ROM的排的循环冗余校验码(CRC=X^8+X^5+X^4+1)。 ROM的作用是使每一个DS18B20都各不相同,这样就可以实现一根总线上挂接多个DS18B20的目的。

3.DS18B20内部构成:

高速暂存存储器由9个字节组成,当温度转换命令发布后,经转换所得的温度值以二字节补码形式存放在高速暂存存储器的第0和第1个字节。单片机可通过单线接口读到该数据,读取时低位在前,高位在后,对应的温度计算:当符号位S=0时,直接将二进制位转换为十进制;当S=1时,先将补码变为原码,再计算十进制值。

4.DS18B20 单线通信:

DS18B20 单线通信功能是分时完成的,他有严格的时隙概念,如果出现序列混乱, 1-WIRE 器件将不响应主机,因此读写时序很重要。系统对 DS18B20 的各种操作必须按协议进行。

  1. LCD1602简介

    1.引脚功能:

·引脚1:VSS为地电源。

·引脚2:VDD接5V正电源。

·引脚3:VL为液晶显示器对比度调整端,接正电源时对比度最弱,接地时对比度最高,对比度过高时会产生“鬼影”现象,使用时可以通过一个10kQ的电位器调整其对比度。

·引脚4:RS为寄存器选择脚,高电平时选择数据寄存器、低电平时选择指令寄存器

·引脚5:R/W为读/写信号线,高电平时进行读操作,低电平时进行写操作。当RS和R/W共同为低电平时可以写入指令或显示地址;当RS为低电平,R/W为高电平时,可以读忙信号;当RS为高电平,R/W为低电平时,可以写入数据。

·引脚6:E端为使能端,当E端由高电平跳变为低电平时,液晶模块执行命令。

·引脚7~14:D0~D7为8位双向数据线。

·引脚15:背光源正极。

·引脚16:背光源负极。

2.LCD1602的基本操作

①读状态:RS=0,RW=1,E=高脉冲。输出:D0~D7为状态字。

②读数据:RS=1,RW=1,E=高脉冲。输出:D0~D7为数据。

③写指令:RS=0,RW=0,E=高脉冲。输出:无

④写数据:RS=1,RW=0,E=高脉冲。输出:无。

  3、指令说明

显示模式设置


显示开/关光标设置

    此次实践中主要查询的是这两个元件,通过了解其原理与工作方式,实现所需功能。其次是查询中断及定时器使用,不在赘述。

   

  1. 功能简介

   本系统基本功能为测温过温警报及时间显示,按键P1.0、P1.1控制设定温度的加减,P1.2控制是否报警。按键P3.3按下为进入中断,此时系统切换显示此刻时间,时间初始值需人为设定。

3、调试过程中遇到的问题

(1)初次使用LCD1602时,编写程序发现液晶屏上显示不了

解决方案:LCD1602显示字符,需将显示数字改为字符串形式。

(2)DS18B20初始化一直失败

解决方案:DS18B20时序性非常严格,需准确定时,故单独为此元件设定了延时函数。

  1. DS18B20温度转换出现问题,零上温度小数均可正常显示而零下小数为乱码       暂未解决
  2. 切换时间显示和温度显示时LCD1602出现重影和乱码现象

解决方案:每次调用时间或温度显示时先清屏,但只能调用一次,一直调用会出现闪烁重影现象,故需加上标志位,每次调用函数时标志位为1,执行一次后标志位置0,标志位为1时执行清屏动作,并且将另一个显示函数的标志位置1,如此便可使每次调用函数时都能使清屏动作执行一次。

protues仿真图:

 

温度显示:

 

时间显示:

 

附上代码:

#include <reg52.h>  
#define uint unsigned int
#define uchar unsigned char
#define LCD P2
sbit E=P3^0;				//LCD使能端口定义 
sbit RW=P3^1;				//LCD读写使能端口定义
sbit RS=P3^2;				//LCD数据/命令选择方式端口定义
sbit bflag=P2^7;			//LCD忙指示端口,高电平为忙
sbit DQ	 = P3^4; //DS18B20引脚
sbit P10=P1^0;					 //温度加一
sbit P11=P1^1;					 //温度减一
sbit P12=P1^2;					 //报警
sbit P13=P1^3;					 //喇叭
sbit TW=P3^3;					 //显示时间还是温度
uint readtemp=0;				   //读取温度
uint settemp=25;					//设定温度
uchar i=0;						
uchar miao=50;						 //时间显示
uchar fen=59;
uchar shi=23;
uchar str[]={"0123456789"};		   //驱动数组
uchar str1[]={"Temp:"};				  //读取温度
uchar str3[]={"Set:"};				  //设定温度
uchar str4[]={"Time:"};				  //时间
uint xtemp;							   //装载小数
int flag=1;							   //温度清屏标志
int balg=1;							   //时间清屏标志位
void delay_18b20(uint i)					 //DS18B20专用延时
{
   for(;i>0;i--);
}

void delay(uint x)
{
   uint i,j;
   for(i=0;i<x;i++)
   {
      for(j=0;j<120;j++);
   }
}
void check_busy(void)  //检查忙标志位函数
{
   uchar dt;
   do
   {
      dt=0xff;
	  E=0;
	  RS=0;
	  RW=1;   //只有RS=0,RW=1,E=1时才能读忙标志位
	  E=1;
	  dt=P2;     //P0口的状态送入dt中
   }
   while(dt&0x80);     //如果忙标志位BF=1,继续循环检测,等待BF=0
   E=0;    //BF=0,结束检测
}
void writedat(unsigned char dat)	 //函数功能:写数据函数 
{
   check_busy();
   RS=1;		//当RS=1,RW=0时,表明写入的是数据
   RW=0;
   E=0;
   P2=dat;
   delay(5);		//当使能由高到低时,LCD执行相应命令
   E=1;
   E=0;
}
void writecom(unsigned char com)	 //函数功能:写指令函数 
{
   check_busy();
   RS=0;		//当RS=0,RW=0时,表明写入的是命令
   RW=0;
   E=0;
   P2=com;		//当使能由高到低时,LCD执行相应命令
   delay(5);
   E=1;
   E=0;
}
void initlcd()			 //函数功能:设置LCD_1602的开显示 光标不闪烁等的功能 
{
   writecom(0x38);			//指令6,8位数据总线,双行显示,每位采用5*7点阵  指令6
   writecom(0x08);			//指令4,关显示,关光标,无闪烁                  指令4
   writecom(0x06);			//指令3,光标自动右移,文字不移动                指令3
   writecom(0x01);			//指令1,清显示                                  指令1
   writecom(0x0c);			//指令4,开显示                                  指令4
}
void InitDs18b20(void)			  //初始化
{
	uchar x=0;
	DQ=1;
	delay_18b20(8);
	DQ = 0;    
	delay_18b20(80);    
	DQ=1;
	delay_18b20(14);
	x=DQ;
	delay_18b20(20);
}
unsigned char ReadOneChar(void)					 //读字节
{
	unsigned char i=0;
	unsigned char dat = 0; //接收数据

	for(i=0;i<8;i++)
	{
		DQ= 0;
		dat=dat>>1;	  //右移一位
		DQ = 1; //释放总线
		if(DQ)
		
			dat = dat|0x80;
			delay_18b20(4);
	}
	return dat;
}
void WriteOneChar(unsigned char dat)			 //写字节
{
	unsigned char i;
	for(i=0;i<8;i++)
	{
		DQ= 0; //拉低电平
		DQ = dat&0x01;
		if(DQ)
		{
		   delay_18b20(1);DQ=1;}
		 else { delay_18b20(5);DQ=1;}
         dat = dat>>1;
	}		
}
uchar ReadTemperature(void)
{
	unsigned char a=0,b=0;
	uchar temp=0;
	InitDs18b20();	//初始化DS18B20
	WriteOneChar(0xcc); //跳过ROM
	WriteOneChar(0x44); //启动温度转换指令
	delay_18b20(100);
	InitDs18b20(); //每一次写命令都需要初始化
	WriteOneChar(0xcc); //跳过ROM
	WriteOneChar(0xbe); //读暂存器内容
	a=ReadOneChar();	 //获取温度的第一个字节         a存低字节
	b=ReadOneChar();     //获取温度的第二个字节			b存高字节			  00000 111    1111 0000 
	temp=b<<4|a>>4;       //  获取温度整数值
	xtemp=a&0x0f;			   //获取小数
	return (temp);
}
 void display()										  //正温度显示
 {
    uint temp0=0,temp1=0,temp2=0,temp3=0,i=0;
	temp0=readtemp/100;
	temp1=(readtemp%100)/10;
	temp2=readtemp%10;
	temp3=xtemp*625/1000;
	writecom(0x80);
	delay(5);
	while(str1[i]!='\0')
	{
	   writedat(str1[i]);
	   i++;
	}
	writecom(0x80+7);		//定义地址
	delay(1);
	writedat(str[temp0]);		 //百位
	delay(1);
	writedat(str[temp1]);		  //十位
	delay(1);
	writedat(str[temp2]);		   //个位
	delay(1);
	writedat('.');
	delay(1);
	writedat(str[temp3]);				   //小数
	delay(1);
	writedat(0xdf);
	delay(1);
	writedat('c');
	delay(1);
}
void displayfu()										//负温度显示
{
   uint temp0=0,temp1=0,temp2=0,temp3=0,i=0;
	temp0=readtemp/100;
	temp1=(readtemp/10)%10;
	temp2=readtemp%10;
/*	xtemp=~xtemp;
	xtemp=xtemp&0x0f;
	xtemp=xtemp+1;
	temp3=xtemp*625/1000;
*/
	writecom(0x80);
	delay(1);
	while(str1[i]!='\0')
	{
	   writedat(str1[i]);
	   i++;
	}
	writecom(0x80+7);
	delay(1);
	writedat('-');
	writecom(0x80+8);
	delay(1);
	writedat(str[temp0]);
	delay(1);
	writedat(str[temp1]);
	delay(1);
	writedat(str[temp2]);
	delay(1);
	writedat('.');
	delay(1);
	writedat(str[temp3]);
	delay(1);
	writedat(0xdf);
	delay(1);
	writedat('c');
	delay(1);
}
void display0()												 //0 时
{
    uint temp0=0,temp1=0,temp2=0,temp3=0,i=0;
	temp0=readtemp/100;
	temp1=(readtemp%100)/10;
	temp2=readtemp%10;
	temp3=xtemp*625/1000;
	writecom(0x80);
	delay(1);
	while(str1[i]!='\0')
	{
	   writedat(str1[i]);
	   i++;
	}
	writecom(0x80+7);
	delay(1);
	writedat(str[temp0]);
	delay(1);
	writedat(str[temp1]);
	delay(1);
	writedat(str[temp2]);
	delay(1);
	writedat('.');
	delay(1);
	writedat(str[temp3]);
	delay(1);
	writedat(0xdf);
	delay(1);
	writedat('c');
	delay(1);
}
void wenkong()
{
    if(P10==0)				 //温控加一
	{
	   	settemp=settemp+1;
		while(P10==0);			//检测按键是否弹起
		  
	}
	if(P11==0)			  //温控减一
	{
	    settemp=settemp-1;
		while(P11==0);		//检测按键是否弹起
	}
}
void displayset()										//显示设定的温度
{
    uint temp0=0,temp1=0,temp2=0,i=0;
	temp0=settemp/100;
	temp1=(settemp%100)/10;
	temp2=settemp%10;
	writecom(0x80+0x40);
    while(str1[i]!='\0')
	{
	   writedat(str3[i]);
	   i++;
	}
	writecom(0x80+0x40+7);
	delay(1);
	writedat(str[temp0]);
	delay(1);
	writedat(str[temp1]);
	delay(1);
	writedat(str[temp2]);
	delay(1);
	writedat('.');
	delay(1);
	writedat('0');
	delay(1);
	writedat(0xdf);
	delay(1);
	writedat('c');
	delay(1);
}
void delay500()
{
	unsigned char  i;
	for(i=250;i>0;i--);
	
}
void displaymusic()								 //报警程序
{
    uchar readtemp1;
    uchar count;
    if(P12==0)
	{
	   readtemp1=readtemp;
	   if(readtemp>settemp)
		{
			for(count=200;count>0;count--)
			{
				P13=~P13;
				delay500();
			}
			for(count =200;count>0;count--)
			{	
				P13=~P13;
				delay500();
				delay500();
			}
		}
	}

}

void findisplay()										   //温度显示整合
{
    displayset();
	  wenkong();
	  displaymusic();
      if(ReadTemperature()==0)
	  {
	     writecom(0x01);
		 readtemp=0;
		 display0();
	  }
	  if(ReadTemperature()<128)
	  {
	     readtemp=ReadTemperature();
		 display();
	  }
	  else
	  {
	     char a=0;
		 a=ReadTemperature();
		 readtemp=~a+1;
		 displayfu();
	  }
}
void timedisplay()
{	uint i=0;
    writecom(0x80);					 //第一行显示time:
    while(str4[i]!='\0')
	{
	   writedat(str4[i]);
	   i++;
	}
	writecom(0x80+0x40+4);		   //第二行显示 时间  00:00:00
	writedat(str[shi/10]);		   //小时数
	writedat(str[shi%10]);
	writedat(':');
	writedat(str[fen/10]);			//分钟数
	writedat(str[fen%10]);
	writedat(':');
	writedat(str[miao/10]);			 //秒数
	writedat(str[miao%10]);
}

   
void timer0() interrupt 1				 //定时50ms	  0.05s
{
    char i;
     i++;
   TH1=(65536-50000)/256;
   TL1=(65536-50000)%256;
   if(i==20)
   {
     i=0;
     miao++;
   }
   if(miao==60)
   {
     miao=0;
	 fen++;
   }
   if(fen==60)
   {
     fen=0;
     shi++;
   }
   if(shi==24)
   {
     shi=0;
   }
}

void int1() interrupt 2
{
    if(balg==1)							   //清屏标志
	{
	writecom(0x01);
	balg=0;
	}
   timedisplay();
   flag=1;								//方便下次温度显示清屏
}  
void main()
{
   TMOD=0x01;
   TL0=(65536-50000)%256 ;  //定义50ms
   TH0=(65536-50000)/256 ;
   IE=0X86;			 //启用 TF0  INT1
   TR0=1;
   initlcd();
   while(1)

   {
        balg=1;									//中断清屏准备
        if(flag==1)
		{
		 writecom(0x01);
		 flag=0;
		}
	    findisplay();
   }
}

   

  • 35
    点赞
  • 171
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

森屿~~

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值