(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)
2019-6-2 00:11 上傳
點擊文件名下載附件
使用STC51單片機在1602上制作的電子鐘
下載積分: 黑幣 -5