程序清单
本程序用C语言编写,经Keil C51编译成二进制码后写入89C51内的EPROM内即可。
#i nclude "atmel\at89x51.h"
#i nclude "intrins.h"
unsigned char hour,min,sec,year,month,day,weekday
unsigned int count_down
bit LED_on
unsigned char display[8]
unsigned char attr
bit flash
unsigned char show_status
// 0:设置闹钟数据
// 1:显示当前日期及星期
// 2:显示当前时间
// 3:设置当前日期
// 4:设置当前时间
bit km
bit kp
bit sound
bit alarm_stop
struct { unsigned char h
unsigned char m
} alarm[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
sbit SDA_PIN = P1^6
sbit SCL_PIN = P1^7
void I2cDelay() //EEPROM操作时需要的延时函数
{ _nop_()
_nop_()
}
void DelayX1ms(unsigned char count) //延迟函数,参数为毫秒数
{unsigned char i,j
for(i=0
for(j=0
}
void Start() //I2C启动,24C08使用I2C方式
{ SDA_PIN=1
SCL_PIN=1
SDA_PIN=0
SCL_PIN=0
}
void Stop() //I2C停止
{ I2cDelay()
I2cDelay()
I2cDelay()
I2cDelay()
}
bit SendByte(unsigned char value) //发送1字节数据给EEPROM
{unsigned char i
bit no_ack=0
for(i=0
{ I2cDelay()
if(value&0x80) SDA_PIN=1
else SDA_PIN=0
value=value<<1
I2cDelay()
I2cDelay()
I2cDelay()
}
I2cDelay()
I2cDelay()
I2cDelay()
if(SDA_PIN==1) no_ack=1
I2cDelay()
return no_ack
}
void mywrite(unsigned char address,unsigned char value) //向EEPROM写1字节
{ Start()
SendByte(value)
}
unsigned char ReadByte() //从EEPROM接收1字节
{unsigned char i,bval
bval=0
for(i=0
{ I2cDelay()
SDA_PIN=1
I2cDelay()
I2cDelay()
I2cDelay()
}
I2cDelay()
I2cDelay()
I2cDelay()
I2cDelay()
return(bval)
}
unsigned char myread(unsigned char address) //从EEPROM读入1字节数据
{unsigned char tmp
Start()
Start()
Stop()
return(tmp)
}
void Timer0ISR(void) interrupt 1 using 3 //定时器0中断程序,用于走时,1/8000秒一次
{unsigned char tmp,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
else sound_output=1
return
}
if(count_down==3000)
{ if(year==0) weekday=5
else { tmp=(year-1)/4+1
weekday=(tmp+5)%7
}
tmp_days=0
for(tmp=1
if(tmp==1 || tmp==3 || tmp==5 || tmp==7 || tmp==8 || tmp==10)
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
return
}
if(count_down==5000)
{ if((alarm_stop || sound) && alarm[cur_alarm_active].m!=min) //触发后1分钟
{ alarm_stop=0
if(sound==0 && alarm_stop==0) //没有已触发的闹钟项
for(tmp=0
{ 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
}
return
}
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
switch(day)
{ case 29: if(month==2 && year%4) { day=1
break
case 30: if(month==2 && year%4==0) { day=1
break
case 31: if(month==4 || month==6 || month==9 || month==11)
{ day=1
break
case 32: day=1
if(month==13) { month=1
}
}
}
}
}
}
void Timer1ISR(void) interrupt 3 using 2 //定时器2中断,用于按键扫描
{unsigned char keytmp
char tmp
TH1=0x15
if(show_status==0) //当前正在设置闹钟项
{ display[0]=cur_alarm_set
display[2]=alarm[cur_alarm_set].h/10
display[4]=alarm[cur_alarm_set].m/10
display[6]=(alarm_wk>>cur_alarm_set)&1
}
if(show_status==1 || show_status==3) //当前显示或设置日期
{ display[0]=year/10
display[3]=month%10
display[6]=0xf
}
if(show_status==2 || show_status==4) //当前显示或设置时间
{ display[0]=hour/10
display[3]=min%10
display[6]=0xf
}
keytmp=~(P1) & 0x0f
if(keytmp==0) { km=0
else
{ if(km==0) km=1
else
{ if(kp==0)
{ kp=1
if(keytmp==1) //第一个按钮
{ if(sound) { alarm_stop=1
else if((show_status==1 || show_status==2) && led_on) //正显示日期或时间
{ show_status=0
else if(show_status==0) //如正在设置闹钟时间项
{ show_status=2
return
}
if(keytmp==2 && led_on) //第二个按钮,仅当数码管打开时有效
{ switch(attr)
{ case 0xff: if(show_status==1) show_status=2
else if(show_status==2) show_status=1
break
case 0x3f: if(show_status==0) cur_alarm_set=(cur_alarm_set+1)%8
else if(show_status==3)
year=(year+1)%50
else if(show_status==4)
hour=(hour+1)%24
break
case 0xcf: if(show_status==0) //闹钟设置的“时”加1
alarm[cur_alarm_set].h=(alarm[cur_alarm_set].h+1)%24
else if(show_status==3)
{ month++
if(month==13) month=1
else if(show_status==4)
min=(min+1)%60
break
case 0xf3: if(show_status==0)
alarm[cur_alarm_set].m=(alarm[cur_alarm_set].m+1)%60
else if(show_status==3)
{day++
if(day==32) day=1
else if(show_status==4)
{count_down=8000
sec=(sec+1)%60
break
case 0xfd: if(show_status==0)
alarm_wk^=0x1<
break
case 0xfe: if(show_status==0)
alarm_en^=0x1<
} //end of switch(attr)
return
} //end of if(keytmp==1)
if(keytmp==4) //第三个按钮
{ switch(attr)
{ case 0xff: if(show_status==1 || show_status==2)
led_on=~led_on
break
case 0x3f: if(show_status==0) //如果正在设置闹钟
{ if(cur_alarm_set==0) cur_alarm_set=7
else cur_alarm_set--
else if(show_status==3) //当前日期的“年”减1
{ if(year==0) year=49
else if(show_status==4) //当前时间的“时”减1
{ tmp=hour-1
break
case 0xcf: if(show_status==0) //闹钟设置的“时”减1
{ tmp=alarm[cur_alarm_set].h-1
if(tmp<0) alarm[cur_alarm_set].h=23
else alarm[cur_alarm_set].h=tmp
}
else if(show_status==3)
{ month--
if(month==0) month=12
else if(show_status==4)
{ tmp=min-1
if(tmp<0) min=59
break
case 0xf3: if(show_status==0) //闹钟设置的“分钟”减1
{ tmp=alarm[cur_alarm_set].m-1
if(tmp<0) alarm[cur_alarm_set].m=59
else alarm[cur_alarm_set].m=tmp
}
else if(show_status==3)
{ day--
if(day==0) day=31
else if(show_status==4)
{ tmp=sec-1
count_down=8000
if(tmp<0) sec=59
break
case 0xfd: if(show_status==0) //切换周末标志
alarm_wk^=0x1<
break
case 0xfe: if(show_status==0) //切换启用标志
alarm_en^=0x1<
} //end of switch(attr)
return
} //end of if(keytmp==2)
if(keytmp==8 & led_on) //第四个按钮,仅当数码管打开时有效
{ switch(attr)
{ case 0xff: if(show_status==1) //如果当前显示日期
show_status=3
else if(show_status==2) //如果当前显示时间
show_status=4
attr=0x3f
case 0x3f: attr=0xcf
case 0xcf: attr=0xf3
case 0xf3: if(show_status==0) attr=0xfd
else if(show_status==3)
{ show_status=1
else if(show_status==4)
{ show_status=2
break
case 0xfd: if(show_status==0) attr=0xfe
break
case 0xfe: if(show_status==0) attr=0x3f
}
} // end of if(keytmp==4)
} // end of if(kp==0)
} // end of if(km==0)
} // end of if(keytmp!=0)
}
main()
{unsigned char i
hour=23
count_down=8000
flash=0
km=0
new_alarm_info=0
for(i=0
{ alarm[i].h=myread(i*2)
alarm_en=myread(i*2)
IE=0
TMOD=0x12
TH0=6
TH1=0x15
TR0=1
ET0=1
while(1)
{ if(led_on)
for(i=0
{ P2=0
if(flash || attr&(0x80>>i))
{ P0=display[i]
}
else P2=0
if(new_alarm_info)
{ P2=0
new_alarm_info=0
for(i=0
mywrite(i*2,alarm_en)
}
}
}
唯样商城-电子元器件采购网(www.oneyac.com)是本土元器件目录分销商,采用“小批量、现货、样品”销售模式,致力于满足客户多型号、高质量、快速交付的采购需求。
唯样自建高效智能仓储,拥有自营库存超过50,000种,提供一站式正品现货采购、个性化解决方案、选型替代等多元化服务。