#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; //設置鍵 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; //設置選擇標記,=0非設置,=1設置年,=2設置月,=3設置日。=4設置時,=5設置分,=6設置秒 // =7設置鬧鐘-時,=8設置鬧鐘-分。=9設置鬧鐘秒,=10設置鬧鐘-開關,=11整點報時-開關 uchar set_dao=0; //倒計時設置標記 uchar num; //計數變量 uchar naozhong[5]; //鬧鐘-秒、鬧鐘-分、鬧鐘-時、鬧鐘-開關、整點報時-開關 bit baoshi_f=0; //報時標記位,=1整點報時 bit naozhong_f=0; //鬧鐘開始標記位,=1鬧鐘開始,=0鬧鐘未開始 /******************************************************** 函數名稱:void delayms(uint ms) 函數作用:毫秒延時函數 參數說明: ********************************************************/ void delayms(uint ms) { unsigned char i=100,j; for(;ms;ms--) { while(--i) { j=10; while(--j); } } } /******************************************************** 函數名稱:void baoshi(uchar i) 函數作用:整點報時函數 參數說明:I為蜂鳴器響的次數 ********************************************************/ void baoshi(uchar i) { uchar j; for(j=0;j<i;j++)//循環i次 { buzz=0; //蜂鳴器鳴叫 led=0; //LED燈點亮 delayms(20);//延時 buzz=1; //關閉蜂鳴器鳴叫 led=1; //關閉LED燈 delayms(20);//延時 } } /******************************************************** 函數名稱:void display(void) 函數作用:正常顯示日期、時間函數 參數說明: ********************************************************/ void display(void) { uchar xq; //存儲星期 uchar temp2[2]; //存儲鬧鐘結束時間 //判斷整點報時 if(time[0]<3&&time[1]==0&&baoshi_f==0)//判斷是否為整點 { baoshi_f=1; //標記整點報時開啟 if(naozhong[4]%2==1) //如果整點報時開關有打開 { if(time[2]%12==0) //根據當前時間,控制蜂鳴器鳴叫次數 baoshi(12); else baoshi(time[2]%12); } } if(time[0]>10&&time[1]==0) //整點報時結束 baoshi_f=0; //重置整點報時標志 //計算鬧鐘結束【時間】 if(naozhong[1]!=59) //鬧鐘-分 不等于59分 【例:11:11】 { temp2[0]=naozhong[2]; //鬧鐘結束時間為:小時不變,分鐘+1 temp2[1]=naozhong[1]+1; } else //鬧鐘-分 等于59分 { if(naozhong[2]!=23) //鬧鐘-時 不等于23時 【例:11:59】 { temp2[0]=naozhong[2]+1;//鬧鐘結束時間為:小時加1,分鐘=0 temp2[1]=0; } else //鬧鐘-時 等于23時 【例:23:59】 { temp2[0]=0; //鬧鐘結束時間為:小時=0,分鐘=0 temp2[1]=0; } } if(time[2]==naozhong[2]&&time[1]==naozhong[1]&&time[0]==naozhong[0]&&naozhong[3]%2==1)//判斷當前是否為鬧鐘時間 { buzz=0; //開啟鬧鈴,蜂鳴器鳴叫、LED燈點亮 led=0; naozhong_f=1; //標記鬧鐘開啟 } if(time[2]==temp2[0]&&time[1]==temp2[1]&&time[0]==naozhong[0]&&naozhong[3]%2==1) //判斷鬧鐘一分鐘是否結束 { buzz=1; //關閉鬧鈴,蜂鳴器停止、LED燈關閉 led=1; naozhong_f=0; //重置鬧鐘開啟標志 } 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行,所有關于顯示都一樣】 LCD_disp_char(1,2,ASCII[time[2]%12%10]);//*/ //24小時制 /*LCD_disp_char(0,2,ASCII[time[2]/10]);//顯示時【0:表示第1列,2:表示第2行,所有關于顯示都一樣】 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]); } /******************************************************** 函數名稱:void display2(void) 函數作用:顯示調整日期、時間函數 參數說明: ********************************************************/ void display2() { num++; lcd1602_write_character(1,1,"Date:"); lcd1602_write_character(1,2,"Time:"); if(num%2==0) ////偶數次顯示,奇數次不顯示。這樣就會有閃爍效果,可以清楚看到當前設置的是哪個值 { 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 //奇數次不顯示 { switch(set_f)//根據當前設置的內容,對應位置閃爍 { 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; } } } /******************************************************** 函數名稱:void display3(void) 函數作用:顯示調整鬧鐘函數 參數說明: ********************************************************/ void display3() { num++; lcd1602_write_character(3,1,"Alarm clock"); if(num%2==0) ////偶數次顯示,奇數次不顯示。這樣就會有閃爍效果,可以清楚看到當前設置的是哪個值 { 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"); //顯示鬧鐘-開/關 else lcd1602_write_character(11,2,"ON"); } else //奇數次不顯示 { switch(set_f)//根據當前設置的內容,對應位置閃爍 { 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; } } } /******************************************************** 函數名稱:void display4(void) 函數作用:顯示調整整點報時開關函數 參數說明: ********************************************************/ void display4() { num++; lcd1602_write_character(2,1,"On time alarm"); if(num%2==0) //偶數次顯示,奇數次不顯示。這樣就會有閃爍效果,可以清楚看到當前設置的是哪個值 { if(naozhong[4]%2==0) //顯示設置整點報時-開/關 lcd1602_write_character(7,2,"OFF"); else lcd1602_write_character(7,2,"ON"); } else //奇數次不顯示 lcd1602_write_character(7,2," "); //顯示空格 } /******************************************************** 函數名稱:void display5(void) 函數作用:顯示秒表計時函數 參數說明: ********************************************************/ 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]); //顯示秒表-分秒 } /******************************************************** 函數名稱:void display6() 函數作用:倒計時顯示函數 參數說明: ********************************************************/ 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]); //顯示倒計時-分秒 } /******************************************************** 函數名稱:void display7() 函數作用:倒計時設置顯示函數 參數說明: ********************************************************/ void display7() { num++; lcd1602_write_character(1,1,"The countdown"); if(num%2==0) //偶數次顯示,奇數次不顯示。這樣就會有閃爍效果,可以清楚看到當前設置的是哪個值 { 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]); //顯示設置倒計時-分秒 } else //奇數次不顯示 { switch(set_dao)//根據當前設置的內容,對應位置閃爍 { 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; } } } /******************************************************** 函數名稱:void scan(void) 函數作用:按鍵查詢處理函數 參數說明: ********************************************************/ void scan(void) { //設置鍵 if(key_mode==0) //按鍵按下 { delayms(7); //延時消抖 if(key_mode==0) //再次確認按鍵按下 { if(miaobiao_f==0&&dao_f==0)//非秒表/非倒計時模式 { buzz=1; //進入設置關閉鬧鐘聲光提示 led=1; if(set_f==0||set_f==6||set_f==10) //進入設置先清除屏幕,顯示設置部分 { Writeds1302 (WRITE_PROTECT,0X00); //禁止DS1302寫保護 LCD_write_command(0x01); //清除屏幕顯示 delay_n40us(100); //延時等待全部清除完畢 } set_f++; //設置變量+1 if(set_f>11) //全部設置完成,退出設置 { set_f=0; //重置設置變量 AT24C02_write_date(0,naozhong[0]);//寫入【鬧鐘-秒】數據保存 AT24C02_write_date(1,naozhong[1]);//寫入【鬧鐘-分】數據保存 AT24C02_write_date(2,naozhong[2]);//寫入【鬧鐘-時】數據保存 AT24C02_write_date(3,naozhong[3]);//寫入【鬧鐘-開關】數據保存 AT24C02_write_date(4,naozhong[4]);//寫入【整點報時-開關】數據保存 Writeds1302 (WRITE_MINUTE,(time[1]/10)*16+time[1]%10);//將設置好的時間寫入DS1302 Writeds1302 (WRITE_SECOND,(time[0]/10)*16+time[0]%10); LCD_write_command(0x01); //清除屏幕顯示 delay_n40us(100); //延時等待全部清除完畢 } } else //否則,秒表模式或者倒計時模式 { if(set_dao==0) //如果,非倒計時設置起始時間狀態下 TR0=~TR0; //切換 秒表計時或倒計時-開始/暫停 } } while(!key_mode); //等待按鍵松開 } //確定 if(key_ok==0) //按鍵按下 { delayms(7); //延時消抖 if(key_ok==0&&set_f!=0)//再次確認按鍵按下,并且當前處于設置模式 { set_f=0; //重置設置變量 AT24C02_write_date(0,naozhong[0]);//寫入【鬧鐘-秒】數據保存 AT24C02_write_date(1,naozhong[1]);//寫入【鬧鐘-分】數據保存 AT24C02_write_date(2,naozhong[2]);//寫入【鬧鐘-時】數據保存 AT24C02_write_date(3,naozhong[3]);//寫入【鬧鐘-開關】數據保存 AT24C02_write_date(4,naozhong[4]);//寫入【整點報時-開關】數據保存 Writeds1302 (WRITE_MINUTE,(time[1]/10)*16+time[1]%10);//將設置好的時間寫入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) //否則,當前鬧鐘響起,進入暫停鬧鐘 { buzz=1; //關閉蜂鳴器 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) //退出秒表模式時,關閉秒表計時 { TR0=0; //關閉定時器 T0_num=0; //重置所有秒表的時間 times=0; fens=0; } AT24C02_write_date(5,miaobiao_f);//寫入【秒表標志】數據保存 } else if(dao_f==1) //否者,倒計時模式 { if(buzz==0) //如果蜂鳴器響 buzz=1; //先關閉蜂鳴器 else //否者 { if(set_dao==0||set_dao==3) { LCD_write_command(0x01);//清除屏幕顯示 delay_n40us(100); //延時等待全部清除完畢 } set_dao++; //倒計時起始時間設置標志+1 if(set_dao==4) //全部設置完成 set_dao=0; //重置倒計時起始時間設置標志 } } while(!key_ok); //等待按鍵松開 } //加鍵 if(key_jia==0) { delayms(7); if(key_jia==0&&set_f!=0) { if(set_f==1) //設置年 { time[6]++; //年份+1 time[6]=(time[6]/10)*16+time[6]%10; //將年份轉換成16進制,例如:16年-->0x16 if(time[6]>0x79) //判斷是否達到最大年份79年 time[6]=0x00; //重新回到00年 Writeds1302 (WRITE_YEA,time[6]); //將設置好的年份寫入到DS1302存儲起來 time[6]=Read1302(0x8d); //讀取當前年份 } if(set_f==2) //設置月 { time[4]++; //月份+1 time[4]=(time[4]/10)*16+time[4]%10; //將月份轉換成16進制,例如:08月-->0x08 if(time[4]>0x12) //判斷是否達到最大月份12月 time[4]=0x01; //重新回到01月 Writeds1302 (WRITE_MONTH,time[4]); //將設置好的月份寫入到DS1302存儲起來 } if(set_f==3) //設置日 { time[3]++; //日份+1 time[3]=(time[3]/10)*16+time[3]%10; //將日份轉換成16進制,例如: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) //判斷是否達到最大日份31日 time[3]=0x01; //重新回到01日 } else //否者2,4,6,9,11為小月 { if(time[4]==0x02) //如果是2月,需要區分閏、平年 { if(((!(time[6]%4) && (time[6]%100)) || !(time[6]%400))==0)//如果閏年 { if(time[3]>0x28) //判斷是否達到最大日份28日 time[3]=0x01; //重新回到01日 } else //否者平年 { if(time[3]>0x29) //判斷是否達到最大日份29日 time[3]=0x01; //重新回到01日 } } else //否者為剩下的月份 { if(time[3]>0x30) //判斷是否達到最大日份30日 time[3]=0x01; //重新回到01日 } } Writeds1302 (WRITE_DAY,time[3]); //將設置好的日份寫入到DS1302存儲起來 } if(set_f==4) //設置時,同上 { 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) //設置分,同上 { 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) //設置秒,同上 { 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) //設置鬧鐘-時 { naozhong[2]++; //鬧鐘-時 +1 if(naozhong[2]>23) //判斷鬧鐘-時 是否大于23時 naozhong[2]=0; //如果是,回到0時 } if(set_f==8) //設置鬧鐘-分 { naozhong[1]++; //鬧鐘-分 +1 if(naozhong[1]>59) //判斷鬧鐘-分 是否大于59時 naozhong[1]=0; //如果是,回到0分 } if(set_f==9) //設置鬧鐘-秒 { naozhong[0]++; //鬧鐘-秒 +1 if(naozhong[0]>59) //判斷鬧鐘-秒 是否大于59秒 naozhong[0]=0; //如果是,回到0秒 } if(set_f==10) //設置鬧鐘-開/關 { naozhong[3]++; //切換鬧鐘開/關,只需要0表示關,1表示開就可以。 if(naozhong[3]==2) naozhong[3]=0; } if(set_f==11) //設置整點報時-開/關 { naozhong[4]++; //切換整點報時開/關,只需要0表示關,1表示開就可以。 if(naozhong[4]==2) naozhong[4]=0; } } if(key_jia==0&&miaobiao_f==1)//秒表模式下 { T0_num=0; //復位秒表時間 times=0; fens=0; } if(key_jia==0&&set_dao!=0&&set_f==0)//設置倒計時起始時間 { if(set_dao==1) //設置倒計時起始時間-分 { if(fens!=255) fens++; } if(set_dao==2) //設置倒計時起始時間-秒 { if(times==59) { fens++; times=0; } else times++; } if(set_dao==3) //設置倒計時起始時間-分秒 { 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) //設置年 { if(time[6]==0) //判斷當前是否為00年 time[6]=79; //如果是回到最大年份:79年 else time[6]--; //否者,年份-1 time[6]=(time[6]/10)*16+time[6]%10;//將年份轉換成16進制,例如:16年-->0x16 Writeds1302 (WRITE_YEA,time[6]); //將設置好的年份寫入到DS1302存儲起來 } if(set_f==2) //設置月,同上 { 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) //設置日,同上 { 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) //設置時,同上 { 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) //設置分,同上 { 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) //設置秒,同上 { 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) //設置鬧鐘-時,同上 { if(naozhong[2]==0) naozhong[2]=23; else naozhong[2]--; } if(set_f==8) //設置鬧鐘-分,同上 { if(naozhong[1]==0) naozhong[1]=59; else naozhong[1]--; } if(set_f==9) //設置鬧鐘-秒,同上 { if(naozhong[0]==0) naozhong[0]=59; else naozhong[0]--; } if(set_f==10) //設置鬧鐘-開/關,同上 { naozhong[3]++; if(naozhong[3]==2) naozhong[3]=0; } if(set_f==11) //設置整點報時-開/關,同上 { naozhong[4]++; if(naozhong[4]==2) naozhong[4]=0; } } if(key_jian==0&&miaobiao_f==1)//秒表模式 { T0_num=0; //復位秒表時間 times=0; fens=0; } if(key_jian==0&&set_dao!=0&&set_f==0)//設置倒計時起始時間 { if(set_dao==1) //設置倒計時起始時間-分 { if(fens!=0) fens--; } if(set_dao==2) //設置倒計時起始時間-秒 { if(times!=0) times--; } if(set_dao==3) //設置倒計時起始時間-分秒 { 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; //關閉定時器 buzz=1; //關閉蜂鳴器 set_dao=0; //重置倒計時起始時間設置標志 AT24C02_write_date(6,dao_f);//寫入【倒計時標志】數據保存 } while(!key_dao); //等待按鍵松開 } } /******************************************************** 函數名稱:void mian() 函數作用:主函數 參數說明: ********************************************************/ 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);//寫入數據保存 } } } naozhong[0]=AT24C02_read_date(0);//讀取存儲的【鬧鐘-秒】數據 naozhong[1]=AT24C02_read_date(1);//讀取存儲的【鬧鐘-分】數據 naozhong[2]=AT24C02_read_date(2);//讀取存儲的【鬧鐘-時】數據 naozhong[3]=AT24C02_read_date(3);//讀取存儲的【鬧鐘-開關】數據 naozhong[4]=AT24C02_read_date(4);//讀取存儲的【整點報時-開關】數據 miaobiao_f=(bit)AT24C02_read_date(5);//讀取存儲的【秒表標志】數據 dao_f=(bit)AT24C02_read_date(6);//讀取存儲的【倒計時標志】數據 T0_init(); //定時器初始化 LCD_init(); //LCD1602初始化 Read_time(); //這邊初始化先讀取一次日期時間,是為了防止模式記憶到倒計時或秒表時退出秒表或倒計時時會誤認為是整點進行報時。 while(1) //死循環 { scan(); //按鍵檢測處理 if(miaobiao_f==0&&dao_f==0)//非秒表模式/非倒計時模式,正常顯示模式 { if(set_f==0) //非設置模式下 { Read_time(); //讀取DS1302時間 display(); //更新顯示數據 } else if(set_f<7) //設置日期、時間模式 { Read_time(); //讀取時間、日期 display2(); //顯示 } else if(set_f<11) //設置鬧鐘模式 display3(); else if(set_f==11)//設置整點報時開關模式 display4(); } else if(miaobiao_f==1) //秒表模式 display5(); else if(dao_f==1&&set_dao==0)//倒計時模式 display6(); else //倒計時設置倒計時的時間模式 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數據信號 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函數定義*********************/ void Writeds1302 ( uchar addr,dat); //DS1302指定地址,寫數據 uchar Read1302 ( uchar addr ); //DS1302指定地址,讀數據 uchar Read1302_yuanshi(uchar addr); //DS1302讀原始數據函數 void Read_time(void); //DS1302讀時間日期函數 void DS1302_init(void); //DS1302初始化函數 /*****************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};//陽歷平年 /******************************************************** 函數名稱:void Writeds1302 ( unsigned char addr,dat ) 函數作用:DS1302發送地址,數據 參數說明:addr:地址,dat:數據 ********************************************************/ void Writeds1302 ( uchar addr,dat ) { unsigned char i,temp; CE=0; //CE引腳為低,數據傳送中止 SCLK=0; //清零時鐘總線 CE = 1; //CE引腳為高,邏輯控制有效 //發送地址 for ( i=8; i>0; i-- ) //循環8次移位 { SCLK = 0; temp = addr; DIO = (bit)(temp&0x01); //每次傳輸低字節 addr >>= 1; //右移一位 SCLK = 1; } //發送數據 for ( i=8; i>0; i-- ) { SCLK = 0; temp = dat; DIO = (bit)(temp&0x01); dat >>= 1; SCLK = 1; } SCLK=1; CE = 0; } /******************************************************** 函數名稱:uchar Read1302 ( uchar addr ) 函數作用:DS1302讀取數據并轉化成十進制 參數說明:addr參考DS1302寄存器宏定義 ********************************************************/ uchar Read1302 ( uchar addr ) { unsigned char i,temp,dat1,dat2; CE=0; SCLK=0; CE = 1; //發送地址 for ( i=8; i>0; i-- ) //循環8次移位 { SCLK = 0; temp = addr; DIO = (bit)(temp&0x01); //每次傳輸低字節 addr >>= 1; //右移一位 SCLK = 1; } //讀取數據 for ( i=8; i>0; i-- ) { ACC_7=DIO; SCLK = 1; ACC>>=1; SCLK = 0; } SCLK=1; CE=0; dat1=ACC; dat2=dat1/16; //數據進制轉換 dat1=dat1%16; //十六進制轉十進制 dat1=dat1+dat2*10; return (dat1); } /******************************************************** 函數名稱:void Read_time(void) 函數作用:DS1302讀取時間日期 參數說明: ********************************************************/ 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); } /******************************************************** 函數名稱:bit YearFlag(uchar cYear) 函數作用:計算是否閏年 參數說明:輸入:1:閏年,0:平年 ********************************************************/ bit YearFlag(uchar cYear) { if( (!(cYear%4) && (cYear%100)) || !(cYear%400) ) return 1; else return 0; } /******************************************************** 函數名稱:uchar GetWeekDay(uchar cYear,uchar cMon,uchar cDay) 函數作用:計算陽歷日期對應的星期數 參數說明:輸入:陽歷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; //記錄定時中斷次數 uchar times; //記錄定時秒鐘數 uchar fens; //記錄定時分鐘數 bit dao_f=0; //倒計時標記位,=0非倒計時模式,=1倒計時模式 bit miaobiao_f=0;//秒表標記位,=0非秒表模式,=1秒表模式 /********************************************************* 函數名稱:void T0_init() 函數作用:定時器0初始化函數 參數說明: *********************************************************/ 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; //關閉定時器 } /********************************************************* 函數名稱:void T0_interrupt(void) interrupt 1 using 0 函數作用:定時器0中斷處理函數 參數說明:定時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++; //定時中斷次數+1 if(T0_num==20) //定時1S完成,50ms*20=1S { T0_num=0; //重置定時中斷次數 times++; //秒數+1S if(times==60) //如果秒數等于60S { times=0; //重置秒鐘數 fens++; //分鐘數+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; //關閉定時器,倒計時結束 buzz=0; //開啟蜂鳴器鳴叫提示 } else //否者,分鐘不為0 { fens--; //分鐘數-1 times=59;//秒鐘=59 T0_num=19;//計數變量=19 } } else //否者,秒鐘數不為0 { times--; //秒鐘數-1S T0_num=19; //計數變量=19 } } else T0_num--; //計數變量-1。減到0表示1秒倒計時完成 } } #endif |