51单片机编程基础(C语言):电子时钟(LED1602作为显示)

题目要求:

审题时这个题是用数码管来显示的,数码管显示时钟我完成了一个,只是要求跟他不一样,所以这次想用LCD1602来显示,所以我先用LCD1602完成,再用数码管完成(其实也只要在我之前的项目基础上改一下就OK了)。

其实从第一个要求就看出来了,数码管无法显示:,只能显示.这次我用LCD显示,把所以得.改为:

1、显示“时.分”进行显示,例如“12.18”,其中.每秒闪烁一次。

2、能够校正时间的时和分,按键分为5个功能键

(1)设定键:在计时模式时,按下此键时停止计时,进入设置状态,并切换到分钟的设置状态,再按一次切换到小时的设置状态,每按下一次完成时.分设置的切换,用点亮时.分个位的数码管小数点表示分或秒处于设置状态。在闹钟时间设定状态时,按下此键同样进入设置状态,完成分、秒设置的切换。

(2)递增键:在设置状态时,按一次递增键,被设置的分钟数字或时钟数字增1,持续按下数字自动增1。

(3)递减键:在设置状态时,按一次递减键,被设置的分钟数字或时钟数字减1,持续按下数字自动增1。

(4)计时键:在设置状态或闹钟时间设定状态时,按下此键则单片机切换到计时的显示模式,按照新的时.分设置值进行计时。如果已经在计时状态则此键无效。

(5)闹钟键:在计时模式时,按下此键则单片机切换到闹钟时间设定状态的显示模式。等待“设定键”、“递增键”、“递减键”来设定分钟和秒钟。

3、当计时到闹钟设定时间,用发光二极管闪烁,十秒钟后结束闪烁,正常计时

总代码:

main.c     剩下的都是模块化编程好的,在我的模块化编程大全里面,

调试视频在我视频里

#include <REGX52.H>
#include "LCD1602.h"
#include "Delay.h"
#include "MatrixKey"
#include "Timer0.h"

unsigned char hour=23;  //小时位
unsigned char min=57;  //分钟位  
unsigned char miao=0;   //秒位
unsigned char keyNumber;     //接收矩阵键盘的返回值
unsigned char Mode=0;       // :显示标志位
unsigned char Start=0;       // 0为开始计时,1暂停计时
unsigned char min_hour_set; //当S1按下时,切换到计时小时和分钟设置位
unsigned char clock_hour;//闹钟的小时位
unsigned char clock_min;  //闹钟的分钟位 
unsigned char clock_miao;   //闹钟的秒位
unsigned char clock_counttime=0; //界面显示标记位,0为显示时钟模式,1为显示clock模式
unsigned char clock_min_clock_hour_set; //在闹钟模式显示下,切换到闹钟小时和分钟设置位   //按键不可能同时是两个值。
unsigned char flag=0;  //处于计时界面下,flag=0,处于clock界面下,flag=1,
                       //flag=0时,此时按下S1就是时钟模式设置键,flag=1,此时就是clock模式设置键
unsigned char who=0;   //由于加加,减减键是对min,hour起作用,即使进入闹钟模式,按下s1,按加加键无法改变闹钟的设置
                       //反而让计时模式下的时钟改变了,因为min_hour_set非0即1,
					   //所以对加加,减减键设置标志位,
sbit  LED=P2^0;
sbit BEEP=P2^5;
unsigned int i=1000;    //蜂鸣器报警时长。
unsigned int j=10;

