#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 |