#include<reg52.h> //頭文件 #include<LCD1602.h> #include<DS1302.h> #include<AT24C02.h> #include<INTERRUPT.h> #define uchar unsigned char//宏定義 #define uint unsigned int /***********************引腳定義***********************/ sbit key_mode = P1^0; //設(shè)置鍵 sbit key_jia = P1^1; //加鍵 sbit key_jian = P1^2; //減鍵 sbit key_ok = P1^3; //確定鍵/切換秒表 sbit key_dao = P1^4; //切換倒計時 sbit led = P2^4; //LED燈 /***********************變量定義***********************/ uchar set_f=0; //設(shè)置選擇標(biāo)記,=0非設(shè)置,=1設(shè)置年,=2設(shè)置月,=3設(shè)置日。=4設(shè)置時,=5設(shè)置分,=6設(shè)置秒 // =7設(shè)置鬧鐘-時,=8設(shè)置鬧鐘-分。=9設(shè)置鬧鐘秒,=10設(shè)置鬧鐘-開關(guān),=11整點報時-開關(guān) uchar set_dao=0; //倒計時設(shè)置標(biāo)記 uchar num; //計數(shù)變量 uchar naozhong[5]; //鬧鐘-秒、鬧鐘-分、鬧鐘-時、鬧鐘-開關(guān)、整點報時-開關(guān) bit baoshi_f=0; //報時標(biāo)記位,=1整點報時 bit naozhong_f=0; //鬧鐘開始標(biāo)記位,=1鬧鐘開始,=0鬧鐘未開始 /******************************************************** 函數(shù)名稱:void delayms(uint ms) 函數(shù)作用:毫秒延時函數(shù) 參數(shù)說明: ********************************************************/ void delayms(uint ms) { unsigned char i=100,j; for(;ms;ms--) { while(--i) { j=10; while(--j); } } } /******************************************************** 函數(shù)名稱:void baoshi(uchar i) 函數(shù)作用:整點報時函數(shù) 參數(shù)說明:I為蜂鳴器響的次數(shù) ********************************************************/ void baoshi(uchar i) { uchar j; for(j=0;j<i;j++)//循環(huán)i次 { buzz=0; //蜂鳴器鳴叫 led=0; //LED燈點亮 delayms(20);//延時 buzz=1; //關(guān)閉蜂鳴器鳴叫 led=1; //關(guān)閉LED燈 delayms(20);//延時 } } /******************************************************** 函數(shù)名稱:void display(void) 函數(shù)作用:正常顯示日期、時間函數(shù) 參數(shù)說明: ********************************************************/ void display(void) { uchar xq; //存儲星期 uchar temp2[2]; //存儲鬧鐘結(jié)束時間 //判斷整點報時 if(time[0]<3&&time[1]==0&&baoshi_f==0)//判斷是否為整點 { baoshi_f=1; //標(biāo)記整點報時開啟 if(naozhong[4]%2==1) //如果整點報時開關(guān)有打開 { if(time[2]%12==0) //根據(jù)當(dāng)前時間,控制蜂鳴器鳴叫次數(shù) baoshi(12); else baoshi(time[2]%12); } } if(time[0]>10&&time[1]==0) //整點報時結(jié)束 baoshi_f=0; //重置整點報時標(biāo)志 //計算鬧鐘結(jié)束【時間】 if(naozhong[1]!=59) //鬧鐘-分 不等于59分 【例:11:11】 { temp2[0]=naozhong[2]; //鬧鐘結(jié)束時間為:小時不變,分鐘+1 temp2[1]=naozhong[1]+1; } else //鬧鐘-分 等于59分 { if(naozhong[2]!=23) //鬧鐘-時 不等于23時 【例:11:59】 { temp2[0]=naozhong[2]+1;//鬧鐘結(jié)束時間為:小時加1,分鐘=0 temp2[1]=0; } else //鬧鐘-時 等于23時 【例:23:59】 { temp2[0]=0; //鬧鐘結(jié)束時間為:小時=0,分鐘=0 temp2[1]=0; } } if(time[2]==naozhong[2]&&time[1]==naozhong[1]&&time[0]==naozhong[0]&&naozhong[3]%2==1)//判斷當(dāng)前是否為鬧鐘時間 { buzz=0; //開啟鬧鈴,蜂鳴器鳴叫、LED燈點亮 led=0; naozhong_f=1; //標(biāo)記鬧鐘開啟 } if(time[2]==temp2[0]&&time[1]==temp2[1]&&time[0]==naozhong[0]&&naozhong[3]%2==1) //判斷鬧鐘一分鐘是否結(jié)束 { buzz=1; //關(guān)閉鬧鈴,蜂鳴器停止、LED燈關(guān)閉 led=1; naozhong_f=0; //重置鬧鐘開啟標(biāo)志 } xq=GetWeekDay(time[6],time[4],time[3]);//獲取星期 //顯示星期 switch(xq) { case 1:lcd1602_write_character(11,2,"Mon"); break; case 2:lcd1602_write_character(10,2,"Tues"); break; case 3:lcd1602_write_character(9,2,"Wednes"); break; case 4:lcd1602_write_character(10,2,"Thurs"); break; case 5:lcd1602_write_character(10,2,"Frid"); break; case 6:lcd1602_write_character(10,2,"Satur"); break; case 7:lcd1602_write_character(11,2,"Sun"); break; default: break; } //顯示時間 //12小時制 LCD_disp_char(0,2,ASCII[time[2]%12/10]);//顯示時【0:表示第1列,2:表示第2行,所有關(guān)于顯示都一樣】 LCD_disp_char(1,2,ASCII[time[2]%12%10]);//*/ //24小時制 /*LCD_disp_char(0,2,ASCII[time[2]/10]);//顯示時【0:表示第1列,2:表示第2行,所有關(guān)于顯示都一樣】 LCD_disp_char(1,2,ASCII[time[2]%10]); //*/ LCD_disp_char(2,2,':'); LCD_disp_char(3,2,ASCII[time[1]/10]); //顯示分 LCD_disp_char(4,2,ASCII[time[1]%10]); LCD_disp_char(5,2,':'); LCD_disp_char(6,2,ASCII[time[0]/10]); //顯示秒 LCD_disp_char(7,2,ASCII[time[0]%10]); if(time[2]/12==0) //小于12小時,判斷為上午 lcd1602_write_character(11,1,"AM"); else //否者,下午 lcd1602_write_character(11,1,"PM"); //顯示日期 LCD_disp_char(0,1,ASCII[time[6]/10]);//顯示年 LCD_disp_char(1,1,ASCII[time[6]%10]); LCD_disp_char(2,1,'/'); LCD_disp_char(3,1,ASCII[time[4]/10]);//顯示月 LCD_disp_char(4,1,ASCII[time[4]%10]); LCD_disp_char(5,1,'/'); LCD_disp_char(6,1,ASCII[time[3]/10]);//顯示日 LCD_disp_char(7,1,ASCII[time[3]%10]); } /******************************************************** 函數(shù)名稱:void display2(void) 函數(shù)作用:顯示調(diào)整日期、時間函數(shù) 參數(shù)說明: ********************************************************/ void display2() { num++; lcd1602_write_character(1,1,"Date:"); lcd1602_write_character(1,2,"Time:"); if(num%2==0) ////偶數(shù)次顯示,奇數(shù)次不顯示。這樣就會有閃爍效果,可以清楚看到當(dāng)前設(shè)置的是哪個值 { LCD_disp_char(6,1,ASCII[time[6]/10]); //顯示年 LCD_disp_char(7,1,ASCII[time[6]%10]); LCD_disp_char(8,1,'/'); LCD_disp_char(9,1,ASCII[time[4]/10]); //顯示月 LCD_disp_char(10,1,ASCII[time[4]%10]); LCD_disp_char(11,1,'/'); LCD_disp_char(12,1,ASCII[time[3]/10]);//顯示日 LCD_disp_char(13,1,ASCII[time[3]%10]); LCD_disp_char(6,2,ASCII[time[2]/10]); //顯示時 LCD_disp_char(7,2,ASCII[time[2]%10]); LCD_disp_char(8,2,':'); LCD_disp_char(9,2,ASCII[time[1]/10]); //顯示分 LCD_disp_char(10,2,ASCII[time[1]%10]); LCD_disp_char(11,2,':'); LCD_disp_char(12,2,ASCII[time[0]/10]);//顯示秒 LCD_disp_char(13,2,ASCII[time[0]%10]); } else //奇數(shù)次不顯示 { switch(set_f)//根據(jù)當(dāng)前設(shè)置的內(nèi)容,對應(yīng)位置閃爍 { case 1: lcd1602_write_character(6,1," "); break; case 2: lcd1602_write_character(9,1," "); break; case 3: lcd1602_write_character(12,1," "); break; case 4: lcd1602_write_character(6,2," "); break; case 5: lcd1602_write_character(9,2," "); break; case 6: lcd1602_write_character(12,2," "); break; default: break; } } } /******************************************************** 函數(shù)名稱:void display3(void) 函數(shù)作用:顯示調(diào)整鬧鐘函數(shù) 參數(shù)說明: ********************************************************/ void display3() { num++; lcd1602_write_character(3,1,"Alarm clock"); if(num%2==0) ////偶數(shù)次顯示,奇數(shù)次不顯示。這樣就會有閃爍效果,可以清楚看到當(dāng)前設(shè)置的是哪個值 { LCD_disp_char(2,2,ASCII[naozhong[2]/10]);//顯示鬧鐘-時 LCD_disp_char(3,2,ASCII[naozhong[2]%10]); LCD_disp_char(4,2,':'); LCD_disp_char(5,2,ASCII[naozhong[1]/10]);//顯示鬧鐘-分 LCD_disp_char(6,2,ASCII[naozhong[1]%10]); LCD_disp_char(7,2,':'); LCD_disp_char(8,2,ASCII[naozhong[0]/10]);//顯示鬧鐘-秒 LCD_disp_char(9,2,ASCII[naozhong[0]%10]); if(naozhong[3]%2==0) lcd1602_write_character(11,2,"OFF"); //顯示鬧鐘-開/關(guān) else lcd1602_write_character(11,2,"ON"); } else //奇數(shù)次不顯示 { switch(set_f)//根據(jù)當(dāng)前設(shè)置的內(nèi)容,對應(yīng)位置閃爍 { case 7: lcd1602_write_character(2,2," "); break; case 8: lcd1602_write_character(5,2," "); break; case 9: lcd1602_write_character(8,2," "); break; case 10: lcd1602_write_character(11,2," "); break; default: break; } } } /******************************************************** 函數(shù)名稱:void display4(void) 函數(shù)作用:顯示調(diào)整整點報時開關(guān)函數(shù) 參數(shù)說明: ********************************************************/ void display4() { num++; lcd1602_write_character(2,1,"On time alarm"); if(num%2==0) //偶數(shù)次顯示,奇數(shù)次不顯示。這樣就會有閃爍效果,可以清楚看到當(dāng)前設(shè)置的是哪個值 { if(naozhong[4]%2==0) //顯示設(shè)置整點報時-開/關(guān) lcd1602_write_character(7,2,"OFF"); else lcd1602_write_character(7,2,"ON"); } else //奇數(shù)次不顯示 lcd1602_write_character(7,2," "); //顯示空格 } /******************************************************** 函數(shù)名稱:void display5(void) 函數(shù)作用:顯示秒表計時函數(shù) 參數(shù)說明: ********************************************************/ void display5() { lcd1602_write_character(0,1,"Seconds counter"); LCD_disp_char(4,2,ASCII[fens/100]); //顯示秒表-分 LCD_disp_char(5,2,ASCII[fens%100/10]); LCD_disp_char(6,2,ASCII[fens%10]); LCD_disp_char(7,2,':'); LCD_disp_char(8,2,ASCII[times/10]); //顯示秒表-秒 LCD_disp_char(9,2,ASCII[times%10]); LCD_disp_char(10,2,'.'); LCD_disp_char(11,2,ASCII[T0_num/2]); //顯示秒表-分秒 } /******************************************************** 函數(shù)名稱:void display6() 函數(shù)作用:倒計時顯示函數(shù) 參數(shù)說明: ********************************************************/ void display6() { lcd1602_write_character(1,1,"The countdown"); LCD_disp_char(4,2,ASCII[fens/100]); //顯示倒計時-分 LCD_disp_char(5,2,ASCII[fens%100/10]); LCD_disp_char(6,2,ASCII[fens%10]); LCD_disp_char(7,2,':'); LCD_disp_char(8,2,ASCII[times/10]); //顯示倒計時-秒 LCD_disp_char(9,2,ASCII[times%10]); LCD_disp_char(10,2,'.'); LCD_disp_char(11,2,ASCII[T0_num/2]); //顯示倒計時-分秒 } /******************************************************** 函數(shù)名稱:void display7() 函數(shù)作用:倒計時設(shè)置顯示函數(shù) 參數(shù)說明: ********************************************************/ void display7() { num++; lcd1602_write_character(1,1,"The countdown"); if(num%2==0) //偶數(shù)次顯示,奇數(shù)次不顯示。這樣就會有閃爍效果,可以清楚看到當(dāng)前設(shè)置的是哪個值 { LCD_disp_char(4,2,ASCII[fens/100]); //顯示設(shè)置倒計時-分 LCD_disp_char(5,2,ASCII[fens%100/10]); LCD_disp_char(6,2,ASCII[fens%10]); LCD_disp_char(7,2,':'); LCD_disp_char(8,2,ASCII[times/10]); //顯示設(shè)置倒計時-秒 LCD_disp_char(9,2,ASCII[times%10]); LCD_disp_char(10,2,'.'); LCD_disp_char(11,2,ASCII[T0_num/2]); //顯示設(shè)置倒計時-分秒 } else //奇數(shù)次不顯示 { switch(set_dao)//根據(jù)當(dāng)前設(shè)置的內(nèi)容,對應(yīng)位置閃爍 { case 1: lcd1602_write_character(4,2," "); break; case 2: lcd1602_write_character(8,2," "); break; case 3: lcd1602_write_character(11,2," "); break; default: break; } } } /******************************************************** 函數(shù)名稱:void scan(void) 函數(shù)作用:按鍵查詢處理函數(shù) 參數(shù)說明: ********************************************************/ void scan(void) { //設(shè)置鍵 if(key_mode==0) //按鍵按下 { delayms(7); //延時消抖 if(key_mode==0) //再次確認(rèn)按鍵按下 { if(miaobiao_f==0&&dao_f==0)//非秒表/非倒計時模式 { buzz=1; //進(jìn)入設(shè)置關(guān)閉鬧鐘聲光提示 led=1; if(set_f==0||set_f==6||set_f==10) //進(jìn)入設(shè)置先清除屏幕,顯示設(shè)置部分 { Writeds1302 (WRITE_PROTECT,0X00); //禁止DS1302寫保護(hù) LCD_write_command(0x01); //清除屏幕顯示 delay_n40us(100); //延時等待全部清除完畢 } set_f++; //設(shè)置變量+1 if(set_f>11) //全部設(shè)置完成,退出設(shè)置 { set_f=0; //重置設(shè)置變量 AT24C02_write_date(0,naozhong[0]);//寫入【鬧鐘-秒】數(shù)據(jù)保存 AT24C02_write_date(1,naozhong[1]);//寫入【鬧鐘-分】數(shù)據(jù)保存 AT24C02_write_date(2,naozhong[2]);//寫入【鬧鐘-時】數(shù)據(jù)保存 AT24C02_write_date(3,naozhong[3]);//寫入【鬧鐘-開關(guān)】數(shù)據(jù)保存 AT24C02_write_date(4,naozhong[4]);//寫入【整點報時-開關(guān)】數(shù)據(jù)保存 Writeds1302 (WRITE_MINUTE,(time[1]/10)*16+time[1]%10);//將設(shè)置好的時間寫入DS1302 Writeds1302 (WRITE_SECOND,(time[0]/10)*16+time[0]%10); LCD_write_command(0x01); //清除屏幕顯示 delay_n40us(100); //延時等待全部清除完畢 } } else //否則,秒表模式或者倒計時模式 { if(set_dao==0) //如果,非倒計時設(shè)置起始時間狀態(tài)下 TR0=~TR0; //切換 秒表計時或倒計時-開始/暫停 } } while(!key_mode); //等待按鍵松開 } //確定 if(key_ok==0) //按鍵按下 { delayms(7); //延時消抖 if(key_ok==0&&set_f!=0)//再次確認(rèn)按鍵按下,并且當(dāng)前處于設(shè)置模式 { set_f=0; //重置設(shè)置變量 AT24C02_write_date(0,naozhong[0]);//寫入【鬧鐘-秒】數(shù)據(jù)保存 AT24C02_write_date(1,naozhong[1]);//寫入【鬧鐘-分】數(shù)據(jù)保存 AT24C02_write_date(2,naozhong[2]);//寫入【鬧鐘-時】數(shù)據(jù)保存 AT24C02_write_date(3,naozhong[3]);//寫入【鬧鐘-開關(guān)】數(shù)據(jù)保存 AT24C02_write_date(4,naozhong[4]);//寫入【整點報時-開關(guān)】數(shù)據(jù)保存 Writeds1302 (WRITE_MINUTE,(time[1]/10)*16+time[1]%10);//將設(shè)置好的時間寫入DS1302 Writeds1302 (WRITE_SECOND,(time[0]/10)*16+time[0]%10); LCD_write_command(0x01); //清除屏幕顯示 delay_n40us(100); //延時等待全部清除完畢 } else if(key_ok==0&&naozhong_f==1) //否則,當(dāng)前鬧鐘響起,進(jìn)入暫停鬧鐘 { buzz=1; //關(guān)閉蜂鳴器 led=1; //熄滅LED燈 } else if(key_ok==0&&set_f==0&&dao_f==0)//否者,切換秒表模式和正常模式 { miaobiao_f=~miaobiao_f; //切換秒表模式和正常模式 LCD_write_command(0x01); //清除屏幕顯示 delay_n40us(100); //延時等待全部清除完畢 if(miaobiao_f==0) //退出秒表模式時,關(guān)閉秒表計時 { TR0=0; //關(guān)閉定時器 T0_num=0; //重置所有秒表的時間 times=0; fens=0; } AT24C02_write_date(5,miaobiao_f);//寫入【秒表標(biāo)志】數(shù)據(jù)保存 } else if(dao_f==1) //否者,倒計時模式 { if(buzz==0) //如果蜂鳴器響 buzz=1; //先關(guān)閉蜂鳴器 else //否者 { if(set_dao==0||set_dao==3) { LCD_write_command(0x01);//清除屏幕顯示 delay_n40us(100); //延時等待全部清除完畢 } set_dao++; //倒計時起始時間設(shè)置標(biāo)志+1 if(set_dao==4) //全部設(shè)置完成 set_dao=0; //重置倒計時起始時間設(shè)置標(biāo)志 } } while(!key_ok); //等待按鍵松開 } //加鍵 if(key_jia==0) { delayms(7); if(key_jia==0&&set_f!=0) { if(set_f==1) //設(shè)置年 { time[6]++; //年份+1 time[6]=(time[6]/10)*16+time[6]%10; //將年份轉(zhuǎn)換成16進(jìn)制,例如:16年-->0x16 if(time[6]>0x79) //判斷是否達(dá)到最大年份79年 time[6]=0x00; //重新回到00年 Writeds1302 (WRITE_YEA,time[6]); //將設(shè)置好的年份寫入到DS1302存儲起來 time[6]=Read1302(0x8d); //讀取當(dāng)前年份 } if(set_f==2) //設(shè)置月 { time[4]++; //月份+1 time[4]=(time[4]/10)*16+time[4]%10; //將月份轉(zhuǎn)換成16進(jìn)制,例如:08月-->0x08 if(time[4]>0x12) //判斷是否達(dá)到最大月份12月 time[4]=0x01; //重新回到01月 Writeds1302 (WRITE_MONTH,time[4]); //將設(shè)置好的月份寫入到DS1302存儲起來 } if(set_f==3) //設(shè)置日 { time[3]++; //日份+1 time[3]=(time[3]/10)*16+time[3]%10; //將日份轉(zhuǎn)換成16進(jìn)制,例如:15日-->0x15 if(time[4]==1||time[4]==3||time[4]==5||time[4]==7||time[4]==8||time[4]==10||time[4]==12)//1,3,5,7,8,10,12為大月,每月31天 { if(time[3]>0x31) //判斷是否達(dá)到最大日份31日 time[3]=0x01; //重新回到01日 } else //否者2,4,6,9,11為小月 { if(time[4]==0x02) //如果是2月,需要區(qū)分閏、平年 { if(((!(time[6]%4) && (time[6]%100)) || !(time[6]%400))==0)//如果閏年 { if(time[3]>0x28) //判斷是否達(dá)到最大日份28日 time[3]=0x01; //重新回到01日 } else //否者平年 { if(time[3]>0x29) //判斷是否達(dá)到最大日份29日 time[3]=0x01; //重新回到01日 } } else //否者為剩下的月份 { if(time[3]>0x30) //判斷是否達(dá)到最大日份30日 time[3]=0x01; //重新回到01日 } } Writeds1302 (WRITE_DAY,time[3]); //將設(shè)置好的日份寫入到DS1302存儲起來 } if(set_f==4) //設(shè)置時,同上 { time[2]++; time[2]=(time[2]/10)*16+time[2]%10; if(time[2]>0x23) time[2]=0x00; Writeds1302 (WRITE_HOUR,time[2]); } if(set_f==5) //設(shè)置分,同上 { time[1]++; time[1]=(time[1]/10)*16+time[1]%10; if(time[1]>0x59) time[1]=0x00; Writeds1302 (WRITE_MINUTE,time[1]); } if(set_f==6) //設(shè)置秒,同上 { time[0]++; time[0]=(time[0]/10)*16+time[0]%10; if(time[0]>0x59) time[0]=0x00; Writeds1302 (WRITE_SECOND,time[0]); } if(set_f==7) //設(shè)置鬧鐘-時 { naozhong[2]++; //鬧鐘-時 +1 if(naozhong[2]>23) //判斷鬧鐘-時 是否大于23時 naozhong[2]=0; //如果是,回到0時 } if(set_f==8) //設(shè)置鬧鐘-分 { naozhong[1]++; //鬧鐘-分 +1 if(naozhong[1]>59) //判斷鬧鐘-分 是否大于59時 naozhong[1]=0; //如果是,回到0分 } if(set_f==9) //設(shè)置鬧鐘-秒 { naozhong[0]++; //鬧鐘-秒 +1 if(naozhong[0]>59) //判斷鬧鐘-秒 是否大于59秒 naozhong[0]=0; //如果是,回到0秒 } if(set_f==10) //設(shè)置鬧鐘-開/關(guān) { naozhong[3]++; //切換鬧鐘開/關(guān),只需要0表示關(guān),1表示開就可以。 if(naozhong[3]==2) naozhong[3]=0; } if(set_f==11) //設(shè)置整點報時-開/關(guān) { naozhong[4]++; //切換整點報時開/關(guān),只需要0表示關(guān),1表示開就可以。 if(naozhong[4]==2) naozhong[4]=0; } } if(key_jia==0&&miaobiao_f==1)//秒表模式下 { T0_num=0; //復(fù)位秒表時間 times=0; fens=0; } if(key_jia==0&&set_dao!=0&&set_f==0)//設(shè)置倒計時起始時間 { if(set_dao==1) //設(shè)置倒計時起始時間-分 { if(fens!=255) fens++; } if(set_dao==2) //設(shè)置倒計時起始時間-秒 { if(times==59) { fens++; times=0; } else times++; } if(set_dao==3) //設(shè)置倒計時起始時間-分秒 { if(T0_num==18) { times++; T0_num=0; } else T0_num=T0_num+2; } } } //減鍵 if(key_jian==0) { delayms(7); if(key_jian==0&&set_f!=0) { if(set_f==1) //設(shè)置年 { if(time[6]==0) //判斷當(dāng)前是否為00年 time[6]=79; //如果是回到最大年份:79年 else time[6]--; //否者,年份-1 time[6]=(time[6]/10)*16+time[6]%10;//將年份轉(zhuǎn)換成16進(jìn)制,例如:16年-->0x16 Writeds1302 (WRITE_YEA,time[6]); //將設(shè)置好的年份寫入到DS1302存儲起來 } if(set_f==2) //設(shè)置月,同上 { if(time[4]==1) time[4]=12; else time[4]--; time[4]=(time[4]/10)*16+time[4]%10; Writeds1302 (WRITE_MONTH,time[4]); } if(set_f==3) //設(shè)置日,同上 { time[3]--; time[3]=(time[3]/10)*16+time[3]%10; if(time[4]==1||time[4]==3||time[4]==5||time[4]==7||time[4]==8||time[4]==10||time[4]==12) { if(time[3]<0x01) time[3]=0x31; } else { if(time[4]==0x02) { if(((!(time[6]%4) && (time[6]%100)) || !(time[6]%400))==0) { if(time[3]<0x01) time[3]=0x28; } else { if(time[3]<0x01) time[3]=0x29; } } else { if(time[3]<0x01) time[3]=0x30; } } Writeds1302 (WRITE_DAY,time[3]); } if(set_f==4) //設(shè)置時,同上 { if(time[2]==0) time[2]=23; else time[2]--; time[2]=(time[2]/10)*16+time[2]%10; Writeds1302 (WRITE_HOUR,time[2]); } if(set_f==5) //設(shè)置分,同上 { if(time[1]==0) time[1]=59; else time[1]--; time[1]=(time[1]/10)*16+time[1]%10; Writeds1302 (WRITE_MINUTE,time[1]); } if(set_f==6) //設(shè)置秒,同上 { if(time[0]==0) time[0]=59; else time[0]--; time[0]=(time[0]/10)*16+time[0]%10; Writeds1302 (WRITE_SECOND,time[0]); } if(set_f==7) //設(shè)置鬧鐘-時,同上 { if(naozhong[2]==0) naozhong[2]=23; else naozhong[2]--; } if(set_f==8) //設(shè)置鬧鐘-分,同上 { if(naozhong[1]==0) naozhong[1]=59; else naozhong[1]--; } if(set_f==9) //設(shè)置鬧鐘-秒,同上 { if(naozhong[0]==0) naozhong[0]=59; else naozhong[0]--; } if(set_f==10) //設(shè)置鬧鐘-開/關(guān),同上 { naozhong[3]++; if(naozhong[3]==2) naozhong[3]=0; } if(set_f==11) //設(shè)置整點報時-開/關(guān),同上 { naozhong[4]++; if(naozhong[4]==2) naozhong[4]=0; } } if(key_jian==0&&miaobiao_f==1)//秒表模式 { T0_num=0; //復(fù)位秒表時間 times=0; fens=0; } if(key_jian==0&&set_dao!=0&&set_f==0)//設(shè)置倒計時起始時間 { if(set_dao==1) //設(shè)置倒計時起始時間-分 { if(fens!=0) fens--; } if(set_dao==2) //設(shè)置倒計時起始時間-秒 { if(times!=0) times--; } if(set_dao==3) //設(shè)置倒計時起始時間-分秒 { if(T0_num!=0) T0_num=T0_num-2; } } } //倒計時 if(key_dao==0&&set_f==0&&miaobiao_f==0) { delayms(7); if(key_dao==0) { dao_f=~dao_f; //切換倒計時模式/正常模式 LCD_write_command(0x01);//清除屏幕顯示 delay_n40us(100); //延時等待全部清除完畢 TR0=0; //關(guān)閉定時器 buzz=1; //關(guān)閉蜂鳴器 set_dao=0; //重置倒計時起始時間設(shè)置標(biāo)志 AT24C02_write_date(6,dao_f);//寫入【倒計時標(biāo)志】數(shù)據(jù)保存 } while(!key_dao); //等待按鍵松開 } } /******************************************************** 函數(shù)名稱:void mian() 函數(shù)作用:主函數(shù) 參數(shù)說明: ********************************************************/ void main() { uchar i; if(key_dao==0) { delayms(100); if(key_dao==0) { for(i=0;i<7;i++) { AT24C02_write_date(i,0);//寫入數(shù)據(jù)保存 } } } naozhong[0]=AT24C02_read_date(0);//讀取存儲的【鬧鐘-秒】數(shù)據(jù) naozhong[1]=AT24C02_read_date(1);//讀取存儲的【鬧鐘-分】數(shù)據(jù) naozhong[2]=AT24C02_read_date(2);//讀取存儲的【鬧鐘-時】數(shù)據(jù) naozhong[3]=AT24C02_read_date(3);//讀取存儲的【鬧鐘-開關(guān)】數(shù)據(jù) naozhong[4]=AT24C02_read_date(4);//讀取存儲的【整點報時-開關(guān)】數(shù)據(jù) miaobiao_f=(bit)AT24C02_read_date(5);//讀取存儲的【秒表標(biāo)志】數(shù)據(jù) dao_f=(bit)AT24C02_read_date(6);//讀取存儲的【倒計時標(biāo)志】數(shù)據(jù) T0_init(); //定時器初始化 LCD_init(); //LCD1602初始化 Read_time(); //這邊初始化先讀取一次日期時間,是為了防止模式記憶到倒計時或秒表時退出秒表或倒計時時會誤認(rèn)為是整點進(jìn)行報時。 while(1) //死循環(huán) { scan(); //按鍵檢測處理 if(miaobiao_f==0&&dao_f==0)//非秒表模式/非倒計時模式,正常顯示模式 { if(set_f==0) //非設(shè)置模式下 { Read_time(); //讀取DS1302時間 display(); //更新顯示數(shù)據(jù) } else if(set_f<7) //設(shè)置日期、時間模式 { Read_time(); //讀取時間、日期 display2(); //顯示 } else if(set_f<11) //設(shè)置鬧鐘模式 display3(); else if(set_f==11)//設(shè)置整點報時開關(guān)模式 display4(); } else if(miaobiao_f==1) //秒表模式 display5(); else if(dao_f==1&&set_dao==0)//倒計時模式 display6(); else //倒計時設(shè)置倒計時的時間模式 display7(); } } #ifndef _DS1302_H_ #define _DS1302_H_ #include<reg52.h> #define uchar unsigned char #define uint unsigned int /*****************DS1302引腳定義*******************/ sbit SCLK = P3^5; // DS1302時鐘信號 7腳 sbit DIO = P3^6; // DS1302數(shù)據(jù)信號 6腳 sbit CE = P3^7; // DS1302片選 5腳 /*****************位尋址寄存器定義*******************/ sbit ACC_7 = ACC^7; /*****************DS1302寄存器宏定義*****************/ #define WRITE_SECOND 0x80 #define WRITE_MINUTE 0x82 #define WRITE_HOUR 0x84 #define WRITE_DAY 0x86 #define WRITE_MONTH 0x88 #define WRITE_WEEK 0x8a #define WRITE_YEA 0x8c #define READ_SECOND 0x81 #define READ_MINUTE 0x83 #define READ_HOUR 0x85 #define READ_DAY 0x87 #define READ_MONTH 0x89 #define READ_WEEK 0x8b #define READ_YEA 0x8d #define WRITE_PROTECT 0x8E /*****************DS1302函數(shù)定義*********************/ void Writeds1302 ( uchar addr,dat); //DS1302指定地址,寫數(shù)據(jù) uchar Read1302 ( uchar addr ); //DS1302指定地址,讀數(shù)據(jù) uchar Read1302_yuanshi(uchar addr); //DS1302讀原始數(shù)據(jù)函數(shù) void Read_time(void); //DS1302讀時間日期函數(shù) void DS1302_init(void); //DS1302初始化函數(shù) /*****************DS1302變量定義*********************/ uchar data time[]={0x00,0x00,0x00,0x00,0x00,0x00,0x00}; //存儲秒,分,時,日,月,星期,年 uchar code Mon1[2][13]= {0,31,28,31,30,31,30,31,31,30,31,30,31, //陽歷閏年 0,31,29,31,30,31,30,31,31,30,31,30,31};//陽歷平年 /******************************************************** 函數(shù)名稱:void Writeds1302 ( unsigned char addr,dat ) 函數(shù)作用:DS1302發(fā)送地址,數(shù)據(jù) 參數(shù)說明:addr:地址,dat:數(shù)據(jù) ********************************************************/ void Writeds1302 ( uchar addr,dat ) { unsigned char i,temp; CE=0; //CE引腳為低,數(shù)據(jù)傳送中止 SCLK=0; //清零時鐘總線 CE = 1; //CE引腳為高,邏輯控制有效 //發(fā)送地址 for ( i=8; i>0; i-- ) //循環(huán)8次移位 { SCLK = 0; temp = addr; DIO = (bit)(temp&0x01); //每次傳輸?shù)妥止?jié) addr >>= 1; //右移一位 SCLK = 1; } //發(fā)送數(shù)據(jù) for ( i=8; i>0; i-- ) { SCLK = 0; temp = dat; DIO = (bit)(temp&0x01); dat >>= 1; SCLK = 1; } SCLK=1; CE = 0; } /******************************************************** 函數(shù)名稱:uchar Read1302 ( uchar addr ) 函數(shù)作用:DS1302讀取數(shù)據(jù)并轉(zhuǎn)化成十進(jìn)制 參數(shù)說明:addr參考DS1302寄存器宏定義 ********************************************************/ uchar Read1302 ( uchar addr ) { unsigned char i,temp,dat1,dat2; CE=0; SCLK=0; CE = 1; //發(fā)送地址 for ( i=8; i>0; i-- ) //循環(huán)8次移位 { SCLK = 0; temp = addr; DIO = (bit)(temp&0x01); //每次傳輸?shù)妥止?jié) addr >>= 1; //右移一位 SCLK = 1; } //讀取數(shù)據(jù) for ( i=8; i>0; i-- ) { ACC_7=DIO; SCLK = 1; ACC>>=1; SCLK = 0; } SCLK=1; CE=0; dat1=ACC; dat2=dat1/16; //數(shù)據(jù)進(jìn)制轉(zhuǎn)換 dat1=dat1%16; //十六進(jìn)制轉(zhuǎn)十進(jìn)制 dat1=dat1+dat2*10; return (dat1); } /******************************************************** 函數(shù)名稱:void Read_time(void) 函數(shù)作用:DS1302讀取時間日期 參數(shù)說明: ********************************************************/ void Read_time(void) { time[0]=Read1302(0x81); time[1]=Read1302(0x83); time[2]=Read1302(0x85); time[3]=Read1302(0x87); time[4]=Read1302(0x89); time[5]=Read1302(0x8b); time[6]=Read1302(0x8d); } /******************************************************** 函數(shù)名稱:bit YearFlag(uchar cYear) 函數(shù)作用:計算是否閏年 參數(shù)說明:輸入:1:閏年,0:平年 ********************************************************/ bit YearFlag(uchar cYear) { if( (!(cYear%4) && (cYear%100)) || !(cYear%400) ) return 1; else return 0; } /******************************************************** 函數(shù)名稱:uchar GetWeekDay(uchar cYear,uchar cMon,uchar cDay) 函數(shù)作用:計算陽歷日期對應(yīng)的星期數(shù) 參數(shù)說明:輸入:陽歷GreYear(年),GreMon(月),GreDay(日) 輸出:星期幾 ********************************************************/ uchar GetWeekDay(uchar cYear,uchar cMon,uchar cDay) { char i; int Sum=0,tmpyear=2000+cYear; for(i=1;i<=cMon-1;i++) Sum+=Mon1[YearFlag(cYear)]; Sum+=cDay-1; return (((tmpyear-1)+(tmpyear-1)/4-(tmpyear-1)/100+(tmpyear-1)/400+Sum)%7)+1; } #endif #ifndef _INTERRUPT_H_ #define _INTERRUPT_H_ #include<reg52.h> #define uchar unsigned char #define uint unsigned int /**********************引腳定義************************/ sbit buzz =P2^7; //蜂鳴器 /**********************變量定義************************/ uchar T0_num; //記錄定時中斷次數(shù) uchar times; //記錄定時秒鐘數(shù) uchar fens; //記錄定時分鐘數(shù) bit dao_f=0; //倒計時標(biāo)記位,=0非倒計時模式,=1倒計時模式 bit miaobiao_f=0;//秒表標(biāo)記位,=0非秒表模式,=1秒表模式 /********************************************************* 函數(shù)名稱:void T0_init() 函數(shù)作用:定時器0初始化函數(shù) 參數(shù)說明: *********************************************************/ void T0_init() { EA=1; //開總中斷 ET0=1; //定時器T0中斷允許 TMOD=0x01; //使用定時器T0的模式1 TH0=(65536-50000)/256; //定時器T0的高8位賦初值 TL0=(65536-50000)%256; //定時器T0的低8位賦初值 TR0=0; //關(guān)閉定時器 } /********************************************************* 函數(shù)名稱:void T0_interrupt(void) interrupt 1 using 0 函數(shù)作用:定時器0中斷處理函數(shù) 參數(shù)說明:定時50ms中斷一次 *********************************************************/ void T0_interrupt(void) interrupt 1 using 0 { TH0=(65536-50000)/256; //定時器T0的高8位重新賦初值 TL0=(65536-50000)%256; //定時器T0的低8位重新賦初值 if(miaobiao_f==1) //秒表模式 { T0_num++; //定時中斷次數(shù)+1 if(T0_num==20) //定時1S完成,50ms*20=1S { T0_num=0; //重置定時中斷次數(shù) times++; //秒數(shù)+1S if(times==60) //如果秒數(shù)等于60S { times=0; //重置秒鐘數(shù) fens++; //分鐘數(shù)+1min } } } else //否則,倒計時模式 if(dao_f==1) { if(fens==0&×<5&&T0_num%4==0)//如果倒計時最后剩下5秒 buzz=~buzz; //蜂鳴器鳴叫 if(T0_num==0) //如果分秒倒計時到0 { if(times==0) //如果秒鐘=0 { if(fens==0) //如果分鐘=0 { TR0=0; //關(guān)閉定時器,倒計時結(jié)束 buzz=0; //開啟蜂鳴器鳴叫提示 } else //否者,分鐘不為0 { fens--; //分鐘數(shù)-1 times=59;//秒鐘=59 T0_num=19;//計數(shù)變量=19 } } else //否者,秒鐘數(shù)不為0 { times--; //秒鐘數(shù)-1S T0_num=19; //計數(shù)變量=19 } } else T0_num--; //計數(shù)變量-1。減到0表示1秒倒計時完成 } } #endif |