基于51单片机的LCD显示、键盘、DS18B20和DS1302综合设计

2 篇文章 0 订阅
1 篇文章 0 订阅

一、制作目的

  1. 熟练掌握键盘、显示、DS18B20温度传感器等各个模块;
  2. 训练系统综合的能力;
  3. 编写键盘、显示、DS18B20温度传感器综合程序。

二、开发环境

  1. Keil开发环境
  2. Proteus仿真环境。

三、制作内容用LCD、DS18B20、按键配合完成设计

  1. LCD显示,当前的室内温度及时间和日期(可使用DS1302时钟芯片);
  2. 用按键可调节日期和时间

四、实验步骤

  1. 进行方案分析该项实践要使用到LCD1604,DS18B20,DS1302这三种元器件,并且要使用按键与DS1302进行连接,从而实现通过按键调整DS1302的日期和时间。首先应该对各个部分功能能清晰显示,显示后再对各个部分进行衔接.

  2. 搭建仿真电路图
    在这里插入图片描述
    运用了AT89C51单片机,LCD1604,DS1302时钟芯片,三个独立按键和DS18B20芯片。

  3. 构思整体设计本组选择的是用LCD显示,当前的室内温度及时间和日期(其中使用了DS1302时钟芯片),并且用按键可调节日期和时间。首先搭建LCD1604的仿真电路,测试无误后搭建DS1302时钟芯片电路,并且添加三个独立按键,经调试无误,最后搭建DS18B20温度传感器电路,在LCD1604的后两行进行显示,进而完成整体设计。

  4. 绘制流程图
    在这里插入图片描述

  5. 分模块调试
    (1)首先检测LCD1604是否能正常运行
    在这里插入图片描述
    (2)LCD1604能正常显示,接下来对DS18B20温度传感器模块进行测试,是否能准确显示改变的温度值。(这里使用-10度测试)
    在这里插入图片描述
    (3)对按键进行检测,是否能对日期产生改变,功能键功能是按一下即可改变所要调的位置。例如一开始调秒,按一下功能键即可调分,可由秒分时日月周年循环切换,其他两个独立按键一个是对当前值+1一个是对当前值-1,我们这里测试能不能调到2000年与23小时时候。
    在这里插入图片描述

  6. 综合调试能够正确显示所设定初值的DS1302时钟上的日期与时间,并且可以通过按键对日期和时间进行改变,DS18B20温度传感器也能在LCD1604上显示出当前温度值并且能够随着温度值的改变而在LCD1604上的显示改变。

五、实验程序与分析

  1. 程序
