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

article/2025/9/30 15:05:23

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

    此系统主要由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=0E=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点阵  指令6writecom(0x08);			//指令4,关显示,关光标,无闪烁                  指令4writecom(0x06);			//指令3,光标自动右移,文字不移动                指令3writecom(0x01);			//指令1,清显示                                  指令1writecom(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();	//初始化DS18B20WriteOneChar(0xcc); //跳过ROMWriteOneChar(0x44); //启动温度转换指令delay_18b20(100);InitDs18b20(); //每一次写命令都需要初始化WriteOneChar(0xcc); //跳过ROMWriteOneChar(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:00writedat(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 ;  //定义50msTH0=(65536-50000)/256 ;IE=0X86;			 //启用 TF0  INT1TR0=1;initlcd();while(1){balg=1;									//中断清屏准备if(flag==1){writecom(0x01);flag=0;}findisplay();}
}


http://chatgpt.dhexx.cn/article/v8BMX9yj.shtml

相关文章

vue项目中动态显示时间

vue项目中动态显示时间 前言一、js源代码二、效果图1.修改2.html与style的修改3.修改后效果图 总结 前言 在vue项目中动态显示时间&#xff0c;并且按日期、时间、星期一列排列。 我们想要的是下图时间显示方法。 一、js源代码 声明变量 export default {data() {return {ti…

51单片机lcd1602显示时间日期

实验内容&#xff1a; 使用51单片机控制LCD1602液晶显示屏显示 时间/日期/星期/温度 信息&#xff0c;并可通过按键设置值。 仿真效果展示&#xff1a; proteus仿真图&#xff1a; 硬件测试图&#xff1a; 说明&#xff1a; 硬件测试按键使用左侧的四个独立按键 key…

计算机怎么在桌面显示时间,怎么设置使电脑即显示时间有显示日期