void main()
{
	Timer0Init();
	LCD_Init();
	LCD_ShowChar(2,3,':');
	while(1)
	{
		keyNumber=MatrixKey();
		if(Mode==0)
		{
			LCD_ShowChar(2,3,':');
		}
		if(Mode==1)
		{
			LCD_ShowChar(2,3,' ');
		}
		if(clock_counttime==0)
		{
            LCD_ShowString(1,1,"count time");
			LCD_ShowNum(2,4,min,2);//更新显示
			LCD_ShowNum(2,15,miao,2);//更新显示
			LCD_ShowNum(2,1,hour,2);
		}
		if(clock_counttime==1)
		{
			LCD_ShowString(1,1,"clock      ");
			LCD_ShowString(2,7,"           ");
			LCD_ShowNum(2,4,clock_min,2);//更新为闹钟模式显示
		    LCD_ShowNum(2,1,clock_hour,2);//更新为闹钟模式显示
		}
		if(keyNumber==5)//S5按下,进入闹钟模式界面
		{
			clock_counttime=1;
			LCD_ShowString(1,12,"        ");
			flag=1;
			who=1;
		}
		if(keyNumber==4)//S4按下,进入计时模式界面
		{
			clock_counttime=0;
			LCD_ShowString(2,7,"           ");
			LCD_ShowString(1,12,"        ");
			Start=0;
			flag=0;
			who=0;
		}
		if(flag==0)
		{
			if(keyNumber==1)//S1按下 进入设置按键
			{
				Start=1;
				min_hour_set++;
				LCD_ShowString(2,7,"min ");
				if(min_hour_set>=2)
				{
					min_hour_set=0;
					LCD_ShowString(2,7,"hour");
				}		
			}
		}
		if(flag==1)
		{	
			if(keyNumber==1)//S1按下 进入设置按键
			{
				clock_min_clock_hour_set++;
				LCD_ShowString(1,12,"min        ");
				if(clock_min_clock_hour_set>=2)
				{
					clock_min_clock_hour_set=0;
					LCD_ShowString(1,12,"hour       ");
				}		
			}
		}
		if(keyNumber==2)//S2按下,设置加加键
		{
			if(who==0)
			{
				if(min_hour_set==1)//分钟设置状态
				{
					min++;
					if(min>=60)
					{
						min=0;
					}
				}
				if(min_hour_set==0)//小时设置状态
				{
					hour++;
					if(hour>=24)
					{
						hour=0;
					}
				}
			}
			if(who==1)
			{
				if(clock_min_clock_hour_set==1)//时钟分钟设置状态
				{
					clock_min++;
					if(clock_min>=60)
					{
						clock_min=0;
					}
				}
				if(clock_min_clock_hour_set==0)//时钟小时设置状态
				{
					clock_hour++;
					if(clock_hour>=24)
					{
						clock_hour=0;
					}
				}
  		     }
		}
		if(keyNumber==3)//S2按下  设置减减键
		{
			if(who==0)
			{
				if(min_hour_set==1)//分钟设置时间
				{
					if(min==0)
					{
						min=60;
					}
					min--;
				}
				if(min_hour_set==0)//小时设置状态
				{
					if(hour==0)
					{
						hour=24;
					}
					hour--;
				}
			}
			if(who==1)
			{
				if(clock_min_clock_hour_set==1)//时钟分钟设置状态
				{
					if(clock_min==0)
					{
						clock_min=60;
					}
					clock_min--;
				}
				if(clock_min_clock_hour_set==0)//时钟小时设置状态
				{
					if(clock_hour==0)
					{
						clock_hour=24;
					}
					clock_hour--;
				}
  		     }
		}
		if(clock_hour==hour&&clock_min==min)
		{
//			LED=0;
//			while(j--)//LED闪烁
//			{
//			 LED=~LED;
//			 Delay(1);
//			}
			while(i--)
			   {
				   BEEP=!BEEP;
				   Delay(1);
			   }
			   i=1000;
		}
	}
}
//定时器0中断函数模板
void Timer0_Routine() interrupt 1
{
	static unsigned int T0Count;
	TL0 = 0x18;		//设置定时初值
	TH0 = 0xFC;		//设置定时初值
	T0Count++;
	if(T0Count>=1000)
	{
		T0Count=0;
		if(Start==0)
		{	
			miao++;
			if(miao>=60)
			{
				min++;
				miao=0;
			}
			if(min>=60)
			{
				hour++;
				min=0;
			}
			if(hour>=24&&min==0)
			{
				hour=0;
			}
			Mode++;
			if(Mode>=2)
			{
				Mode=0;
			}

		}
	}
}

设计思路:

一个一个功能实现,但是要有自己的整体框架,不然后面会越敲越晕,因为都是嵌套的,这个跳到那个,没有系统的框图是不行的,我刚开始就没设计闹钟的那一块代码,所以定时器模块写完之后,突然加闹钟模块就很乱,思绪就没有了,后面就休息了,特别累的时候,想不明白的时候一定要好好休息,也许休息好了就会有灵感了,我就是休息之后,想到应该要设置两个界面显示。一个是闹钟界面,一个是时钟界面,通过按键来切换,

项目总结:

其实在设计的时候,我都是一步一步调试的,每写一段代码自己去找问题,去发现跟自己预期的是不是一样的。有问题就去找解决方案,确实这一个过程是极其费时间的,特别遇到一些bug,更会折磨人的心态,但是往往是这些问题,才会让我们更加去思考,

比如我在实现第一个功能时,就花了很多时间,也遇到了bug.

1.先实现第一个要求(wo当时第一步开始想的是这样的)

直接调用LCD1602模块和延时函数模块,下面是main函数代码

#include <REGX52.H>
#include "LCD1602.h"
#include "Delay.h"
unsigned char hour=12;
unsigned char min=18;

void main()
{
	LCD_Init();
	LCD_ShowNum(2,1,hour,2);
	LCD_ShowNum(2,4,min,2);
	LCD_ShowChar(2,3,':');
	while(1)
	{ 
		Delay(1000);
		LCD_ShowChar(2,3,' ');
		Delay(1000);
		LCD_ShowChar(2,3,':');
	}
}

虽然很好的实现了,但是后面又出现问题了。。。。。

但是配上定时器扫描后,就会让秒每隔2秒显示一次。 因为Delay了2秒,然而,定时器与CPU是分开工作的,虽然题目不对秒显示有要求,但是我觉得上面显示不妥,所以我把:的显示放在定时器中断里面,这样:就会按秒每加一而闪烁。 下面是代码。

#include <REGX52.H>
#include "LCD1602.h"
#include "Delay.h"
#include "MatrixKey"
#include "Timer0.h"
unsigned char hour=12;//小时位
unsigned char min=18;//分钟位  
unsigned char miao=0;   //秒位
unsigned char keyNumber;   //接收矩阵键盘的返回值
unsigned char Mode=0;  // :显示标志位

