学了一个多月51了,终于整了个电子钟出来,个人感觉还是比较有趣的。
需要注意的是我用的是普中的板子,板子类型不同,io口的功能可能会有所差异。然后我这个k1开关和k2开关是接反了的,原本k1应该是接P3^0,k2接P3^1的,结果我一测试才知道k1接到了P3^1,k2接到P3^0了,不过这不要紧,用sbit定义位变量时注意换一下就可以了。然后大概讲讲功能,用8个数码管显示目前时间和闹铃时间,然后用4个独立按键对目前时间和闹铃时间进行调整(k2是加,k3是减 ,k4是用来停止闹铃的),第一次按k1是对目前时间秒数调整,第2次按k1是对目前时间分钟数调整,第三次按k1是对目前时间小时数调整,第4次按k1是对闹铃秒数调整,第5次按k1是对闹铃时间分钟数调整,第6次按k1是对闹铃秒数调整,第7次按k1是调整完毕,进去非调整状态即实时显示目前时间(不过有点差异,时间走的快了一点)。主要用到了数码管动态显示,独立按键,定时器中断这些。
代码如下:
#include<reg52.h>
typedef unsigned int u16;
typedef unsigned char u8;
sbit led=P2^0;
sbit lsa=P2^2;
sbit lsb=P2^3;
sbit lsc=P2^4;
sbit beep=P1^5;
sbit k1=P3^1;
sbit k2=P3^0;
sbit k3=P3^2;
sbit k4=P3^3;
sbit dian=P0^7;
u8 keyvalue,alarmexist=0;
u8 smgduan[]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x67,0x00};//段选码,分别对应0到无
u16 cnt=0,i=0,j=0,flag=0,time[]={0,0,0,0,0,0,0,0};//只用数码管0,1 3,4 6,7
u16 alarm[]={0,0,0,0,0,0,1,0};
u16*p;
void delay(u16 mmp);
void t0andt1init();
void addproct(int x);
void addproca(int x);
void reduceproct(int x);
void reduceproca(int x);
void keyscan();
void jia();
void jian();
void main()
{
led=0;
t0andt1init();
P0=0x00;
while(1)
{
if(time[0]==alarm[0]&&time[1]==alarm[1]&&time[3]==alarm[3]&&time[4]==alarm[4]&&time[6]==alarm[6]&&time[7]==alarm[7])//满足条件 蜂鸣器以一定的时间间隔响,只到K4按键并松开,此时数码管任然正常显示当前时间
{
alarmexist=0;
while(k4)
{
beep=~beep;
delay(25);
beep=~beep;
delay(25);
}
}
keyscan();
}
}
void delay(u16 mmp)
{
while(mmp--);
}
void t0andt1init()
{
TMOD=0x11;
TH0=0xfc;
TL0=0x67;//赋定时器初始值,定时1ms
TH1=0xfc;
TL1=0x67;
TR0=1;//T0定时器开始定时
EA=1;
ET0=1;
ET1=1;
}
void addproct(int x) //对非调整状态和调整状态的加1处理(仅用于对当前时间)
{
if(x==0||x==3||x==6)
if(time[x]==10)
{
time[x]=0;
time[x+1]=time[x+1]+1;
addproct(x+1);
}
if(x==1||x==4)
if(time[x]==6)
{
time[x]=0;
time[x+2]=time[x+2]+1;
addproct(x+2);
}
if(time[6]==4&&time[7]==2)
time[6]=time[7]=0;
}
void addproca(int x) //对调整状态的加1处理(仅用于对闹钟时间)
{
if(x==0||x==3||x==6)
if(alarm[x]==10)
{
alarm[x]=0;
alarm[x+1]=alarm[x+1]+1;
addproca(x+1);
}
if(x==1||x==4)
if(alarm[x]==6)
{
alarm[x]=0;
alarm[x+2]=alarm[x+2]+1;
addproca(x+2);
}
if(alarm[6]==4&&alarm[7]==2)
alarm[6]=alarm[7]=0;
}
void reduceproct(int x) // 对调整状态的减1处理(仅用于对当前时间)
{
if(time[0]==0&&time[1]==0&&time[3]==0&&time[4]==0&&time[6]==0&&time[7]==0)
{
time[0]=time[3]=9;
time[1]=time[4]=5;
time[6]=3;
time[7]=2;
return ;
}
if(x==0||x==3||x==6)
{
if(time[x]>=1)
time[x]=time[x]-1;
else
{
if(time[7]==0&&x==6)
{
time[6]=3;
time[7]=2;
}
else
{
time[x]=9;
reduceproct(x+1);
}
}
}
else
{
if(time[x]>=1)
time[x]=time[x]-1;
else
{
time[x]=5;
if(x!=7)
reduceproct(x+2);
else
time[x]=1;
}
}
}
void reduceproca(int x) // 对调整状态的减1处理(仅用于对闹钟时间)
{
if(alarm[0]==0&&alarm[1]==0&&alarm[3]==0&&alarm[4]==0&&alarm[6]==0&&alarm[7]==0)
{
alarm[0]=alarm[3]=9;
alarm[1]=alarm[4]=5;
alarm[6]=3;
alarm[7]=2;
return ;
}
if(x==0||x==3||x==6)
{
if(alarm[x]>=1)
alarm[x]=alarm[x]-1;
else
{
if(alarm[7]==0&&x==6)
{
alarm[6]=3;
alarm[7]=2;
}
else
{
alarm[x]=9;
reduceproca(x+1);
}
}
}
else
{
if(alarm[x]>=1)
alarm[x]=alarm[x]-1;
else
{
alarm[x]=5;
if(x!=7)
reduceproca(x+2);
else
alarm[x]=1;
}
}
}
void keyscan()
{
flag=0;
keyvalue=0;
if(k1==0)
{
TR0=0;//不在显示当前时间
TR1=1;
delay(1000);
if(k1==0)
{
while(!k1) ;
delay(1000);
led=~led;
keyvalue++;
}
else
return ;
while(keyvalue!=7)
{
if(k1==0)
{
delay(1000);
if(k1==0)
{
while(!k1) ;
led=~led;
keyvalue++;
if(keyvalue==4)
flag=1;
}
}
if(k2==0)
{
delay(1000);
if(k2==0)
{
while(!k2) ;
led=~led;
jia();
}
}
if(k3==0)
{
delay(1000);
if(k3==0)
{
while(!k3) ;
led=~led;
jian();
}
}
}
TR0=1;
TR1=0;
if(((alarm[6]+alarm[7]*10)*60+alarm[3]+alarm[4]*10)>((time[6]+time[7]*10)*60+time[3]+time[4]*10))//判断闹钟时间是否大于当前时间,
alarmexist=1;
else
alarmexist=0;
}
}
void jia()
{
switch(keyvalue)
{
case 1:time[0]=time[0]+1;addproct(0);break;
case 2:time[3]=time[3]+1;addproct(3);break;
case 3:time[6]=time[6]+1;addproct(6);break;
case 4:alarm[0]=alarm[0]+1;addproca(0);break;
case 5:alarm[3]=alarm[3]+1;addproca(3);break;
case 6:alarm[6]=alarm[6]+1;addproca(6);break;
}
}
void jian()
{
switch(keyvalue)
{
case 1:reduceproct(0);break;
case 2:reduceproct(3);break;
case 3:reduceproct(6);break;
case 4:reduceproca(0);break;
case 5:reduceproca(3);break;
case 6:reduceproca(6);break;
}
}
void Timer0() interrupt 1//非调整时,执行的中断服务程序
{
TH0=0xfc;
TL0=0x67;//赋定时器初始值,定时1ms
cnt++;
if(1000==cnt)
{
cnt=0;
time[0]=time[0]+1;
addproct(0);
}
P0=0X00;
switch(i)
{
case 0:lsa=0;lsb=0;lsc=0;P0=smgduan[time[0]];dian=(alarmexist==1)?1:0;i++;break;
case 1:lsa=1;lsb=0;lsc=0;P0=smgduan[time[1]];i++;i++;break;
case 3:lsa=1;lsb=1;lsc=0;P0=smgduan[time[3]];i++;break;
case 4:lsa=0;lsb=0;lsc=1;P0=smgduan[time[4]];i++;i++;break;
case 6:lsa=0;lsb=1;lsc=1;P0=smgduan[time[6]];i++;break;
case 7:lsa=1;lsb=1;lsc=1;P0=smgduan[time[7]];i=0;break;
}
}
void Timer1() interrupt 3 //调整时,执行的中断服务程序 ,flag=0显示正在调整的time,为1显示正在调整的alarm
{
TH1=0xfc;
TL1=0x67;//赋定时器初始值,定时1ms
if(flag==0)
p=time;
else
p=alarm;
P0=0X00;
switch(j)
{
case 0:lsa=0;lsb=0;lsc=0;P0=smgduan[p[0]];j++;break;
case 1:lsa=1;lsb=0;lsc=0;P0=smgduan[p[1]];j++;j++;break;
case 3:lsa=1;lsb=1;lsc=0;P0=smgduan[p[3]];j++;break;
case 4:lsa=0;lsb=0;lsc=1;P0=smgduan[p[4]];j++;j++;break;
case 6:lsa=0;lsb=1;lsc=1;P0=smgduan[p[6]];j++;break;
case 7:lsa=1;lsb=1;lsc=1;P0=smgduan[p[7]];j=0;break;
}
}