C51数码管鬼影产生的一个解决方法
(这个方法有助于加深对于中断的理解)
在今天设计一个关于数码管的秒表时,采用了 以下代码
:
#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, 0x88, 0x83, 0xC6, 0xA1, 0x86, 0x8E
};
unsigned char LedBuff[6] =
{
0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};
unsigned char i=0;
unsigned int cnt=0;
unsigned char flag=0;
void main()
{
unsigned long sec=0;
EA=1;ENLED=0;ADDR3=1;TMOD=0X01;
TH0=0XFC;TL0=0X67;ET0=1;TR0=1;
while(1)
{
if(flag==1)
{
flag=0;sec++;
LedBuff[0] = LedChar[sec%10];
LedBuff[1] = LedChar[sec/10%10];
LedBuff[2] = LedChar[sec/100%10];
if (sec/100%10==0&&sec/10%10==0)
{
LedBuff[2] = 0xFF;
LedBuff[1] = 0xFF;
};
if (sec/100%10==0&&sec/10%10!=0)
{
LedBuff[2] = 0xFF;
};
LedBuff[3] = 0x40;
LedBuff[4] = 0x4F;
LedBuff[5] = 0x5B;
}
}
}
void InterruptTimer0() interrupt 1
{
TH0=0XFC;TL0=0X67;cnt++;
if(cnt>=1000){cnt=0;flag=1;}
P0=0X00;
switch (i)
{
case 0: ADDR2=1; ADDR1=0; ADDR0=1; i++; P0=~LedBuff[0]; break;
case 1: ADDR2=1; ADDR1=0; ADDR0=0; i++; P0=~LedBuff[1]; break;
case 2: ADDR2=0; ADDR1=1; ADDR0=1; i++; P0=~LedBuff[2]; break;
case 3: ADDR2=0; ADDR1=1; ADDR0=0; i++; P0=LedBuff[3]; break;
case 4: ADDR2=0; ADDR1=0; ADDR0=1; i++; P0=LedBuff[4]; break;
case 5: ADDR2=0; ADDR1=0; ADDR0=0; i=0; P0=LedBuff[5]; break;
default: break;
}
}
;
原本目的是三位秒表如果百位为0则不会亮,但是却出现了鬼影现象,这是为什么呢?
个人的理解是,在以下代码处,由于原本采用的定时器中断方式,在定时器即将溢出时,代码刚好运行到 if 之前,则会带着错误的LedBuff值进入中断程序,产生鬼影
LedBuff[1] = LedChar[sec/10%10];
LedBuff[2] = LedChar[sec/100%10];
if (sec/100%10==0&&sec/10%10==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, 0x88, 0x83, 0xC6, 0xA1, 0x86, 0x8E
};
unsigned char LedBuff[6] =
{
0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};
unsigned char i = 0;
unsigned int cnt = 0;
unsigned char flag = 0;
unsigned long sec = 0;
void main()
{
EA=1;ENLED=0;ADDR3=1;TMOD=0X01;
TH0=0XFC;TL0=0X67;ET0=1;TR0=1;
while(1);
}
void InterruptTimer0() interrupt 1
{
LedBuff[3] = 0x40;
LedBuff[4] = 0x4F;
LedBuff[5] = 0x5B;
if(flag==1)
{
flag=0;sec++;
LedBuff[0] = LedChar[sec%10];
LedBuff[1] = LedChar[sec/10%10];
LedBuff[2] = LedChar[sec/100%10];
if (sec/100%10==0&&sec/10%10==0){
LedBuff[2] = 0xFF;
LedBuff[1] = 0xFF;
}
if (sec/100%10==0&&sec/10%10!=0){
LedBuff[2] = 0xFF;
}
}
TH0 = 0XFC;
TL0 = 0X67;
cnt++;
if(cnt >= 1000){
cnt = 0;
flag = 1;
}
P0=0X00;
switch (i)
{
case 0: ADDR2=1; ADDR1=0; ADDR0=1; i++; P0=~LedBuff[0]; break;
case 1: ADDR2=1; ADDR1=0; ADDR0=0; i++; P0=~LedBuff[1]; break;
case 2: ADDR2=0; ADDR1=1; ADDR0=1; i++; P0=~LedBuff[2]; break;
case 3: ADDR2=0; ADDR1=1; ADDR0=0; i++; P0=LedBuff[3]; break;
case 4: ADDR2=0; ADDR1=0; ADDR0=1; i++; P0=LedBuff[4]; break;
case 5: ADDR2=0; ADDR1=0; ADDR0=0; i=0; P0=LedBuff[5]; break;
default: break;
}
}