#include <reg51.h>#include <intrins.h>  
//包含_nop_( )空函数指令的头文件
#define uchar unsigned char
#define uint unsigned int 
sbit RS=P2^0; 	//LCD1604位变量
sbit RW=P2^1;	//LCD1604位变量
sbit E=P2^2; 	//LCD1604位变量 
sbit RST=P0^0;	
//DS1302芯片复位,1—芯片的读/写使能,0—芯片复位并被禁止读/写
sbit SCLK=P0^1;       //DS1302芯片同步串行时钟输入
sbit DS1302IO=P0^2;   //DS1302芯片数据输入/输出
sbit DQ= P2^3;	//定义DS18B20端口DQ
void lcd_initial(void);	//LCD初始化函数
void check_busy(void); 	//检查忙标志函数
void write_command(uchar com); 	//写命令函数
void write_data(uchar dat);	//写数据函数
void delay(uint);		//延时函数
void DS1302_initial();          //DS1302初始化函数
void DS1302Write(uchar addr,uchar dat);	 
//对DS1302时钟写入命令,写入数据
void DS1302Read_Time();                  
//读取七个字节的时钟信号:秒分时日月周年
uchar DS1302Read(uchar addr);   			 
//对DS1302时钟写入命令,读出数据
void xiangshi();        //将DS1302上的时钟显示在LCD1604上
void button();		//根据按键值进行操作
void DS18B20_init(void);//DS18B20的初始化
uchar read_bit(void);	 //读一位
uchar read_byte(void);	 //读一个字节
void write_bit(uchar temp);//写一位
void write_byte(uchar val);//写一个字节
void read_T(void);	//读温度
void delay5(uchar n);	//5us延时
void convert_T();
void display_T(void);
uchar Read_DS1302_data[]={0x81,0x83,0x85,0x87,0x89,0x8b,0x8d};	 
//DS1302秒分时日月周年读命令
uchar Write_DS1302_ADDR[]={0x80,0x82,0x84,0x86,0x88,0x8a,0x8c};  
//DS1302秒分时日月周年写命令
uchar TIME[7]={0x00,0x00,0x12,0x05,0x02,0x02,0x20};					 
//DS1302初值
uchar digit=0;//功能键
uchar temp_data_l,temp_data_h;
uint temp_data;
uchar code LCDData[10]= 
{0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37,0x38,0x39};
uchar code ditab[16]  = 
{0x30,0x31,0x31,0x32,0x33,0x33,0x34,0x34,0x35,0x36,										 
0x36,0x37,0x38,0x38,0x39,0x39};
uchar code  table2[16] ="Show Tempreture:";
uchar display[7] = {0x00,0x00,0x00,0x2e,0x00,0xdf,0x43};
void main(void) //主函数
{	
lcd_initial( );	//调用对LCD初始化函数	
DS1302_initial(); //调用对DS1302初始化函数	
while(1){ 		 
DS1302Read_Time();//读取七个字节的时钟信号:秒分时日月周年		 
xiangshi();//将DS1302上的时钟显示在LCD1604上		 
button();         //根据按键值进行操作   	 	 
read_T();   		 
convert_T();		 
display_T(); 	 } 		
delay(100); 	//延时		
write_command(0x01);//写入清屏命令		
delay(100);	//延时 }
void button()//根据按键值进行操作
{	
uchar n,i;	
P1=0x07;//只看重前三位,后五位忽略
	n=P1;	
	n=n&0x07;	
	if(n!=0x07){    //检测按键按bai下
	delay(500); //去抖		
	if(n!=0x07); } //检测按键确实按下,进行按键处理			
	if(n==0x06){		
	digit++;}	//由转换周改为转换年(例子)	
	if(digit==7){		
	digit=0;}	//轮了一圈又回来	
	if(n==0x05){		
	for(i=0;i<7;i++){			
	if(digit==i){				
	if((TIME[i]&0x0f)<9){					
	TIME[i]=TIME[i]+0x01;}				
	else{TIME[i]=TIME[i]+0x10-0x09;}				
	DS1302_initial(); }}}	//按下第二个建加1			
	if(n==0x03){			
	for(i=0;i<7;i++){			
	if(digit==i){				
	if((TIME[i]&0x0f)<10&&(TIME[i]&0x0f)!=0){					
	TIME[i]=TIME[i]-0x01;}				
	else{TIME[i]=TIME[i]+0x09-0x10;}				
	DS1302_initial(); }}}	//按下第三个建减1
void delay(uint j)//1ms延时子程序
{	
uchar i=250;	
for(;j>0;j--)	
{		
while(--i);		
i=249;		
while(--i);		
i=250;	}}
void delay5(uchar n){	
 do	 
 {	 
 _nop_();	
 _nop_();	
 _nop_();	 
 n--;	 
 }	
  while(n);}
void xiangshi()	//将DS1302上的时钟显示在
LCD1604上{	
button();	
write_command(0x80);	
write_data(0x30+2);	
write_data(0x30+0);	
write_data(0x30+TIME[6]/16);	//年	
write_data(0x30+(TIME[6]&0x0f));	
write_data('-');	
write_data(0x30+TIME[4]/16);	//月	
write_data(0x30+(TIME[4]&0x0f));	
write_data('-');
write_data(0x30+TIME[3]/16);	//日	
write_data(0x30+(TIME[3]&0x0f));		write_command(0x8d);			//星期	
write_data(0x30+(TIME[5]&0x07));		
write_command(0xc0);	
write_data(0x30+TIME[2]/16);	//小时	
write_data(0x30+(TIME[2]&0x0f));	
write_data(':');	
write_data(0x30+TIME[1]/16);	//分	
write_data(0x30+(TIME[1]&0x0f));	
write_data(':');	
write_data(0x30+TIME[0]/16);	//秒	
write_data(0x30+(TIME[0]&0x0f));}``
void convert_T()
{	     
uchar temp;     
if((temp_data_h&0xf0)==0xf0)//判断是不是负数	   
{	      
temp_data_l=~temp_data_l;//如果是负数,取反	      
if(temp_data_l==0xff)	 //如果低八位全为1	        {	      		
temp_data_l=temp_data_l+0x01;	      		
temp_data_h=~temp_data_h;		  		
temp_data_h=temp_data_h+0x01;  //高八位加1		 	
}	      
else	       
{	       		
temp_data_l=temp_data_l+0x01;  //取反后需要加1	      		
temp_data_h=~temp_data_h;           }	 			
display[4]=ditab[temp_data_l&0x0f];//查表得小数位的值     			
temp=((temp_data_l&0xf0)>>4)|((temp_data_h&0x0f)<<4);     			
display[0]=0x2d;     			
display[1]=LCDData[(temp%100)/10];     			
display[2]=LCDData[(temp%100)%10];	   }   
else		//如果不是负数       
{  		      	
display[4]=ditab[temp_data_l&0x0f];//查表得小数位的值     			
temp=((temp_data_l&0xf0)>>4)|((temp_data_h&0x0f)<<4);	
//个位数值     			
display[0]=LCDData[temp/100];		//百位     			
display[1]=LCDData[(temp%100)/10];	//十位    	 		
display[2]=LCDData[(temp%100)%10];	//个位 	    
}}
void display_T(void){  
uchar i;  
write_command(0x90);  
for(i=0;i<16;i++)  
{    
write_data(table2[i]);  
}  
write_command(0xd0);  
for(i=0;i<7;i++)  {    
write_data(display[i]);  } }
void DS1302_initial()  //DS1302初始化函数
{	
uchar n;	
DS1302Write(0x8e,0x00);    
//禁止写保护(正常工作时不能改变DS1302里的数据,就要进行写保护,就像家里要锁上一把锁)	
for(n=0;n<7;n++){//写入七个字节时钟信号:秒分时日月周年		
DS1302Write(Write_DS1302_ADDR[n],TIME[n]);
}	
DS1302Write(0x8e,0x80);	   //打开写保护功能
} 
void DS1302Read_Time()
//读取七个字节的时钟信号:秒分时日月周年
{	
uchar n;	
for(n=0;n<7;n++){		
TIME[n]=DS1302Read(Read_DS1302_data[n]);}}
``````c
void DS1302Write(uchar addr,uchar dat)	 
//对DS1302时钟写入命令,写入数据
{	
uchar n;	
RST=0;//禁止读写	
_nop_();	
SCLK=0; //输入时钟置为低电平	
_nop_();	
RST=1;   //允许读写	
_nop_();	
for(n=0;n<8;n++){//开始传送8位地址命令		
DS1302IO=addr&0x01;   //数据从最低位开始传送		
addr>>=1;		
SCLK=1;               //时钟拉高,写入一位数据(上升沿写入)		
_nop_();		
SCLK=0; //拉低,写入完毕		
_nop_();	}	
for(n=0;n<8;n++){//写入八位数据		
DS1302IO=dat&0x01;   //数据从最低位开始传送		
dat>>=1;		
SCLK=1;               
//时钟拉高,写入一位数据(上升沿写入)		
_nop_();		
SCLK=0; //拉低,写入完毕		
_nop_();	
}	
RST=0; //写入数据完毕	
_nop_();}
``````c
uchar DS1302Read(uchar addr)   //对DS1302时钟写入命令,读出数据
{	
uchar n,dat,dat1;	
RST=0;		//禁止读写	
_nop_();	
SCLK=0;     //输入时钟置为低电平	
_nop_();	
RST=1;      //允许读写	
_nop_();	
for(n=0;n<8;n++){//开始传送8位地址命令		
DS1302IO=addr&0x01;   //数据从最低位开始传送		
addr>>=1;		
SCLK=1;               //时钟拉高,写入一位数据(上升沿写入)		
_nop_();		
SCLK=0; //拉低,写入完毕		
_nop_();	}	
_nop_();	
for(n=0;n<8;n++){ //读取八位数据		
dat1=DS1302IO;		
dat=(dat>>1)|(dat1<<7);		
SCLK=1;		
_nop_();		
SCLK=0;	//DS1302下降沿,放置数据		
_nop_();	}	
RST=0;      //写入数据完毕	
_nop_();	
SCLK=1;   //DS1302复位的稳定时间,具体为什么不大清楚	
_nop_();	
DS1302IO=0;	
_nop_();	
DS1302IO=1;	
_nop_();	
return dat;}
void DS18B20_init(void)	//DS18B20的初始化
{ 	 
DQ =0;    	 
delay5(120);      
//拉低1-Wire总线超过480us来发送复位脉冲,释放总线进入接收模式	 
DQ =1;    	
//总线释放后,5KΩ左右的上拉电阻将1-Wire总线拉至高电平	 
delay5(16);	//等待15-60us	 
delay5(80);		
//DS18B20内部总线拉低60-240us来实现发送一个存在脉冲
}
uchar read_bit(void)			
//DS18B20读一个位(每个读时段最小必须有60us的持续时间和并且独立的写时段至少有1us的恢复时间)
{  
DQ=0;//主设备拉低总线  
_nop_();//空操作用于恢复时间  
_nop_();  
DQ=1;	//主设备释放总线  
delay5(2);//采样有效时间为15us  
return(DQ); }  
uchar read_byte(void)//DS18B20读一个字节
{ 
uchar i,temp; temp=0; 
for(i=0;i<8;i++) {  
temp>>=1;						  
if(read_bit())   {		  
temp|=0x80;		  
delay5(11);//每个读时段最小必须有60us的持续时间   
}   
delay5(6);   } 
return(temp);}
void write_bit(uchar temp)//写一位
{ 
DQ=0; 
if(temp==1)//写1的时候,不需要等待,直接拉高主设备总线 
DQ=1; 
delay5(12);//写0的时候,至少拉低60us 
DQ=1; }  
void write_byte(uchar val)//写一个字节
{ 
uchar i,temp; 
for(i=0;i<8;i++) {  
temp=val>>i;//从最低位开始一位一位写进去  
temp=temp&0x01;  
write_bit(temp);  
delay5(5);  }}
void read_T(void)//读温度
{     
DS18B20_init();	//DS18B20的初始化     
write_byte(0xCC);  //跳过读序号列号的操作(跳过ROM)     
write_byte(0x44);  //启动温度转换	 
delay5(500);     
DS18B20_init();	//DS18B20的初始化     
write_byte(0xCC);  //跳过读序号列号的操作     
write_byte(0xBE);  //读取温度寄存器     
temp_data_l= read_byte();  //温度低8位     
temp_data_h = read_byte();  //温度高8位 
}
void check_busy(void) 
{	//检查忙标志函数	
uchar dt;	
do	
{		
dt=0xff;		
E=0;		
RS=0;			
RW=1;		
E=1;		
dt=P3;	}while(dt&0x80);	
E=0;}
void write_command(uchar com) {  //写命令函数	
check_busy();	
E=0;	
RS=0;	
RW=0;	
P3=com;	
E=1;	
_nop_( );	
E=0;	
delay(1);}
void write_data(uchar dat)//写数据函数
{	
check_busy();	
E=0;	
RS=1;	
RW=0;	
P3=dat;	E=1;	
_nop_();	
E=0;	
delay(1);	
}
void LCD_initial(void)	 //液晶显示器初始化函数
{	
write_command(0x38);	
//写入命令0x38:8位两行显示,5×7点阵字符	
write_command(0x0c);	
//写入命令0x0C:开整体显示,光标关,无黑块	
write_command(0x06);	
//写入命令0x06:光标右移	
write_command(0x01); 	
//写入命令0x01:清屏	
delay(1);}
  1. 实验结果的分析与总结,有无改进方案?
    实验结果与分析:基本功能能够实现,但是在对DS1302时钟芯片进行调值时,比如24小时后应该归零,但是却变成了25,而且在减法的时候,一旦从0再减,就会变成乱码,这些是有缺漏的。改进方案:改进按键检测与按键进入的子程序中的程序,从而能够实现24小时后归零并且在时钟为00时能够从前借一位。
  • 6
    点赞
  • 42
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

Is_LiuYiZheng

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

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

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

打赏作者

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

抵扣说明:

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

余额充值