仿真图:
代码段:
/*整体功能:用八位共阳极数目管作电子时钟显示,并用key0位控制进行时分秒位的选择,当按一次时代表选中时位,两次选中分位,三次选中秒位,第四次取消选中时钟正常运行
且选中时该位的小数点会亮代表该位已被选中;key1按键用来对位进行加一操作,key2用来对位进行减一操作*/
#include<reg52.h>
#define uint unsigned int //重定义,方便使用
#define uchar unsigned char
sbit key0=P3^1; //位定义,此处赋予key0设置功能,通过对key0的操作来选中时钟的三个位
sbit key1=P3^2; //赋予key1按一次加一功能
sbit key2=P3^3; //赋予key2按一次减一功能
sbit DU=P2^0; //P2^0为段选开关,即数码管段码显示的开关
sbit WE=P2^1; //P2^1为位选开关,即数码管位数选择的开关
void delay(uint z); //延时函数
void display(); //数码管显示函数
uchar code table[]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90,0xbf}; //此处用共阳极八段数码管,前十位为0~9显示的段码,第十一个即table[10]为显示位之间的横杠的段码
uchar code wei[]={0x01,0x02,0x04,0x08,0x10,0x20,0x40,0x80}; //74HC573芯片,第二片控制位选,高四位二进制数决定位选,最高位为第一位。
uchar a[8]; //缓冲区变量,用来存放八个数码管要显示的数字;
uchar hour=05; //设置小时的初始量为05
uchar minute=21; //设置分钟的初始量为21
uchar second=00; //设置秒的初始量为00
uchar n; //定义变量n ,表示定时器T0的中断次数,以50ms一个中断,要中断20次为一秒
uchar t=0; //定义变量t,用来统计key0按下的次数,依次为条件对时分秒位进行选中之后的操作
/********延时函数 **********/
void delay(uint z){ //此处延迟函数带一个参数z,这样方便对延迟的控制,也可以不带参数,但那样要改变延迟的话只能对函数内的条件进行改变
uint j,k;
for(j=0;j<z;j++)
for(k=0;k<25;k++);
}
/******数码管显示函数******/
void display (uchar t) {
uint i;
for(i=0;i<8;i++){
P0=wei[i]; //先送位选信号,即先选择对哪一位进行显示,由于74HC573芯片的锁存特性,故对此进行一个方波的脉冲信号即可进行数据的锁存,但应先送数据后进行脉冲
WE=0;
WE=1;
WE=0; //由于控制位选的芯片和控制段选的信号连接在C51的同一个P0口处,因此当向74HC573送段选信号时,应关闭位选开关
if(t>0&&t==i){ //此处对key0按下的次数t进行判断,用来让选择的那一位的小数点亮
P0=table[a[i]]&0x7f; //注意:此处的&为与操作符,目的是让对应的数字和数字的小数点同时点亮
DU=0;
DU=1;
DU=0;
delay(10);
}
else{
P0=table[a[i]]; //对没有选中的位进行段码的输出显示
DU=0;
DU=1;
DU=0;
delay(10); //延迟
}
}
}
/******主函数*******/
void main () {
a[2]=a[5]=10; //让数码管的第3和第6位显示-
TMOD=0x01; //由于单次中断定时为50ms,因此应使用16位定时器,对应的工作方式的状态字为01,即TMOD=0x01 课本P83 表3.2
TH0=0x3C; //单片机的晶振频率为12M,定时时间为50ms,对应的时间常数的十六位显示为3CB0,往TH0中送入高八位3C 课本P86 例
TL0=0xB0; //往TL0中送入低八位B0
IE=0x82; //IE位的第7位为EA为CPU中断允许标志,第0位为定时器T0中断允许位,将这两位和EX0置1,对应的状态字为0x82 课本P79
TR0=1; //启动定时器T0 课本P83
IT0=1; //设置外部中断为眺沿触发 课本P78最后一行
IT1=1; //同理
while(1){
display(t); //开启状态对初始设定值进行显示
if(key0==0){ //当按键按下时
t++; //t自加,记录按下的次数,调时
EX0=1; //调时状态下允许外部INT0,INT1中断,即只有按下key0后,再按key1,key2才有作用
EX1=1; //用来调小时,分,秒
if(t>7){ //当调完即跳出选中状态时
t=0; //灭小数点,对计数器归零
n=0; //中断次数计数器也归零,准备开始计时
TR0=1; //启动计数器T0
EX0=0; //关闭外部中断
EX1=0;
}
else if(t==2) t=4; //调分 当按键按下两次后,为了让选中位为分的个位,让t=4,即此时选中数码管的第5位(最左侧为第一位)
else if(t==5) t=7; //调秒 同理,选中秒的个位
while(key0==0) display(t); //等待按键松开
}
if(n>=20&&t==0){ //中断20次,1秒到,正常计时状态下时钟计时
n=0;
second++;
if(second>=60){
second=0;
minute++;
if(minute>=60){
minute=0;
hour++;
if(hour>=24)
hour=0;
}
}
}
a[0]=hour/10; //把八位要显示的数字放在a[]中,方便使用
a[1]=hour%10;
a[3]=minute/10;
a[4]=minute%10;
a[6]=second/10;
a[7]=second%10;
}
}
void T0_0() interrupt 1{ //定时器T0中断服务程序
TH0=0x3C;
TL0=0xb0; //送时间常数
n++; //n计数,中断次数加一
}
void INT0_0() interrupt 0{ //外部中断INT0服务程序,为加一操作
if(t==1){ //调小时
hour++;
if(hour>=24)
hour=0;
}
if(t==4){ //调分
minute++;
if(minute>=60)
minute=0;
}
if(t==7){ //调秒
second++;
if(second>=60)
second=0;
}
}
void INT1_0() interrupt 2{ //外部中断INT1服务程序,为减一操作
if(t==1){ //调小时
hour--;
if(hour==0xff)
hour=23;
}
if(t==4){ //调分钟
minute--;
if(minute==0xff)
minute=59;
}
if(t==7){ //调秒
second--;
if(second==0xff)
second=59;
}
}