单片机实验要求如下
合理使用STC单片机内的定时器资源,并使用1602实现数字钟的功能,显示方式xx:xx:xx(时:分:秒) 基本部分: 能在1602上以xx:xx:xx的形式显示时间,符合真实工作情况(40分) 提高部分: (1)能通过一个按键将1602切换到显示年月日,显示格式xx/xx/xx(年/月/日)(20分), (2)通过按键可以调整时、分、秒(30分) 发挥部分: 完善电子钟的功能(10分) 注: (1)设计的电子钟,使用最少的按键,按照电子表,对多使用3个按键。 (2)时钟工作时,其进位应该与真实的电子钟相同。 (3)显示时间和显示年月日之间的进位关系符合实际。
【思路】
(一)使用定时器0产生1秒的时钟信号,用来时钟走时,并达到24小时候进位到日期中的日,进而是月,年。通过if条件语句实现了瑞年的处理,月份天数不一致的处理。
(二)总共使用了两个按键。通过外部中断0,切换到显示日期,并且记录外部中断0触发的次数,通过次数进入调整状态,时间和日期均可以调整。通过外部中断0进入调整状态后,再通过外部中断1调整时间和日期,日期和时间的调整采用了加满溢出的方式。在日期的调整过程中,不会出现13月 35日等非正常逻辑的显示结果。
(三)完善电子钟的部分,日期也可以调整,整点报时(由于板子上没有蜂鸣器,采用了两个LED表示)。
【运行说明】 (1)进入时间显示状态,默认值为00:00:00 (2)通过外部中断0进入日期显示状态,默认值为2019/05/26。 (3)再次按下外部中断0进入时间调整状态,修改时间的小时的十位,并通过在第二行的^作为修改位标志。 (4)之后类似,此步展示日期修改的年的个位。 (5)完成所有的调整后,再次按下外部中断0,会再次进入时间的显示状态。 【答题过程遇到的问题说明】 (1)调整的部分,如果代码放的位置不合适,调表会有不合理的现象发生,并且需要将调表所用的外部中断1优先级大于定时器中断。 (2)尝试过用闪烁和光标作为修改位的指示,但是很容易发生混乱,就采用了在第二行,用合适的字符指示修改的位。 (3)最初的想法,是想调用矩阵键盘的两个键作为加减,后来在调试的过程中,发现有干扰,因为LCD1602和矩阵键盘都用到了P0口,所以当矩阵键盘被按下的时候,会对1602的显示造成干扰,所以之后的方案,取消了减,只采用了两个外部中断的按键。 (4)为了使时间和日期的显示和调整符合真正的电子钟,要花费一定的精力调整代码。 【源代码及注释】 注:文档中的代码只有主程序main.c,别的头文件及.c文件在工程文件夹内。
单片机源程序如下:
- #include "reg51.h"
- #include "led1602.h"
- #define uchar unsigned char
- #define uint unsigned int
- sfr P4=0xc0;
- int year=2019;//初始显示日期的年
- uchar month=05,day=26,sec = 0, min = 0, hou = 0;//初始显示日期为 2019年05月26日,初始显示时间为00:00:00
- uchar num = 0;//调整日期和时间,以及切换显示日期和时间的标志位
- uchar time = 0;//一秒的时间信号
- uchar jia=0;//调整日期和时间的信号
- sbit P46=P4^6;//闹钟(整点报时)的两个灯
- sbit P47=P4^7;
- void time_rec();//时钟走时函数
- void init();//程序初始化函数,包括LCD的初始化,中断的设置,定时器的TH TL设置
- void write_liangwei(uchar add,uchar date);//两位字符分离函数
- void write_siwei(uchar add1,int date1);//四位字符分离函数
- void show_time();//时间显示函数
- void show_dat();//日期显示函数
- void main()
- {
- init();
- while(1){
- time_rec();//调用时钟走时函数
- if(num == 0)//显示时间
- {
- lcdshowstr(0,1," ");
- show_time();
- }
- if(num==1)//显示日期
- {
- lcdshowstr(0,1," ");
- show_dat();
- jia = 0;
- }
- if(num == 2)//显示时间的同时,修改时间的小时的十位
- {
- lcdshowstr(0,1,"^");
- show_time();
- jia = 0;
- }
- if(num == 3)//显示时间的同时,修改时间的小时的个位,以下类似
- {
- lcdshowstr(0,1," ^");
- show_time();
- jia = 0;
- }
- if(num == 4)
- {
- lcdshowstr(0,1," ^");
- show_time();
- jia = 0;
- }
- if(num == 5)
- {
- lcdshowstr(0,1," ^");
- show_time();
- jia = 0;
- }
- if(num == 6)
- {
- lcdshowstr(0,1," ^");
- show_time();
- jia = 0;
- }
- if(num == 7)
- {
- lcdshowstr(0,1," ^");
- show_time();
- jia = 0;
- }
- if(num == 8)
- {
- lcdshowstr(0,1,"^ ");
- show_dat();
- jia = 0;
- }
- if(num == 9)
- {
- lcdshowstr(0,1," ^ ");
- show_dat();
- jia = 0;
- }
- if(num == 10)
- {
- lcdshowstr(0,1," ^ ");
- show_dat();
- jia = 0;
- }
- if(num == 11)
- {
- lcdshowstr(0,1," ^ ");
- show_dat();
- jia = 0;
- }
- if(num == 12)
- {
- lcdshowstr(0,1," ^ ");
- show_dat();
- jia = 0;
- }
- if(num == 13)
- {
- lcdshowstr(0,1," ^ ");
- show_dat();
- jia = 0;
- }
- if(num == 14)
- {
- lcdshowstr(0,1," ^ ");
- show_dat();
- jia = 0;
- }
- if(num == 15)
- {
- lcdshowstr(0,1," ^ ");
- show_dat();
- jia = 0;
- }
- }
- }
- void zhuangtai() interrupt 0 //外部中断0 用于校准时间在时、分、秒之间进行切换
- {
- num = num + 1;
- if(num == 16)
- {
- num = 0;
- }
- }
- void timer0() interrupt 1 //定时器0的中断子函数 用来产生1秒的时间,用于时钟走时
- {
- TH0 = 0x3C;
- TL0 = 0xB0;
- time++;
- if(time == 20)
- {
- sec++;
- time = 0;
- }
- }
- void jiaozhun() interrupt 2 //外部中断1用来调整时间、日期
- {
- jia = 1;
- if(num == 2)
- {
- hou = hou + 10;
- if((hou%10<4)&&hou>24)
- {
- hou = hou - 30;
- }
- if((hou%10>4)&&hou>24)
- {
- hou = hou - 20;
- }
- if(hou==24)
- {
- hou = hou - 20;
- }
- }
- if(num==3)
- {
- hou = hou + 1;
- if(hou>23)
- hou = 0;
- }
- if(num==4)
- {
- min = min+10 ;
- if(min > 59)
- {
- min = min -60;
- }
- }
- if(num==5)
- {
- min= min+1;
- if(min>59)
- {
- min = 0;
- }
- }
- if(num==6 )
- {
- sec=sec + 10;
- if(sec >59 )
- {
- sec = sec - 60;
- }
- }
- if(num==7)
- {
- sec= sec+1;
- if(sec>59)
- {
- sec = 0;
- }
- }
- if(num==8)
- {
- year= year+1000;
- if(year>9000)
- {
- year = year -10000;
- }
- }
- if(num==9)
- {
- year=year+100;
- if(year%1000/100>9)
- {
- year = year - 1000;
- }
- }
- if(num==10)
- {
- year=year+10;
- if(year%100/10>9)
- {
- year = year -100;
- }
- }
- if(num==11)
- {
- year=year+1;
- if(year%10>9)
- {
- year = year - 10;
- }
- }
- if(num==12)
- {
- month = month +10;
- if((month%10<2)&&month>12)
- {
- month = month - 20;
- }
- if((month%10>2)&&month>12)
- {
- month = month - 10;
- }
- if(month==12)
- {
- month = month - 10;
- }
- }
- if(num==13)
- {
- month = month +1;
- if(month%10>9)
- {
- month = 0;
- }
- if(month==12)
- {
- month = 0;
- }
- }
- if(num==14)
- {
- day = day +10;
- if(month==1||month==3||month==5||month==7||month==8||month==10||month==12)
- {
- if((day%10<1)&&day>31)
- {
- day = day - 40;
- }
- if((day%10>1)&&day>31)
- {
- day = day - 30;
- }
- if(day==31)
- {
- day = 0;
- }
- }
- if(month==4||month==6||month==9||month==11)
- {
- if(day>30)
- {
- day = day - 40;
- }
- }
- if(((year%4==0&&year%100!=0)||(year%400==0))&&month==2)
- {
- if(day>29)
- {
- day = day - 30;
- }
- }
- if(year%4!=0&&month==2)
- {
- if(day>28)
- {
- day = day -30;
- }
- }
- }
- if(num==15)
- {
- day = day +1;
- if((month==1||month==3||month==5||month==7||month==8||month==10||month==12)&&day>31)
- {
- day = 0;
- }
- if((month==4||month==6||month==9||month==11)&&day>30)
- {
- day = 0;
- }
- if(((year%4==0&&year%100!=0)||(year%400==0))&&day>29)
- {
- day = 0;
- }
- if((year%4!=0)&&day>28)
- {
- day = 0;
- }
- }
- }
- /*
- *时间走时函数,计满24小时后,日加一
- *并且设置了整点报时,或者说闹钟功能
- *由于单片机没有蜂鸣器,采用两个LED作为表示
- *LED亮一分钟后自动熄灭
- */
- void time_rec()
- {
- if(sec == 60)
- {
- P46 = 1;
- P47 = 1;
- sec = 0;
- min ++;
- if(min ==60)
- {
- P46 = 0;
- P47 = 0;
- min = 0;
- hou++;
- if(hou==24)
- {
- hou = 0;
- day++;
- if((year%4==0&&year%100!=0)||(year%400==0))//判断是否为闰年的2月
- {
- if(day==30)
- {
- day=0;
- month++;
- if(month==13)
- {
- month=0;
- year++;
- }
- }
- }
- if(year%4!=0&&month==2)
- {
- if(day==29)
- {
- day=0;
- month++;
- if(month==13)
- {
- month=0;
- year++;
- }
- }
- }
- if(month!=2&&month!=4&&month!=6&&month!=9&&month!=11)
- {
- if(day==32)
- {
- day=0;
- month++;
- if(month==13)
- {
- month=0;
- year++;
- }
- }
- }
- if(month==4||month==6||month==9||month==11)
- {
- {
- day=0;
- month++;
- if(month==13)
- {
- month=0;
- year++;
- }
- }
- }
-
- }
- }
- }
- }
- /*
- *初始化函数,包括LCD1602初始化
- *中断的开启,优先级的设置
- *定时器的工作方式,计算初值等。
- */
- void init()
- {
- P0M0=0;
- P0M1=0;
- P2M0=0;
- P2M1=0;
- lcdwait();
- lcdinit();
- ET0 = 1;
- EX0 = 1; //外部中断0允许
- EX1 = 1; //外部中断1允许
- PX1 = 0; //调整外部中断1的优先级
- PT0 = 1; //调整定时器0中断优先级
- IT1 = 1;
- TMOD = 0x01; //time0为定时器,方式1
- TH0 = 0x3C;//(65535 - 50000) / 256; //预置计算初值
- TL0 = 0xB0;//(65535 - 50000) % 256;
- IT0 = 1; //低电平有效
- TR0 = 1; //为1时启动计数
- EA = 1;
- }
- /*
- *字符分离函数
- *将两位的字符分离出十位和个位
- */
- void write_liangwei(uchar add,uchar date)
- {
- uchar shi,ge;
- shi=date/10;//分解一个2位数的十位和个位
- ……………………
- …………限于本文篇幅 余下代码请从51黑下载附件…………
复制代码
所有资料51hei提供下载:
51单片机实验_在1602上制作电子钟(包含日期).rar
(227.01 KB, 下载次数: 84)
具体的思路和过程在压缩包里。 压缩包包含工程文件和实验报告。
|