可设置八个闹钟的智能时钟程序11.docx
《可设置八个闹钟的智能时钟程序11.docx》由会员分享,可在线阅读,更多相关《可设置八个闹钟的智能时钟程序11.docx(14页珍藏版)》请在冰豆网上搜索。
可设置八个闹钟的智能时钟程序11
可设置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个
10K欧电阻4个按钮开关4个
可装四节电池的电池盒1个万能板(约12CM*17CM)1块
所有元件按以下的电路图焊接在一块万能板上。
注意LM317的输出应由低调高,以免烧IC。
2、电路图
3、功能简介
该时钟以24小时制显示时间,并可显示2000年至2049年之间的任何日期及星期,日期与时间经按键可相互切换,可输入8个闹钟时间设置,每个闹钟设置包括响铃的时间(小时与分钟)、对工作日有效还是对周末有效的标志,以及本项设置是否启用的标志等三部分。
这8个闹钟设置均保存在EEPROM中,即使掉电也不用重新输入。
当然使用者可通过按钮对任何一个设置作修改。
数码管可经按钮关闭显示,避免夜间刺眼、影响睡眠。
调节LM317输出电压,可改变数码管亮度,但电压不能低于后备电池的电压,否则后备电池供电。
用四节1.5V电池串联作后备电源,保证市电停电时时钟继续走时。
时钟的精度取决于晶振频率的精度。
4、程序清单
本程序用C语言编写,经KeilC51编译成二进制码后写入89C51内的EPROM内即可。
#include"atmel\at89x51.h"
#include"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_();_nop_();
_nop_();_nop_();_nop_();
}
voidDelayX1ms(unsignedcharcount)//延迟函数,参数为毫秒数
{unsignedchari,j;
for(i=0;ifor(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;
elseSDA_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;//驱动蜂鸣器
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;tmpif(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;
return;
}
/***查询是否有闹钟时间项符合触发条件***/
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;tmp++)//则查询8个闹钟项内是否有符合条件的
{if(((alarm_en>>tmp)&1)==0)continue;//该闹钟项不启用
if(((alarm_wk>>tmp)&1)==1)//该闹钟项周末有效
{if(weekday!
=6&&weekday!
=7)continue;}//当前不是星期六或星期天
else
{if(weekday==6||weekday==7)continue;}
if(alarm[tmp].h==hour&&al