/*60S倒计时*/
/*个位每1S变一次,从0~9*/
/*十位,个位为0的下一秒十位发生变化*/#include<reg52.h>sbit ADDR0=P1^0;
sbit ADDR1=P1^1;
sbit ADDR2=P1^2;
sbit ADDR3=P1^3;
sbit ENLED=P1^4;unsigned char code LedChar[]=
{
0xC0,0xF9,0xA4,0xB0,0x99,0x92,0x82,0xF8,
0x80,0x90
};void main()
{unsigned int cnt=0; //记录中断次数unsigned int sec=0; //记录秒数unsigned char g=0; //个位数码管unsigned char s=6; //十位数码管 ENLED=0; //使能U3 选中数码管DS1TMOD=0x01; //T0为模式1TH0=0xB8; //T0赋初值0xB800TL0=0x00;TR0=1; //启动T0while(1){ADDR3=1;P0=0xff;ADDR2=0;ADDR1=0;ADDR0=0;P0=LedChar[g]; //选中个位数码管if(TF0==1) //判断T0是否溢出{TF0=0; //T0溢出后清零中断标志TH0=0xB8; //并重新赋值TL0=0x00;cnt++;}if(cnt>=50) //判断溢出是否达到50次{cnt=0; //达到五十次(1s)清零sec--; //秒数累加}P0=0xff;ADDR0=1;P0=LedChar[s]; //选中十位数码管,并显示当前秒数下的数字if(s==0&&g==0) //避免00状态的出现,状态60~60时间为60ss=6;if(g==0&&sec%10==1)s--;if(sec%10!=0){g=10-sec%10;}if(sec%10==0){g=0;}}
}
(1)实际上数码管状态变化为01~00~60,只不过00存在的时间过短,无法被人眼识别。
(2)在切换数码管前先让 P0=0xff 避免了前一个数码管留下的余辉。
上面程序较为繁琐,以下为更新程序:
/*60倒计时*/#include<reg52.h>sbit ADDR0=P1^0;
sbit ADDR1=P1^1;
sbit ADDR2=P1^2;
sbit ADDR3=P1^3;
sbit ENLED=P1^4;unsigned char code LedChar[]=
{
0xC0,0xF9,0xA4,0xB0,0x99,0x92,0x82,0xF8,
0x80,0x90
};unsigned int cnt=0; //记录中断次数
unsigned char flag=0; //中断标志位
unsigned char i=0; //遍历
unsigned char g=0xff; //初始化个位数码管
unsigned char s=0xff; //初始化十位数码管
unsigned int sec=61; //秒数void main()
{EA=1; //定时器总中断ENLED=0; //?使能U3ADDR3=1; //T0模式为1TMOD=0x01; //定时1msTH0=0xfc; TL0=0x67;ET0=1;TR0=1; //启动T0while(1){if(flag==1) //中断标志{ g=sec%10; s=sec/10;flag=0; //标志清0if(sec==0) //重新倒计时sec=61;}}
}
void InterruptTimer0() interrupt 1
{TH0=0xfc; //重新赋值TL0=0x67;cnt++;if(cnt>=1000) //中断累计1000 1s{cnt=0; //清0flag=1;sec--; //秒数自减 }P0=0xff;switch(i){case 0:ADDR0=0;ADDR1=0;ADDR2=0;P0=LedChar[g];i++;break; //选中个位数码管case 1:ADDR0=1;ADDR1=0;ADDR2=0;P0=LedChar[s];i=0;break; //选中十位数码管default:break;}
}
改进后,程序更为简洁直观。采用中断+switch遍历优化程序。
注意:遍历中,为了使几个数码管看起来像是同时亮,故大大缩短了定时时间,由20ms变为1ms。