void main()
{
	Timer0Init();
	LCD_Init();
	LCD_ShowNum(2,1,hour,2);
	while(1)
	{ 
		LCD_ShowNum(2,4,min,2);
	    LCD_ShowNum(2,15,miao,2);
	}
}

//定时器0中断函数模板
void Timer0_Routine() interrupt 1
{
	static unsigned int T0Count;
	TL0 = 0x18;		//设置定时初值
	TH0 = 0xFC;		//设置定时初值
	T0Count++;
	if(T0Count>=1000)
	{
		T0Count=0;
		miao++;
		if(miao==60)
		{
			min++;
			miao=0;
		}
		if(Mode==0)
		{
		 LCD_ShowChar(2,3,':');
		}
		Mode++;
		if(Mode>=2)
		{
		 LCD_ShowChar(2,3,' ');
			Mode=0;
		}
	}
}

刚开始效果还是可以,但是把显示放在定时器中断中,就会出现bug.

在我完成第二个要求的时候。

2.实现第二个要求: 

第二个要求有点多,我们细分为5个小要求来完成。

要有5个功能键,独立按键只有四个,所以我选择矩阵键盘按键,(当然,你也可以选择独立按键,按一次是这个功能,按两次是另外一个功能,可以设置一个符号位,通过按键改变符号位,从而根据符号位不同来选择想要功能)

所以我矩阵键盘按键模块再次调用过来

1)设定键:在计时模式时,按下此键时停止计时,进入设置状态,并切换到分钟的设置状态,再按一次切换到小时的设置状态,每按下一次完成时.分设置的切换,用点亮时.分个位的数码管小数点表示分或秒处于设置状态。在闹钟时间设定状态时,按下此键同样进入设置状态,完成分、秒设置的切换。(我把这个键用矩阵键盘S1表示)

看到计时,肯定要计数器中断模块,我再把计时器中断调用过来。当然了,这个题只让显示分,小时,没有秒,所以我们设置一个变量来控制秒,秒=60时,min加一,min>60时,hour加一。

产生一个新的问题:我的LCD_ShowNum(2,1,hour,2);放在while循环里时,为了更新显示。为啥min显示后面总会出现一个0,或者一个奇怪的数字,我明明规定hour是两位显示啊,产生一个新的bug希望有人能帮我找到问题,上面的那个代码我没有放在while,没有更新显示,也没有出现min后面多个0;之前写的时钟都没问题的,按理说这个也没问题的。(bug)

为了解决上述问题,我把LCD_ShowNum(2,1,hour,2);放在了定时器中断中。(继续接连出现bug)

由于前面的bug,我把hour放在定时器中断中,暂停后,hour也不会更新显示,矛盾了,所以我还是放到了while(1)循环里更新显示了,bug还需要大家帮我解决啊,不然,看起来好别扭,

好奇怪,明明之前是坏的,写完矩阵键盘控制突然又好了。bug消失了,我觉得是单片机内部问题,可能你们应该不会遇到。但是为了想解决这个花了好多时间。(但是bug时好时坏)。

按下此键无法计时,所以我们又要设置一个标志位。Start=0; // 0为开始计时,1暂停计时,按下按键,Start=1,实现暂停。

切换到分钟的设置状态,再按一次,切换到小时的设置状态,(所以我们继续设置标志位,1为小时键,0位分钟位)切换是不是要调时间,我们顺道把第(2)(3)个要求完成。

(2)递增键:在设置状态时,按一次递增键,被设置的分钟数字或时钟数字增1,持续按下数字自动增1。(完成)(S2键)

(3)递减键:在设置状态时,按一次递减键,被设置的分钟数字或时钟数字减1,持续按下数字自动增1。(完成)  (S3键)

(4)计时键:在设置状态或闹钟时间设定状态时,按下此键则单片机切换到计时的显示模式,按照新的时.分设置值进行计时。如果已经在计时状态则此键无效。(S4键)(完成)

按下此键,进入计时状态,在设置状态或(闹钟时间设定状态)时,闹钟计时状态我们先不管,我还没做,

在设置状态时,我们不是把时和分设置好了。按下计时键,则单片机切换到计时的显示模式,按照新的时.分设置值进行计时。(所以这个键就是开始计时,因为之前暂停了。)如果已经在计时状态则此键无效。是不是要在Start==1,才能生效。

(5)闹钟键:在计时模式时,按下此键则单片机切换到闹钟时间设定状态的显示模式。等待“设定键”、“递增键”、“递减键”来设定分钟和秒钟。

在计时模式时,才能按下此按键,所以Start==0才能生效。进入闹钟模式是不是要回来,第四个要求,按下计时键回来

(这一部分的思路就完全错了)后面自己就再也没设计了。

第二天的时候,自己就从新开始构思,1s闪,为啥不用标志位去变呢1.以及后面遇到的问题,自己都一步一步去思考,去解决,

代码遇到的错误,中午括号

  • 22
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值