工作原理:
动态显示的特点是将所有的位数码管的段选线并联在一起,由位选线控制是哪一位数码管有效。这样一来,就没有必要每一位数码管配一个锁存器,从而大大简化了硬件电路。选亮数码管采用动态扫描显示。所谓动态扫描显示即轮流向各位数码管送出字形码和相应的位选,利用发光管的余晖和人眼视觉暂留作用,使人的感觉好像各位数码管同时都在显示。动态显示的亮度比静态要差一点。
前四个数码管分别显示1234的程序:
#include<STC15F2K60S2.H>
void Delayms(int ms);
void main(void)
{
P2=0XA0;P0=0X00;P2=0X80;P0=0XFF; //初始化程序,关闭蜂鸣器继电器LED
while(1)
{
P2=0XC0; //打开数码管位选573锁存器
P0=0X01; //选中第一个数码管
P2=0XE0; //打开数码管段选573锁存器
P0=0XF9; //使数码管显示1
Delayms(1); //1ms的延迟几乎不能分辨出来
P2=0XC0; //打开数码管位选573锁存器
P0=0X02; //选中第二个数码管
P2=0XE0; //打开数码管段选573锁存器
P0=0XA4; //使数码管显示2
Delayms(1);
P2=0XC0; //打开数码管位选573锁存器
P0=0X04; //选中第三个数码管
P2=0XE0; //打开数码管段选573锁存器
P0=0XB0; //使数码管显示3
Delayms(1);
P2=0XC0; //打开数码管位选573锁存器
P0=0X08; //选中第四个数码管
P2=0XE0; //打开数码管段选573锁存器
P0=0X99; //使数码管显示4
Delayms(1);
}
}
void Delayms(int ms)
{
int i,j;
for(i=0;i<ms;i++)
for(j=845;j>0;j--);
}
数码管99秒倒计时程序:
#include<STC15F2K60S2.H>
unsigned char tab[]={0XC0,0XF9,0XA4,0XB0,0X99,0X92,0X82,0XF8,0X80,0X90};
unsigned char num=99;
unsigned int i=0;
void Delayms(int ms);
void main(void)
{
P2=0XA0;P0=0X00;P2=0X80;P0=0XFF; //关闭蜂鸣器继电器LED
while(1)
{
i++;
if(i==500) //由于下面的两个数码管一共延时2ms,故循环500次即1s数码管变化一次
{
i=0;
if(num==0)num=100; //计时结束,重新计时
num--;
}
P2=0XC0; //打开数码管位选537锁存器
P0=0X01; //选中第一个数码管
P2=0XE0; //打开数码管段选537锁存器
P0=tab[num/10]; //数码管显示十位的数字
Delayms(1);
P2=0XC0; //打开数码管位选537锁存器
P0=0X02; //选中第二个数码管
P2=0XE0; //打开数码管段选537锁存器
P0=tab[num%10]; //数码管显示个位的数字
Delayms(1);
}
}
void Delayms(int ms)
{
int i,j;
for(i=0;i<ms;i++)
for(j=845;j>0;j--);
}
数码管99秒倒计时程序,用定时器延迟。
#include<STC15F2K60S2.H>
unsigned char tab[]={0XC0,0XF9,0XA4,0XB0,0X99,0X92,0X82,0XF8,0X80,0X90};
unsigned char num=99;
unsigned char tt=0;
void Delayms(int ms);
void Timer0Init(void);
void main(void)
{
P2=0XA0;P0=0X00;P2=0X80;P0=0XFF; //关闭蜂鸣器继电器LED
//初始化配置定时器0
Timer0Init();
ET0=1;
EA=1;
while(1)
{
P2=0XC0; //打开数码管位选537锁存器
P0=0X01; //选中第一个数码管
P2=0XE0; //打开数码管段选537锁存器
P0=tab[num/10]; //数码管显示十位的数字
Delayms(1);
P2=0XC0; //打开数码管位选537锁存器
P0=0X02; //选中第二个数码管
P2=0XE0; //打开数码管段选537锁存器
P0=tab[num%10]; //数码管显示个位的数字
Delayms(1);
}
}
void Delayms(int ms)
{
int i,j;
for(i=0;i<ms;i++)
for(j=845;j>0;j--);
}
void Timer0Init(void) //5毫秒@11.0592MHz
{
AUXR |= 0x80; //定时器时钟1T模式
TMOD &= 0xF0; //设置定时器模式
TL0 = 0x00; //设置定时初值
TH0 = 0x28; //设置定时初值
TF0 = 0; //清除TF0标志
TR0 = 1; //定时器0开始计时
}
void Timer0(void) interrupt 1
{
tt++;
if(tt==200)
{
tt=0;
if(num==0)num=100;
num--;
}
}
此程序实现了用定时器0来进行数码管计时间隔1s的延时,而扫描的1ms仍使用了软件延时。
大致思路:我们可以看到原来的程序是在主函数中,计数循环次数,循环500次即1s,操作使num自减,而此程序是在定时器中定时1s,定时到了num自减。其核心思想都是使num每1s自减1。
数码管99秒倒计时程序,调用子函数(第一种方法)
#include<STC15F2K60S2.H>
unsigned char num=99;
unsigned char tab[]={0XC0,0XF9,0XA4,0XB0,0X99,0X92,0X82,0XF8,0X80,0X90};
unsigned int i=0;
unsigned char yi,er;
void Display(unsigned char yi,unsigned char er);
void Delayms(int ms);
void main(void)
{
P2=0XA0;P0=0X00;P2=0X80;P0=0XFF; //关闭蜂鸣器继电器LED
while(1)
{
i++;
if(i==500)
{
i=0;
if(num==0)num=100; //计时结束,重新计时
num--;
}
yi=num/10;
er=num%10;
Display(yi,er);
}
}
void Delayms(int ms)
{
int i,j;
for(i=0;i<ms;i++)
for(j=845;j>0;j--);
}
void Display(unsigned char one,unsigned char two)
{
P2=0XC0; //打开数码管位选573锁存器
P0=0X01; //选中第一个数码管
P2=0XE0; //打开数码管段选573锁存器
P0=tab[one]; //显示十位
Delayms(1);
P2=0XC0; //打开数码管位选573锁存器
P0=0X02; //选中第二个数码管
P2=0XE0; //打开数码管段选573锁存器
P0=tab[two]; //显示个位
Delayms(1);
}
数码管99秒倒计时程序,调用子函数(第二种方法)
#include<STC15F2K60S2.H>
unsigned char num=99;
unsigned char tab[]={0XC0,0XF9,0XA4,0XB0,0X99,0X92,0X82,0XF8,0X80,0X90};
unsigned int i=0;
void Display(unsigned char sum);
void Delayms(int ms);
void main(void)
{
P2=0XA0;P0=0X00;P2=0X80;P0=0XFF; //关闭蜂鸣器继电器LED
while(1)
{
i++;
if(i==500)
{
i=0;
if(num==0)num=100; //计时结束,重新计时
num--;
}
Display(num);
}
}
void Delayms(int ms)
{
int i,j;
for(i=0;i<ms;i++)
for(j=845;j>0;j--);
}
void Display(unsigned char sum)
{
P2=0XC0; //打开数码管位选573锁存器
P0=0X01; //选中第一个数码管
P2=0XE0; //打开数码管段选573锁存器
P0=tab[sum/10]; //显示十位
Delayms(1);
P2=0XC0; //打开数码管位选573锁存器
P0=0X02; //选中第二个数码管
P2=0XE0; //打开数码管段选573锁存器
P0=tab[sum%10]; //显示个位
Delayms(1);
}
8个数码管的程序,前2位仍然99秒倒计时,其他位依次为345678
//8个数码管的程序,让前两位仍然99秒倒计时,其他位分别显示345678
#include<STC15F2K60S2.H>
unsigned char num=99;
unsigned char tab[]={0XC0,0XF9,0XA4,0XB0,0X99,0X92,0X82,0XF8,0X80,0X90};
unsigned int i=0;
unsigned char yi,er,san,si,wu,liu,qi,ba;
void Delayms(int ms);
void Display1(unsigned char yi,unsigned char er);
void Display2(unsigned char san,unsigned char si);
void Display3(unsigned char wu,unsigned char liu);
void Display4(unsigned char qi,unsigned char ba);
void main(void)
{
P2=0XA0;P0=0X00;P2=0X80;P0=0XFF; //关闭蜂鸣器继电器LED
while(1)
{
i++;
if(i==125)
{
i=0;
if(num==0)num=100;
num--;
}
yi=num/10;
er=num%10;
san=3;si=4;wu=5;liu=6;qi=7;ba=8;
Display1(yi,er);
Display2(san,si);
Display3(wu,liu);
Display4(qi,ba);
}
}
void Delayms(int ms)
{
int i,j;
for(i=0;i<ms;i++)
for(j=845;j>0;j--);
}
void Display1(unsigned char yi,unsigned char er)
{
P2=0XC0; //打开数码管位选537锁存器
P0=0X01; //选中第一个数码管
P2=0XE0; //打开数码管段选537锁存器
P0=tab[yi]; //显示yi对应的数值
Delayms(1);
P2=0XC0; //打开数码管位选537锁存器
P0=0X02; //选中第二个数码管
P2=0XE0; //打开数码管段选537锁存器
P0=tab[er]; //显示er对应的数值
Delayms(1);
}
void Display2(unsigned char san,unsigned char si)
{
P2=0XC0; //打开数码管位选537锁存器
P0=0X04; //选中第三个数码管
P2=0XE0; //打开数码管段选537锁存器
P0=tab[san]; //显示san对应的数值
Delayms(1);
P2=0XC0; //打开数码管位选537锁存器
P0=0X08; //选中第四个数码管
P2=0XE0; //打开数码管段选537锁存器
P0=tab[si]; //显示si对应的数值
Delayms(1);
}
void Display3(unsigned char wu,unsigned char liu)
{
P2=0XC0; //打开数码管位选537锁存器
P0=0X10; //选中第五个数码管
P2=0XE0; //打开数码管段选537锁存器
P0=tab[wu]; //显示wu对应的数值
Delayms(1);
P2=0XC0; //打开数码管位选537锁存器
P0=0X20; //选中第六个数码管
P2=0XE0; //打开数码管段选537锁存器
P0=tab[liu]; //显示liu对应的数值
Delayms(1);
}
void Display4(unsigned char qi,unsigned char ba)
{
P2=0XC0; //打开数码管位选537锁存器
P0=0X40; //选中第七个数码管
P2=0XE0; //打开数码管段选537锁存器
P0=tab[qi]; //显示qi对应的数值
Delayms(1);
P2=0XC0; //打开数码管位选537锁存器
P0=0X80; //选中第八个数码管
P2=0XE0; //打开数码管段选537锁存器
P0=tab[ba]; //显示ba对应的数值
Delayms(1);
}
由上可知,想要哪一位显示哪一个值,即可在主函数中相应的对变量赋值,例如:想要第三个显示8,即san=8(也可以为一个可求出值的表达式,如上程序中yi=num/10)
注:通过观察我们可以发现,主函数和子函数中均有yi,er,san…它们是否冲突是否会被认为是重复定义?实则不然,在C语言中变量分为整体变量和局部变量,且局部变量优先于整体变量,也就是当我们在子函数和主函数中都定义了yi,那么在子函数过程中,yi遵循的是子函数的定义,而主函数对它的定义在子函数中是无效的。当然,在仅有主函数定义而没有子函数定义时,即便它在子函数中,也一定遵循主函数的定义,为整体变量。