怎么设置使电脑即显示时间有显示日期以下文字资料是由(历史新知网www.lishixinzhi.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧! 怎么设置使电脑即显示时间有显示日期 单击“开始→控制面板区域和语言选项”,在“区域选项”选项卡中单击“自定义”按钮打开…

1.Vue显示实时时间

实时显示时间&#xff0c;代码如下&#xff1a; <div id"app">{{date}}</div><script>var appnew Vue({el:"#app",data:{date:new Date()},mounted:function(){var _thisthis;this.timersetInterval(function(){_this.datenew Date();}…

Linux、Oracle、MySQL命令提示符显示时间

前言&#xff1a;测试环境Oracle DG开启了FLASHBACK有遇到过to timestamp的恢复场景&#xff0c;因为这个问题有了在sqlplus命令提示符前显示时间的需求&#xff0c;顺着也了解了下怎么在Linux、MySQL命令提示符前显示时间。 1. Linux命令提示符显示时间 PS1是Linux终端用户的一…

Linux命令之显示日期时间date

概述 date 可以用来显示或设定系统的日期与时间。 语法 该命令的语法如下&#xff1a; date [选项] [日期时间格式]该命令支持的选项有&#xff1a; 选项说明-d <时间字符串>显示指定的“时间字符串”表示的时间&#xff0c;而非当前时间。注意用双引号把字符串引起…

Java之Redis分片机制

1. Redis分片机制 1.1 分片机制说明 前提说明: redis可以通过修改内存的大小 实现数据的保存.但是内存的资源不易设置的过大,因为很多的时间都浪费在内存的寻址中. 需求: 如果有海量的数据,需要redis存储 问:应该如何处理? 解决方案: 可以采用Redis分片机制 实现内存数据的扩…

Redis分片+Redis哨兵

Redis分片机制 Redis分片前提:Redis可以通过修改内存的大小实现数据的保存,但是不能设置的过大 解决方案:可以采用Redis分片机制来实现内存数据的扩容,使用Redis分片的主要目的就是为了内存扩容,解决海量数据的存储问题 Redis每个分片内的数据都是不相同的 Redis分片搭建步骤…

flea-cache使用之Redis分片模式接入

Redis分片模式接入 1. 参考2. 依赖3. 基础接入3.1 定义Flea缓存接口3.2 定义抽象Flea缓存类3.3 定义Redis客户端接口类3.4 定义Redis客户端命令行3.5 定义分片模式Redis客户端实现类3.6 定义Redis分片连接池3.7 Redis配置文件3.8 定义Redis Flea缓存类3.9 定义抽象Flea缓存管理…

java如何实现redis分片存储_Redis的分片机制

前言:大家都知道redis单台的默认内存大小一般是10M.如果现在需要我们将1G的数据保存到内存中。这该如何做到呢?比如我们就用单台redis,但是一味的扩大单台redis内存则直接影响执行的效率,会有一种得不偿失的感觉。于是呢,我们就得采用分片策略实现数据保存,通过多台redis…

Redis分片的实现

1.为什么使用分片 1.1 说明: 虽然redis可以扩展内存空间的大小,但是如果需要存储海量的数据,一味地去扩大内存,其实效率不高. 1.2 分片的介绍 准备多台redis,共同为用户提供缓存服务,在保证效率的前提下,实现了内存的扩容. 用户在使用分片机制时,将多台redis当做一个整体来…

使用DockerCompose部署Redis分片集群——整合SpringBoot

今天来记录一下使用DockerCompose部署Redis分片集群的过程&#xff0c;前面写了几篇关于redis的博客了&#xff0c;这里就不再过多介绍了&#xff0c;直接上配置就好了 version: "3.0"services:redisServer1:image: redis:6.2.4container_name: redis_server1volume…

redis之分片集群

写在前面 当redis单实例存储的数据过多时&#xff0c;比如说20G&#xff0c;就会出现因为生成RDB快照较长时间比如500ms阻塞主线程的问题&#xff0c;在这一段时间里&#xff0c;因为主线程被阻塞&#xff0c;所以Redis实例无法正常的对外提供服务&#xff0c;出现这个问题的原…

Redis分片集群(详解+图)

目录 分片集群特征&#xff1a; 散列插槽 集群伸缩 创建新的redis实例 添加新节点到redis 转移插槽 故障转移 自动故障转移 手动故障转移 RedisTemplate访问分片集群 主从和哨兵可以解决高可用、高并发读的问题。但是依然有两个问题没有解决&#xff1a; 海量数据存储问…

redis分片_Redis分片

redis分片 本文是我们学院课程的一部分&#xff0c;标题为Redis NoSQL键值存储 。 这是Redis的速成课程。 您将学习如何安装Redis和启动服务器。 此外&#xff0c;您还会在Redis命令行上乱七八糟。 接下来是更高级的主题&#xff0c;例如复制&#xff0c;分片和集群&#xff0…

(分布式缓存)Redis分片集群

对应的教程视频: 高级篇Day3-04-Redis分片集群_哔哩哔哩_bilibili 一.搭建分片集群 1.集群结构 分片集群需要的节点数量较多&#xff0c;这里我们搭建一个最小的分片集群&#xff0c;包含3个master节点&#xff0c;每个master包含一个slave节点&#xff0c;结构如下&#xff…

Docker中搭建redis分片集群,搭建redis哨兵结构,实现springboot中对redis分片集群、哨兵结构的访问,Redis缓存雪崩、缓存击穿处理(非关系型数据库技术课程 第十二周)

文章目录 一、要求&#xff1a;二、知识总结缓存雪崩解决方案 docker中redis分片集群搭建配置好配置文件redis-6380.confredis-6381.confredis-6382.confredis-6383.confredis-6384.confredis-6385.conf 将conf_cluster文件夹移动到对应位置docker中运行对应的redis容器docker中…

Redis分片入门案例

说明 由多台redis共同处理用户的业务数据&#xff0c;实现了redis内存数据的动态扩容&#xff0c;称之为分片机制。 特点 多态redis当作一台使用 分片搭建 1、在redis工作目录下创建工作目录 [rootlocalhost redis]# mkdir shards2、把redis配置文件复制到指定目录下 3、…

分布式缓存-Redis分片集群

一、分片集群结构 主从和哨兵可以解决高可用、高并发读的问题&#xff0c;但是依然有两个问题没有解决&#xff1a; 海量数据存储问题高并发写的问题 使用分片集群可以解决上述问题&#xff0c;分片集群特征&#xff1a; 集群中有多个 master&#xff0c;每个 master 保存不…

SpringBoot整合Redis分片

1 编辑分片配置文件 #redis.host192.168.126.129 #redis.port6379 redis.nodes192.168.126.129:6379,192.168.126.129:6380,192.168.126.129:63812 编辑配置类实现redis整合 Configuration //我是一个配置类 一般都会与Bean联用 PropertySource("classpath:/properti…