题目要求:
审题时这个题是用数码管来显示的,数码管显示时钟我完成了一个,只是要求跟他不一样,所以这次想用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.以及后面遇到的问题,自己都一步一步去思考,去解决,
代码遇到的错误,中午括号