设置8个闹钟时间的智能时钟Word文档下载推荐.docx
《设置8个闹钟时间的智能时钟Word文档下载推荐.docx》由会员分享,可在线阅读,更多相关《设置8个闹钟时间的智能时钟Word文档下载推荐.docx(15页珍藏版)》请在冰豆网上搜索。
2、程序清单
本程序用C语言编写,经KeilC51编译成二进制码后写入89C51内的EPROM内即可。
#include"
atmel\at89x51.h"
intrins.h"
unsignedcharhour,min,sec,year,month,day,weekday;
//当前时间、日期、星期
unsignedintcount_down;
//1秒钟计时用
bitled_on;
//数码管是否点亮的标志
unsignedchardisplay[8];
//8位数码管要显示的数据
unsignedcharattr;
//八个数码管的闪烁控制字节,当为0时,对应数码管闪
bitflash;
//LED闪烁开关,与attr共同决定数码管是否闪烁
unsignedcharshow_status;
//LED显示状态标志
//0:
设置闹钟数据
//1:
显示当前日期及星期
//2:
显示当前时间
//3:
设置当前日期
//4:
设置当前时间
bitkm;
//按键已去抖动标志
bitkp;
//按键已处理标志
bitsound;
//蜂鸣器响标志
bitalarm_stop;
//蜂鸣器响后用户手工按停标志
struct{unsignedcharh;
//小时
unsignedcharm;
//分钟
}alarm[8];
//8个闹钟项
unsignedcharalarm_en;
//闹钟项启用标志
unsignedcharalarm_wk;
//闹钟项周末启用标志
unsignedcharcur_alarm_set;
//当前设置的闹钟项
unsignedcharcur_alarm_active;
//当前到点的闹钟项
bitnew_alarm_info;
//闹钟项内容已修改标志
sbitsound_output=P1^5;
//蜂鸣器驱动端口,输出0时蜂鸣器响
sbitSDA_PIN=P1^6;
//EEPROM数据线端口
sbitSCL_PIN=P1^7;
//EEPROM时钟线端口
voidI2cDelay()//EEPROM操作时需要的延时函数
{_nop_();
_nop_();
}
voidDelayX1ms(unsignedcharcount)//延迟函数,参数为毫秒数
{unsignedchari,j;
for(i=0;
i<
count;
i++)
for(j=0;
j<
240;
j++);
voidStart()//I2C启动,24C08使用I2C方式
{SDA_PIN=1;
I2cDelay();
SCL_PIN=1;
SDA_PIN=0;
SCL_PIN=0;
voidStop()//I2C停止
{I2cDelay();
SDA_PIN=1;
bitSendByte(unsignedcharvalue)//发送1字节数据给EEPROM
{unsignedchari;
bitno_ack=0;
8;
i++)//发送8位数据
{I2cDelay();
if(value&
0x80)SDA_PIN=1;
elseSDA_PIN=0;
value=value<
<
1;
}
//确认脉冲周期,等待EEPROM的确认
if(SDA_PIN==1)no_ack=1;
returnno_ack;
voidmywrite(unsignedcharaddress,unsignedcharvalue)//向EEPROM写1字节
{Start();
SendByte(0xa0);
SendByte(address);
SendByte(value);
Stop();
DelayX1ms(10);
unsignedcharReadByte()//从EEPROM接收1字节
{unsignedchari,bval;
bval=0;
i++)//接收8位数据
//从P1输入数据时,先往P1输入“1”
bval=bval<
if(SDA_PIN)bval=bval|0x01;
//确认脉冲周期,不送出确认
return(bval);
unsignedcharmyread(unsignedcharaddress)//从EEPROM读入1字节数据
{unsignedchartmp;
Start();
SendByte(0xa1);
tmp=ReadByte();
DelayX1ms
(2);
return(tmp);
voidTimer0ISR(void)interrupt1using3//定时器0中断程序,用于走时,1/8000秒一次
{unsignedchartmp,tmp_days;
count_down--;
if(count_down==1||count_down==2001||count_down==4001||count_down==6001)
{flash=~flash;
//数码管闪烁的开关量
if(sound&
&
flash)sound_output=0;
//驱动蜂鸣器
elsesound_output=1;
//关闭蜂鸣器
return;
/***计算当前日期为星期几***/
if(count_down==3000)
{if(year==0)weekday=5;
//2000年1月1日为星期六
else{tmp=(year-1)/4+1;
tmp=(year-tmp)+tmp*2;
weekday=(tmp+5)%7;
//计算出当前年的1月1日为星期几
tmp_days=0;
for(tmp=1;
tmp<
month;
tmp++)
if(tmp==1||tmp==3||tmp==5||tmp==7||tmp==8||tmp==10)
tmp_days=tmp_days+31;
elseif(tmp==4||tmp==6||tmp==9||tmp==11)
tmp_days=tmp_days+30;
elseif(tmp==2)
{if(year%4==0)tmp_days=tmp_days+29;
elsetmp_days=tmp_days+28;
tmp_days=tmp_days+day-1;
weekday=(weekday+tmp_days%7)%7+1;
/***查询是否有闹钟时间项符合触发条件***/
if(count_down==5000)
{if((alarm_stop||sound)&
alarm[cur_alarm_active].m!
=min)//触发后1分钟
{alarm_stop=0;
sound=0;
}//自动关蜂鸣器
if(sound==0&
alarm_stop==0)//没有已触发的闹钟项
for(tmp=0;
tmp++)//则查询8个闹钟项内是否有符合条件的
{if(((alarm_en>
>
tmp)&
1)==0)continue;
//该闹钟项不启用
if(((alarm_wk>
1)==1)//该闹钟项周末有效
{if(weekday!
=6&
weekday!
=7)continue;
}//当前不是星期六或星期天
else
{if(weekday==6||weekday==7)continue;
if(alarm[tmp].h==hour&
alarm[tmp].m==min)//比较当前时间与该
{sound=1;
cur_alarm_active=tmp;
break;
}//闹钟项的时间
if(count_down==0)//过了一秒钟
{count_down=8000;
sec++;
if(sec==60)
{sec=0;
min++;
if(min==60)
{min=0;
hour++;
if(hour==24)
{hour=0;
day++;
switch(day)
{case29:
if(month==2&
year%4){day=1;
month=3;
case30:
year%4==0){day=1;
case31:
if(month==4||month==6||month==9||month==11)
{day=1;
month++;
case32:
day=1;
if(month==13){month=1;
year++;
voidTimer1ISR(void)interrupt3using2//定时器2中断,用于按键扫描
{unsignedcharkeytmp;
chartmp;
TH1=0x15;
TL1=0xa0;
//每30ms中断一次
/***当前显示的内容***/
if(show_status==0)//当前正在设置闹钟项
{display[0]=cur_alarm_set;
display[1]=0xf;
display[2]=alarm[cur_alarm_set].h/10;
display[3]=alarm[cur_alarm_set].h%10;
display[4]=alarm[cur_alarm_set].m/10;
display[5]=alarm[cur_alarm_set].m%10;
display[6]=(alarm_wk>
cur_alarm_set)&
display[7]=(alarm_en>
if(show_status==1||show_status==3)//当前显示或设置日期
{display[0]=year/10;
display[1]=year%10;
display[2]=month/10;
display[3]=month%10;
display[4]=day/10;
display[5]=day%10;
display[6]=0xf;
display[7]=weekday;
if(show_status==2||show_status==4)//当前显示或设置时间
{display[0]=hour/10;
display[1]=hour%10;
display[2]=min/10;
display[3]=min%10;
display[4]=sec/10;
display[5]=sec%10;
display[7]=0xf;
//最后两后无显示
/***按键扫描及处理***/
keytmp=~(P1)&
0x0f;
if(keytmp==0){km=0;
kp=0;
}
{if(km==0)km=1;
{if(kp==0)
{kp=1;
if(keytmp==1)//第一个按钮
{if(sound){alarm_stop=1;
}//如果闹钟正响,按此键停止
elseif((show_status==1||show_status==2)&
led_on)//正显示日期或时间
{show_status=0;
cur_alarm_set=0;
attr=0x3f;
}//进入闹钟设置
elseif(show_status==0)//如正在设置闹钟时间项
{show_status=2;
new_alarm_info=1;
attr=0xff;
}//返回当前时间显示
if(keytmp==2&
led_on)//第二个按钮,仅当数码管打开时有效
{switch(attr)
{case0xff:
if(show_status==1)show_status=2;
//在显示时间与日期间切换
elseif(show_status==2)show_status=1;
case0x3f:
if(show_status==0)cur_alarm_set=(cur_alarm_set+1)%8;
elseif(show_status==3)
year=(year+1)%50;
//当前日期的“年”加1
elseif(show_status==4)
hour=(hour+1)%24;
//当前时间的“时”加1
case0xcf:
if(show_status==0)//闹钟设置的“时”加1
alarm[cur_alarm_set].h=(alarm[cur_alarm_set].h+1)%24;
{month++;
//当前日期的“月”加1
if(month==13)month=1;
min=(min+1)%60;
//当前时间的“分”加1
case0xf3:
if(show_status==0)
alarm[cur_alarm_set].m=(alarm[cur_alarm_set].m+1)%60;
{day++;
//当前日期的“日”加1
if(day==32)day=1;
{count_down=8000;
sec=(sec+1)%60;
}//当前时间的“秒”加1
case0xfd:
alarm_wk^=0x1<
cur_alarm_set;
//周末标志位切换
case0xfe:
alarm_en^=0x1<
//启用标志位切换
}//endofswitch(attr)
}//endofif(keytmp==1)
if(keytmp==4)//第三个按钮
if(show_status==1||show_status==2)
led_on=~led_on;
//打开或关闭数码管显示
if(show_status==0)//如果正在设置闹钟
{if(cur_alarm_set==0)cur_alarm_set=7;
elsecur_alarm_set--;
elseif(show_status==3)//当前日期的“年”减1
{if(year==0)year=49;
elseyear--;
elseif(show_status==4)//当前时间的“时”减1
{tmp=hour-1;
if(tmp<
0)hour=23;
elsehour=tmp;
if(show_status==0)//闹钟设置的“时”减1
{tmp=alarm[cur_alarm_set].h-1;
0)alarm[cur_alarm_set].h=23;
elsealarm[cur_alarm_set].h=tmp;
elseif(show_status==3)
{month--;
//当前日期的“月”减1
if(month==0)month=12;
elseif(show_status==4)
{tmp=min-1;
//当前时间的“分”减1
0)min=59;
elsemin=tmp;
if(show_status==0)//闹钟设置的“分钟”减1
{tmp=alarm[cur_alarm_set].m-1;
0)alarm[cur_alarm_set].m=59;
elsealarm[cur_alarm_set].m=tmp;
{day--;
//当前日期的“日”减1
if(day==0)day=31;
{tmp=sec-1;
//当前时间的“秒”减1
count_down=8000;
0)sec=59;
elsesec=tmp;
if(show_status==0)//切换周末标志
if(show_status==0)//切换启用标志
}//endofif(keytmp==2)
if(keytmp==8&
led_on)//第四个按钮,仅当数码管打开时有效
if(show_status==1)//如果当前显示日期
show_status=3;
//切换到调准日期状态
elseif(show_status==2)//如果当前显示时间
show_status=4;
//切换到调准时间状态
//第一、二个数码管闪烁
attr=0xcf;
//第三、四个数码管闪烁
attr=0xf3;
//第五、六个数码管闪烁
if(show_status==0)attr=0xfd;
//第七个数码管闪烁
{show_status=1;
}//恢复正常显示日期
}//恢复正常显示时间
if(show_status==0)attr=0xfe;
//第八个数码管闪烁
if(show_status==0)attr=0x3f;
}//endofif(keytmp==4)
}//endofif(kp==0)
}//endofif(km==0)
}//endofif(keytmp!
=0)