可设置8个闹钟时间的智能时钟
普通的家用时钟一般只能设置一个闹钟时间,但很多人均需为工作日、周末、早晨、午休等不同时段设置
不同的闹钟时间。如果是使用普通的闹钟,只好每次休息前重新设置,很不方便,有时甚至会出现忘记更
改闹钟设置而睡过头的情况。
针对这种情况,本人利用89C51单片机设计了一款有8种闹钟设置的时钟,通过一段时间的使用,情况良好。
1、元件清单
共阴极数码管8个
4511七段译码芯片1片
ATMEL89C51单片机1片
24C08EEPROM1片
24M晶振1个
9V变压器(3VA)1个
LM317输出可调稳压IC1个
整流桥堆1个
470uF电容1个
100uF电容1个
10uF电容1个
0.1uF电容1个
33pF电容2个
蜂鸣器1个
9014(或其它NPN管)8个
ksp92(或其它PNP管)1个
二极管2个
1K欧电阻16个
470欧电阻1个
10K欧可调电阻1个
按钮开关4个
可装四节电池的电池盒1个
万能板(约12CM*17CM)1块
所有元件按以下的电路图焊接在一块万能板上。注意LM317的输出应由低调高,以免烧IC。
1、电路图
1、功能简介
该时钟以24小时制显示时间,并可显示2000年至2049年之间的任何日期及星期,日期与时间经按键
可相互切换,可输入8个闹钟时间设置,每个闹钟设置包括响铃的时间(小时与分钟)、对工作日有效还是
对周末有效的标志,以及本项设置是否启用的标志等三部分。这8个闹钟设置均保存在EEPROM中,即使
掉电也不用重新输入。当然使用者可通过按钮对任何一个设置作修改。数码管可经按钮关闭显示,避免夜
间刺眼、影响睡眠。调节LM317输出电压,可改变数码管亮度,但电压不能低于后备电池的电压,否则后
备电池供电。用四节1.5V电池串联作后备电源,保证市电停电时时钟继续走时。时钟的精度取决于晶振频
率的精度。
2、程序清单
本程序用C语言编写,经KeilC51编译成二进制码后写入89C51内的EPROM内即可。
#include"atmelat89x鸡翅怎么做 51.h"
#include"intrins.h"
unsignedcharhour,min,c,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_t;//当前设置的闹钟项
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_();_nop_();
_nop_();_nop_();_nop_();
}
voidDelayX1ms(unsignedcharcount)//延迟函数,参数为毫秒数
{unsignedchari,j;
for(i=0;i
for(j=0;j<240;j++);
}
voidStart()//I2C启动,24C08使用I2C方式
{SDA_PIN=1;I2cDelay();
SCL_PIN=1;I2cDelay();
SDA_PIN=0;I2cDelay();
SCL_PIN=0;
}
voidStop()//I2C停止
{I2cDelay();SDA_PIN=0;
I2cDelay();SCL_PIN=1;
I2cDelay();SDA_PIN=1;
I2cDelay();
}
bitSendByte(unsignedcharvalue)//发送1字节数据给EEPROM
{unsignedchari;
bitno_ack=0;
for(i=0;i<8;i++)//发送8位数据
{I2cDelay();
if(value&0x80)SDA_PIN=1;
elSDA_PIN=0;
value=value<<1;
I2cDelay();SCL_PIN=1;
I2cDelay();
I2cDelay();SCL_PIN=0;
}
I2cDelay();SDA_PIN=1;//确认脉冲周期,等待EEPROM的确认
I2cDelay();SCL_PIN=1;
I2cDelay();
if(SDA_PIN==1)no_ack=1;
I2cDelay();SCL_PIN=0;
returnno_ack;
}
voidmywrite(unsignedcharaddress,unsignedcharvalue)//向EEPROM写1字节
{Start();SendByte(0xa0);SendByte(address);
SendByte(value);Stop();DelayX1ms(10);
}
unsignedcharReadByte()//从EEPROM接收1字节
{unsignedchari,bval;
bval=0;
for(i=0;i<8;i++)//接收8位数据
{I2cDelay();
SDA_PIN=1;//从P1输入数据时,先往P1输入“1”
I2cDelay();SCL_PIN=1;
I2cDelay();bval=bval<<1;if(SDA_PIN)bval=bval|0x01;
I2cDelay();SCL_PIN=0;
}
I2cDelay();SDA_PIN=1;//确认脉冲周期,不送出确认
I2cDelay();SCL_PIN=1;
I2cDelay();
I2cDelay();
return(bval);
}
unsignedcharmyread(unsignedcharaddress)//从EEPROM读入1字节数据
{unsignedchartmp;
Start();SendByte(0xa0);SendByte(address);
Start();SendByte(0xa1);tmp=ReadByte();
Stop();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;//驱动蜂鸣器
elsound_output=1;//关闭蜂鸣器
return;
}
/***计算当前日期为星期几***/
if(count_down==3000)
{if(year==0)weekday=5;//2000年1月1日为星期六
el{tmp=(year-1)/4+1;tmp=(year-tmp)+tmp*2;
weekday=(tmp+5)%7;//计算出当前年的1月1日为星期几
}
tmp_days=0;
for(tmp=1;tmp
if(tmp==1||tmp==3||tmp==5||tmp==7||tmp==8||tmp==10)
tmp_days=tmp_days+31;
elif(tmp==4||tmp==6||tmp==9||tmp==11)
tmp_days=tmp_days+30;
elif(tmp==2)
{if(year%4==0)tmp_days=tmp_days+29;
eltmp_days=tmp_days+28;
}
tmp_days=tmp_days+day-1;weekday=(weekday+tmp_days%7)%7+1;
return;
}
/***查询是否有闹钟时间项符合触发条件***/
if(count_down==5000)
{if((alarm_stop||sound)&&alarm[cur_alarthen是什么意思 m_active].m!=min)//触发后1分钟
{alarm_stop=0;sound=0;}//自动关蜂鸣器
if(sound==0&&alarm_stop==0)//没有已触发的闹钟项
for(tmp=0;tmp<8;tmp++)//则查询8个闹钟项内是否有符合条件的
{if(((alarm_en>>tmp)&1)==0)continue;//该闹钟项不启用
if(((alarm_wk>>tmp)&1)==1)//该闹钟项周末有效
{if(weekday!=6&&weekday!=7)continue;}//当前不是星期六或星期天
el
{if(weekday==6||weekday==7)continue;}
if(alarm[tmp].h==hour&&alarm[tmp].m==min)//比较当前时间与该
{sound=1;cur_alarm_active=tmp;break;}//闹钟项的时间
}
return;
}
if(count_down==0)//过了一秒钟
{count_down=8000;
c++;
if(c==60)
{c=0;
min++;
if(min==60)
{min=0;
hour++;
if(hour==24)
{hour=0;day++;
switch(day)
{ca29:if(month==2&&year%4){day=1;month=3;}
break;
ca30:if(month==2&&year%4==0){day=1;month=3;}
break;
ca31:if(month==4||month==6||month==9||month==11)
{day=1;month++;}
break;
ca32:day=1;month++;
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_t;display[1]=0xf;
display[2]=alarm[cur_alarm_t].h/10;display[3]=alarm[cur_alarm_t].h%10;
display[4]=alarm[cur_alarm_t].m/10;display[5]=alarm[cur_alarm_t].m%10;
display[6]=(alarm_wk>写真图片大全 >cur_alarm_t)&1;display[7]=(alarm_en>>cur_alarm_t)&1;
}
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=全民k歌歌房 =2||show_status==4)//当前显示或设置时间
{display[0]=hour/10;display[1]=hour%10;display[2]=min/10;
display[3]=min%10;display[4]=c/10;display[5]=c%10;
display[6]=0xf;display[7]=0xf;//最后两后无显示
}
/***按键扫描及处理***/
keytmp=~(P1)&0x0f;
if(keytmp==0){km=0;kp=0;}
el
{if(km==0)km=1;
el
{if(kp==0)
{kp=1;
if(keytmp==1)//第一个按钮
{if(sound){alarm_stop=1;sound=0;}//如果闹钟正响,按此键停止
elif((show_status==1||show_status==2)&&led_on)//正显示日期或时间
{show_status=0;cur_alarm_t=0;attr=0x3f;}//进入闹钟设置
elif(show_status==0)//如正在设置闹钟时间项
{show_status=2;new_alarm_info=1;attr=0xff;}//返回当前时间显示
return;
}
if(keytmp==2&&led_on)//第二个按钮,仅当数码管打开时有效
{switch(attr)
{ca0xff:if(show_status==1)show_status=2;//在显示时间与日期间切换
elif(show_status==2)show_status=1;
break;
ca0x3f:if(show_status==0)cur_alarm_t=(cur_alarm_t+1)%8;
elif(show_status==3)
year=(year+1)%50;//当前日期的“年”加1
elif(show_status==4)
hour=(hour+1)%24;//当前时间的“时”加1
break;
ca0xcf:if(show_status==0)//闹钟设置的“时”加1
alarm[cur_alarm_t].h=(alarm[cur_alarm_t].h+1)%24;
elif(show_status==3)
{month++;//当前日期的“月”加1
if(month==13)month=1;}
elif(show_status==4)
min=(min+1)%60;//当前时间的“分”什么洗发水最好 加1
break;
ca0xf3:if(show_status==0)
alarm[cur_alarm_t].m=(alarm[cur_alarm_t].m+1)%60;
elif(show_status==3)
{day++;//当前日期的“日”加1
if(day==32)day=1;}
elif(show_status==4)
{count_down=8000;
c=(c+1)%60;}//当前时间的“秒”加1
break;
ca0xfd:if(show_status==0)
alarm_wk^=0x1<
break;
ca0xfe:if(show_status==0)
alarm_en^=0x1<
}//endofswitch(attr)
return;
}//endofif(keytmp==1)
if(keytmp==4)//第三个按钮
{switch(attr)
{ca0xff:if(show_status==1||show_status==2)
led_on=~led_on;//打开或关闭数码管显示
break;
ca0x3f:if(show_status==0)//如果正在设置闹钟
{if(cur_alarm_t==0)cur_alarm_t=7;
elcur_alarm_t--;}
elif(show_status==3)//当前日期的“年”减1
{if(year==0)year=49;elyear--;}
elif(show_status==4)//当前时间的“时”减1
{tmp=hour-1;if(tmp<0)hour=23;el
hour=tmp;}
break;
ca0xcf:if(show_status==0)//闹钟设置的“时”减1
{tmp=alarm[cur_alarm_t].h-1;
if(tmp<0)alarm[cur_alarm_t].h=23;
elalarm[cur_alarm_t].h=tmp;
}
elif(show_status==3)
{month--;//当前日期的“月”减1
if(month==0)month=12;}
elif(show_status==4)
{tmp=min-1;//当前时间的“分”减1
if(tmp<0)min=59;elmin=tmp;}
break;
ca0xf3:if(show_status==0)//闹钟设置的“分钟”减1
{tmp=alarm[cur_alarm_t].m-1;
if(tmp<0)alarm[cur_alarm_t].m=59;
elalarm[cur_alarm_t].m=tmp;
}
elif(show_status==3)
{day--;//当前日期的“日”减1
if(day==0)day=31;}
elif(show_status==4)
{tmp=c-1;//当前时间的“秒”减1
count_down=8000;
if(tmp<0)c=59;elc=tmp;}
break;
ca0xfd:if(show_status==0)//切换周末标志
alarm_wk^=0x1<
break;
ca0xfe:if(show_status==0)//切换启用标志
alarm_en^=0x1<
}//endofswitch(attr)
return;
}//endofif(keytmp==2)
if(keytmp==8&led_on)//第四个按钮,仅当数码管打开时有效
{switch(attr)
{ca0xff:if(show_status==1)//如果当前显示日期
show_status=3;//切换到调准日期状态
elif(show_status==2)//如果当前显示时间
show_status=4;//切换到调准时间状态
attr=0x3f;break;//第一、二个数码管闪烁
ca0x3f:attr=0xcf;break;//第三、四个数码管闪烁
ca0xcf:attr=0xf3;break;//第五、六个数码管闪烁
ca0xf3:if(show_status==0)attr=0xfd;//第七个数码管闪烁
elif(show_status==3)
{show_status=1;attr=0xff;}//恢复正常显示日期
elif(show_status==4)
{show_status=2;attr=0xff;}//恢复正常显示时间
break;
ca0xfd:if(show_status==0)attr=0xfe;//第八个数码管闪烁
break;
ca0xfe:if(show_status==0)attr=0x3f;//第一、二个数码管闪烁
}
}//endofif(keytmp==4)
}//endofif(kp==0)
}//endofif(km==0)
}//endofif(keytmp!=0)
}
main()
{unsignedchari;
hour=23;min=58;c=30;year=2;month=4;day=25;
count_down=8000;
flash=0;attr=0xff;led_on=1;
km=0;kp=0;show_status=2;//加电后显示当前时间
new_alarm_info=0;sound=0;alarm_stop=0;
for(i=0;i<8;i++)//从EEPROM中读入8个闹钟设置
{alarm[i].h=myread(i*2);alarm[i].m=myread(i*2+1);}
alarm_en=myread(i*2);alarm_wk=myread(i*2+1);
IE=0;IP=0;//disableallinterruptandlowerpriority
TMOD=0x12;//timer0isttomode2,auto_reloading,timer1,mode1
TH0=6;TL0=6;//timer0parametersfor0.125ms
TH1=0x15;TL1=0xa0;//timer1parametersfor30ms
TR0=1;TR1=1;//timer0interruptmostimportant
ET0=1;ET1=1;EA=1;//enableinterruptfunction
while(1)
{if(led_on)
for(i=0;i<8;i++)
{P2=0;
if(flash||attr&(0x80>>i))
{P0=display[i];P2=0x80>>i;DelayX1ms(1);}
}
elP2=0;
if(new_alarm_info)
{P2=0;//暂时关闭数码管
new_alarm_info=0;//写入EEPROM
for(i=0;i<8;i++){mywrite(i*2,alarm[i].h);mywrite(i*2+1,alarm[i].m);}
mywrite(i*2,alarm_en);mywrite(i*2+1,alarm_wk);
}
}
}
本文发布于:2023-03-19 07:32:07,感谢您对本站的认可!
本文链接:https://www.wtabcd.cn/fanwen/zuowen/1679182330308142.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文word下载地址:设置闹钟.doc
本文 PDF 下载地址:设置闹钟.pdf
留言与评论(共有 0 条评论) |