|
用單片機(jī)制作最高精度時(shí)間系統(tǒng),可移植到任何時(shí)鐘程序中
可移植到任何數(shù)字時(shí)鐘程序中,根據(jù)單片機(jī)型號以及晶振頻率修改TH0和TL0的值。
智能日期時(shí)間累加,平閏年判斷,當(dāng)月天數(shù)判斷功能,年計(jì)數(shù)值0~9999。
使用1秒的延遲函數(shù),再加上時(shí)間判斷計(jì)數(shù)函數(shù)的時(shí)間,誤差非常大。
采用5毫秒定時(shí)器中斷計(jì)數(shù),中斷觸發(fā)后重置計(jì)數(shù)值并且5毫秒計(jì)數(shù)加1。
處理5毫秒計(jì)數(shù)以及時(shí)間判斷計(jì)數(shù)函數(shù),定時(shí)器仍在計(jì)數(shù),準(zhǔn)確觸發(fā)高精度的5毫秒中斷。
5毫秒計(jì)數(shù)加到200時(shí),5毫秒計(jì)數(shù)清零并且觸發(fā)時(shí)間計(jì)數(shù)函數(shù),包含所有判斷日期時(shí)間的指令在5毫
秒內(nèi)完成,如5毫秒內(nèi)無法完成請改成更長毫秒時(shí)間中斷1次,避免出現(xiàn)中斷重入等問題。
若發(fā)現(xiàn)bug或其他建議意見請及時(shí)在樓下回復(fù)。
下面是源碼:
- #include "reg51.h"
- #include "intrins.h"
- sfr AUXR = 0x8E;
- sbit led=P3^2; //秒閃爍指示燈
- #define ui unsigned int
- #define uc unsigned char
- ui y; //定義變量年
- uc m,d,h,i,s,w; //定義變量月、日、時(shí)、分、秒、周
- uc ms5; //5毫秒定時(shí)器中斷計(jì)數(shù)
- void InitTimer0(void){ //初始化5毫秒定時(shí)器,根據(jù)晶振頻率修改TH0和TL0的值。
- TMOD = 0x01;
- TH0 = 0x28;
- TL0 = 0x00;
- EA = 1;
- ET0 = 1;
- TR0 = 1;
- }
- bit if_leap_year(ui y){ //平閏年檢測,閏年返回1,平年返回0
- //閏年是4的倍數(shù)且不是100的倍數(shù)或者是400的倍數(shù),否則是平年。
- if((y%4 == 0 && y%100 != 0) || y%400 == 0){
- return 1; //返回1表示閏年
- } else { //否則就是平年
- return 0; //返回0表示平年
- }
- }
- uc get_mon_day_nbr(ui y,uc m){ //通過年月獲取該月有多少天
- if(m == 1 || m == 3 || m == 5 || m == 7 || m == 8 || m == 10 || m == 12) { //大
- 月則31天
- return 31;
- }
- if(m == 4 || m == 6 || m == 9 || m == 11){ //小月則30天
- return 30;
- }
- if(m == 2){ //2月
- if(if_leap_year(y) == 1){ //閏年29天
- return 29;
- } else { //平年28天
- return 28;
- }
- }
- return 0;
- }
- bit dt_is_ok(ui y,uc m,uc d,uc w,uc h,uc i,uc s){ //檢測設(shè)置的日期時(shí)間格式是否有效 1有
- 效0無效
- if(w > 7 || w < 1) return 0; //星期大于7或小于1 返回0
- if(y > 9999 || m > 12 || m < 1 || d < 1) return 0; //年大于999 或 月大于12 或
- 月小于1 或日小于1 返回0
- if(d > get_mon_day_nbr(y,m)) return 0; //通過年月獲取當(dāng)月天數(shù) 大于該值 返回0
- if(h > 23 || i > 59 || s > 59) return 0; //時(shí)大于23 或 分大于59 或秒大于59 返回
- 0
- return 1; //檢測有效 返回1
- }
- bit set_time(ui yy,uc mm,uc dd,uc ww,uc hh,uc ii,uc ss){ //設(shè)置日期時(shí)間
- if(dt_is_ok(yy,mm,dd,ww,hh,ii,ss) == 1){ //檢查日期時(shí)間格式有效
- y=yy;m=mm;d=dd;w=ww; //設(shè)置年月日周
- h=hh;i=ii;s=ss; //設(shè)置時(shí)分秒
- return 1; //設(shè)置成功 返回1
- } else { //格式無效 返回0
- return 0;
- }
- }
- void add_time(){ //時(shí)間步進(jìn)1秒
- s++; //秒加1
- if(s>=60){ //秒加到60
- s=0; //秒清零
- i++; //分加1
- if(i>=60){ //分加到60
- i=0; //分清零
- h++; //時(shí)加1
- if(h>=24){ //時(shí)加到24
- h=0; //時(shí)清零
- d++; //日加1
- w++; //星期加1
- if(w > 7){ //星期超過7
- w=1; //星期等于1
- }
- if(d > get_mon_day_nbr(y,m)){ //日超過當(dāng)前年月的天數(shù)
- d=1; //日清1
- m++; //月加1
- if(m > 12){ //月加到12以上
- m=1; //月清1
- y++; //年加1
- if(y >= 10000){ //年加到10000
- y=0; //年清零
- }
- }
- }
- }
- }
- }
- }
- void main(){ //入口函數(shù),上電復(fù)位后在此開始執(zhí)行指令。
- P3=0xFF; //設(shè)置P3口全部為高電平
- set_time(2000,1,1,6,0,0,0); //設(shè)置日期時(shí)間
- AUXR |= 0x80; //關(guān)閉定時(shí)器0的12分頻
- InitTimer0(); //初始化5毫秒定時(shí)器
- //死循環(huán)內(nèi)可添加其他程序,只有中斷觸發(fā)后退出,中斷返回后繼續(xù)在原地運(yùn)行程序。
- while(1);
- }
- void Timer0Interrupt(void) interrupt 1{ //5毫秒定時(shí)器中斷
- //重置TH0與TL0的值,根據(jù)晶振頻率修改TH0和TL0的值。
- TH0 = 0x28;
- TL0 = 0x00;
- ms5++; //5毫秒中斷計(jì)數(shù)加1
- if(ms5%100 == 0)led=~led;
- //5毫秒中斷計(jì)數(shù)加到200 200*5=1000毫秒 1秒觸發(fā)1次
- if(ms5 >= 200){
- ms5=0; //5毫秒計(jì)數(shù)清零
- add_time(); //時(shí)間步進(jìn)1秒
- }
-
- }
復(fù)制代碼
|
評分
-
查看全部評分
|