51单片机应用篇-- --电子数字钟(LCD1602显示)

开篇先说一句废话····
本旺名字叫萨摩耶,,Please 叫我旺财,,,哈哈,招财进宝嘛!

开篇

这篇文章算是对之前所学的内容的综合应用,很多人都说能实现一个数字钟的时候算是正式入门单片机,或者是晋级成单片机的孙子等级。

项目分析

《电子数字钟》这篇是基于定时器,所以首先就有了定时器的应用,本想着在数码管上显示,但是既然学了LCD1602,刚好拿来用用。还有对独立键盘的使用。(除完整代码外,其余代码都是拼接在一起的,单独使用要注意

  1. 第一步就是让LCD1602上显示一个初始化的日期+时间,这里就要用到LCD1602的初始化。
u8 Date[]="  2020-12-18   5";
u8 Time[]="    16:00:00";

void LcdInit(){
	u8 i;
	WriteCom(0x38);
	WriteCom(0x0c);
	WriteCom(0x06);
	WriteCom(0x01);
	WriteCom(0x80);
	for(i=0;i<16;i++){
		WriteData(Date[i]);
	}
	WriteCom(0x80+0x40);
	for(i=0;i<12;i++){
		WriteData(Time[i]);
	}
}
  1. 接着就是让定时器开始工作,声明一个标志位,作为一个一秒的标志。
//定时器0初始化
	TMOD=0x01;
	TH0=(65536-9174)/256;	//10ms
	TL0=(65536-9174)%256;
	EA=1;
	ET0=1;
	TR0=1;

void Time0() interrupt 1{
	TH0=(65536-9174)/256;
	TL0=(65536-9174)%256;
	tt++;
	if(tt==100){	//10ms*100=1s
		tt=0;
		SecondFlag=1;
	}
}
  1. 一秒时间是出来了,接着就是一秒发生后对时间的处理了。秒不断自加,如果秒到了60要向分进位;而分到了60就要想时进位了;时到了24就要想天进位,天满的情况有四种(28(不闰年2月),29(闰年2月),30(4,6,8,11),31(1,3,5,7,8,10,12)),先对年进行判断,来决定2月有多少天。每次进完位都在在月的位置写入(月份变化了)新的数据
//闰年判断
u8 LeapYear(u16 year){
	if(((year%4==0) && (year%100!=0)) || (year%400))
		return 1;		//闰年
	else 
		return 0;
}

if(mouth==2){
	YearFlag=LeapYear(year);
	if((YearFlag==1) && (day==30)){
		mouth++;
		day=1;
		WriteLcd(7,mouth);
	}
	if((YearFlag==0) && (day==29)){
		mouth++;
		day=1;
		WriteLcd(7,mouth);
	}
}

2月完了,接着是对31和30天的月份判断处理,如果月份刚好和天数对应那表示当月结束,月份加一,天数归1.要注意的是31天的月份里如果是 12月的话,要向年进位1. 并且写入年的位置新数据。

if((mouth==1) || (mouth==3)|| (mouth==5)|| (mouth==7)|| (mouth==8)|| (mouth==10)|| (mouth==12)){
	if(day==32){
		mouth++;
		day=1;
		WriteLcd(7,mouth);
		if(mouth==13){
			year++;
			WriteLcd(2,year/100);
			WriteLcd(4,year%100);
			mouth=1;
			WriteLcd(7,mouth);
			day=1;
			WriteLcd(10,day);
		}
	}
}
if((mouth==4) || (mouth==6)|| (mouth==9)|| (mouth==11)){
	if(day==31){
		mouth++;
		day=1;
		WriteLcd(7,mouth);
	}
}

还要注意每次秒,分,时变化的时候分别对各自的位置使用 WriteLcd() 写入新的数据。而且初始化秒分时的值要和第一次在LCD1602上显示的一致。

if(SecondFlag==1){
		SecondFlag=0;
		second++;
		if(second==60){
			second=0;
			minute++;
			if(minute==60){
				minute=0;
				hour++;
				if(hour==24){
					hour=0;
					day++;
					week++;
					if(week==8)
						week=1;
					WriteCom(0x80+15);
					WriteData(0x30+week);
					WriteLcd(10,day);
				}
				WriteLcd(0x40+4,hour);
			}
			WriteLcd(0x40+7,minute);
		}
		WriteLcd(0x40+10,second);
}
//时分秒天月年周的初始化
hour=16;
	minute=00;
	second=00;
	year=2020;
	mouth=12;
	week=5;
	day=17;
  1. 时间可以正常走了,那接着就是对时间的调整,就是对按键的处理,首先就是按键检测
//按键处理
void KeyDown(){
	if(k1==0){
		Delayms(50);
		if(k1==0){
			//k1功能
			K1Pross();
		}while(!k1);
	}
	if(k2==0){
		Delayms(50);
		if(k2==0){
			//k2功能
			K2Pross();
		}while(!k2);
	}
	if(k3==0){
		Delayms(50);
		if(k3==0){
			//k3功能
			K3Pross();
		}while(!k3);
	}
	if(k4==0){
		Delayms(50);
		if(k4==0){
			//k4功能
			K4Pross();
		}while(!k4);
	}
}
  1. 按键检测完之后就是进入每个按键的功能,K1的功能就是对修改时间或者修改日期的设置,要注意的就是设置之后还要注意光标闪烁初始位置的设置,(也是对某位的设置)
//K1功能处理
void K1Pross(){
	TR0=0;
	flag++;
	if(flag>2)
		flag=1;
	if(flag==1){		//flag=1 表示对时间的设定
		SetFlag=1;
		SetYearFlag=0;
		SiteFlag=0;
		WriteCom(0x80+0x44+SiteFlag);
		WriteCom(0x0f);
	}	
	else{			//flag=2 表示对日期的设定
		SetYearFlag=1;
		SetFlag=0;
		SiteYearFlag=0;
		WriteCom(0x80+0x08+SiteYearFlag);
		WriteCom(0x0f);
	}
}
  1. K2功能的设置,K2用来切换设置位置,(是要设置时呀还是分啥的),因为有个变量来控制这个位置,只需要注意跳过用来分割每个数值的“-”或者“:”,做法就是判断如果到达分割位自加一或者二跳过即可。
//K2功能处理
void K2Pross(){
	if(SetFlag==1){
		SiteFlag++;
		if(SiteFlag==8)
			SiteFlag=0;
		if((SiteFlag==2) || (SiteFlag==5))
			SiteFlag++;
		WriteCom(0x80+0x44+SiteFlag);
	}
	if(SetYearFlag==1){
		SiteYearFlag++;
		if(SiteYearFlag==4)
			SiteYearFlag=0;
		if(SiteYearFlag==1)
			SiteYearFlag+=2;
		WriteCom(0x80+0x08+SiteYearFlag);
	}
}
  1. K3功能的设置,K3则是在当前位置的数值自加一,虽然是自加一,但是要判断那位自加1,判断是否要进位,判断方法和时间进位的那些方法差不多,主需要相对应的修改一些即可。
//K3功能处理
void K3Pross(){
	if(SetFlag==1){
		switch(SiteFlag){
			case 0:{hour+=10;
					WriteLcd(0x44+SiteFlag,hour);
					WriteCom(0x10);
					WriteCom(0x10);
					break;}
			case 1:{hour+=1;
					WriteLcd(0x43+SiteFlag,hour);
					WriteCom(0x10);
					break;}
			case 3:{minute+=10;
					WriteLcd(0x44+SiteFlag,minute);
					WriteCom(0x10);
					WriteCom(0x10);
					break;}
			case 4:{minute+=1;
					WriteLcd(0x43+SiteFlag,minute);
					WriteCom(0x10);
					break;}
			case 6:{second+=10;
					WriteLcd(0x44+SiteFlag,second);
					WriteCom(0x10);
					WriteCom(0x10);
					break;}
			case 7:{second+=1;
					WriteLcd(0x43+SiteFlag,second);
					WriteCom(0x10);
					break;}
		}
	}
	if(SetYearFlag==1){
		switch(SiteYearFlag){
			case 0:{
				mouth++;
				if(mouth==13){
					mouth=1;
					year++;
					WriteLcd(2,year/100);
					WriteLcd(4,year%100);
				}
				WriteLcd(7,mouth);
				if(mouth==3){	//从2月加过去
					YearFlag=LeapYear(year);
					if(YearFlag==1){
						week+=(29%7);
						if(week>7)
							week=week-7;
						WriteCom(0x80+15);
						WriteData(0x30+week);
						
					}
					if(YearFlag==0){
						week+=(28%7);
						if(week>7)
							week=week-7;
						WriteCom(0x80+15);
						WriteData(0x30+week);
					}
				}
				if((mouth==2) || (mouth==4)|| (mouth==6)|| (mouth==8)|| (mouth==9)|| (mouth==11)|| (mouth==1)){
					week+=(31%7);
					if(week>7)
						week=week-7;
					WriteCom(0x80+15);
					WriteData(0x30+week);
				}
				if((mouth==5) || (mouth==7)|| (mouth==10)|| (mouth==12)){
					week+=(30%7);
					if(week>7)
						week=week-7;
					WriteCom(0x80+15);
					WriteData(0x30+week);
				}
				break;
			}
			case 3:{
				day++;
				week++;
				if(week==8)
					week=1;
				WriteCom(0x80+15);
				WriteData(0x30+week);
				if(mouth==2){
					YearFlag=LeapYear(year);
					if((YearFlag==1) && (day==30)){
							mouth++;
							day=1;
							WriteLcd(7,mouth);
						}
						if((YearFlag==0) && (day==29)){
							mouth++;
							day=1;
							WriteLcd(7,mouth);
						}
				}
				if((mouth==1) || (mouth==3)|| (mouth==5)|| (mouth==7)|| (mouth==8)|| (mouth==10)|| (mouth==12)){
					if(day==32){
						mouth++;
						day=1;
						WriteLcd(7,mouth);
						if(mouth==13){
							year++;
							WriteLcd(2,year/100);
							WriteLcd(4,year%100);
							mouth=1;
							WriteLcd(7,mouth);
							day=1;
							WriteLcd(10,day);
						}
					}
				}
				if((mouth==4) || (mouth==6)|| (mouth==9)|| (mouth==11)){
					if(day==31){
						mouth++;
						day=1;
						WriteLcd(7,mouth);
					}
				}
				WriteLcd(10,day);
				WriteCom(0x10);
				break;
			}
		}
	}
}
  1. K4功能的设定,K4功能比较简单,就是开启定时器开始工作,还需要注意的就是判断每个位置的数值是否符合要求,如果不符合强制归为初值,避免发生错误。
//K4功能处理
void K4Pross(){
	if(hour>23)
		hour=0;
	WriteLcd(0x40+4,hour);
	if(minute>59)
		minute=0;
	WriteLcd(0x40+7,minute);
	if(second>59)
		second=0;
	WriteLcd(0x40+10,second);
	SetFlag=0;
	SiteFlag=0;
	SetYearFlag=0;
	SiteYearFlag=0;
	WriteCom(0x0c);
	TR0=1;
}

  1. 对之前功能的调用(主函数),首先就是初始化,分为初始化参数和初始化定时器,初始化完就是不断地检测按键和时间的处理。
void main(){
	Init();
	while(1){
		KeyDown();
		TimePross();
	}
}

总结

大概的思路以及步骤就在上面了,如果阅读起来有问题,我建议单个看,也就是先调试时间,在调试日期,这样你会发现,时间和日期就是用一个标志位加各自的标志位(就三个标志位)区分的,这个就比较容易阅读了,若想自己写,可以观看 郭天祥《新概念51单片机C语言教程》视频。

完整代码贴在这不方便,所以我打包上传了,链接在下面,为了避免掏钱,我设置了粉丝可下载,如果你觉得我写的还不错,还看得过去,就点个赞关注一下,就可以下载了;如果不想这样,也可以先关注然后下载后取关就好,都是为了学习知识。谢谢各位。

实验:数字钟–基于定时器

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值