📄 clock.c
字号:
#include <AT89x51.h>
#include "intrins.h"
unsigned char hour,min,sec,year,month,day,weekday; //当前时间?日期?星期
unsigned int count_down; //1秒钟计时用
bit led_on; //数码管是否点亮的标志
unsigned char display[8]; //8位数码管要显示的数据
unsigned char attr; //八个数码管的闪烁控制字节,当为0时,对应数码管闪
bit flash; //LED 闪烁开关,与attr共同决定数码管是否闪烁
unsigned char show_status; //LED 显示状态标志
// 0:设置闹钟数据
// 1:显示当前日期及星期
// 2:显示当前时间
// 3:设置当前日期
// 4:设置当前时间
bit km; //按键已去抖动标志
bit kp; //按键已处理标志
bit sound; //蜂鸣器响标志
bit alarm_stop; //蜂鸣器响后用户手工按停标志
struct { unsigned char h; //小时
unsigned char m; //分钟
} alarm[8]; //定义结构数组,8个闹钟项
unsigned char alarm_en; //闹钟项启用标志
unsigned char alarm_wk; //闹钟项周末启用标志
unsigned char cur_alarm_set; //当前设置的闹钟项
unsigned char cur_alarm_active; //当前到点的闹钟项
bit new_alarm_info; //闹钟项内容已修改标志
sbit sound_output = P1^5; //蜂鸣器驱动端口,输出0时蜂鸣器响
sbit SDA = P1^6; //EEPROM数据线端口
sbit SCL = P1^7; //EEPROM时钟线端口
//以下是EEPROM操作时需要的延时函数
void I2cDelay()
{
_nop_(); _nop_(); _nop_();
_nop_(); _nop_(); _nop_();
}
//以下是延迟函数,参数为毫秒数
void DelayX1ms(unsigned char count)
{
unsigned char i,j;
for(i=0;i<count;i++)
for(j=0;j<240;j++) ;
}
//以下是I2C启动函数,24C08使用I2C方式
void Start()
{
SDA=1;
I2cDelay();
SCL=1;
I2cDelay();
SDA=0;
I2cDelay();
SCL=0;
}
//以下是I2C停止函数
void Stop()
{
I2cDelay();
SDA=0;
I2cDelay();
SCL=1;
I2cDelay();
SDA=1;
I2cDelay();
}
//以下是发送1字节数据给EEPROM函数
bit SendByte(unsigned char value)
{
unsigned char i;
bit no_ack=0;
for(i=0;i<8;i++) //发送8位数据
{
I2cDelay();
if(value&0x80) SDA=1;
else SDA=0;
value=value<<1;
I2cDelay();
SCL=1;
I2cDelay();
I2cDelay();
SCL=0;
}
I2cDelay();
SDA=1; //确认脉冲周期,等待EEPROM的确认
I2cDelay();
SCL=1;
I2cDelay();
if(SDA==1) no_ack=1;
I2cDelay();
SCL=0;
return no_ack;
}
//以下是向EEPROM写1字节函数
void mywrite(unsigned char address,unsigned char value)
{
Start();
SendByte(0xa0); //发送从地址
SendByte(address); //发送子地址
SendByte(value); //发送数值
Stop();
DelayX1ms(10);
}
//以下是从EEPROM接收1字节函数
unsigned char ReadByte()
{
unsigned char i,bval;
bval=0;
for(i=0;i<8;i++) //接收8位数据
{
I2cDelay();
SDA=1; //从P1输入数据时,先往P1输入"1"
I2cDelay();
SCL=1;
I2cDelay();
bval=bval<<1;
if(SDA) bval=bval|0x01;
I2cDelay();
SCL=0;
}
I2cDelay();
SDA=1; //确认脉冲周期,不送出确认
I2cDelay();
SCL=1;
I2cDelay();
I2cDelay();
return(bval);
}
//以下是从EEPROM读入1字节数据函数
unsigned char myread(unsigned char address)
{
unsigned char tmp;
Start();
SendByte(0xa0);
SendByte(address);
Start();
SendByte(0xa1);
tmp=ReadByte();
Stop();
DelayX1ms(2);
return(tmp);
}
//以下是定时器0中断程序,用于走时,1/8000秒一次
void Timer0ISR(void) interrupt 1 using 3
{
unsigned char tmp; unsigned int tmp_days;
P3=~P3;
count_down--;
if(count_down==1 || count_down==1001 || count_down==2001 || count_down==3001)
{
flash=~flash; //数码管闪烁的开关量
if(sound && flash)
sound_output=0; //驱动蜂鸣器
else sound_output=1; //关闭蜂鸣器
return;
}
/*** 计算当前日期为星期几***/
if(count_down==1500)
{
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==12)
tmp_days=tmp_days+31;
else if(tmp==4 || tmp==6 || tmp==9 || tmp==11)
tmp_days=tmp_days+30;
else if(tmp==2)
{
if(year%4==0) tmp_days=tmp_days+29;
else tmp_days=tmp_days+28;
}
tmp_days=tmp_days+day-1;
weekday=(weekday+tmp_days%7)%7+1;
return;
}
/*** 查询是否有闹钟时间项符合触发条件 ***/
if(count_down==2500)
{
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 && alarm[tmp].m==min) //比较当前时间
{
sound=1; cur_alarm_active=tmp; break;
} //与该闹钟项的时间
}
return;
}
if(count_down==0) //过了一秒钟
{
count_down=4000;
sec++;
if(sec==60)
{
sec=0;
min++;
if(min==60)
{
min=0; hour++;
if(hour==24)
{
hour=0;
day++;
switch(day)
{
case 29: if(month==2 && year%4)
{
day=1;
month=3;
} break;
case 30: if(month==2 && year%4==0)
{
day=1;
month=3;
} break;
case 31:if(month==4 || month==6 || month==9 || month==11)
{
day=1;
month++;
} break;
case 32: day=1; month++;
if(month==13)
{
month=1;
year++;
}
}
}
}
}
}
}
//以下是定时器2中断,用于按键扫描
void Timer1ISR(void) interrupt 3 using 2
{
unsigned char keytmp;
char tmp;
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;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -