Keil51单片机解决数字显示不稳的问题
数字显示不稳,就是我们人眼的特点决定的,0.1秒的残留现象,低于这个值人眼发现不了其中变化,大于这个值就会出现同一个数字闪烁的现象。解决的方法就是所有数字,第一个的显示到最后一个的显示刷新总值低于0.1秒,即100ms。这里包括程序本身的运行时间。所以比较稳妥的办法是,计算与显示分开;显示用中断来做,如下:
#include <reg52.h>
sbit ADDR0 = P1^0;
sbit ADDR1 = P1^1;
sbit ADDR2 = P1^2;
sbit ADDR3 = P1^3;
sbit ENLED = P1^4;
sbit ENLCD = P1^5;
sbit LED0 = P0^0;
sbit LED1 = P0^1;
sbit LED2 = P0^2;
sbit LED3 = P0^3;
sbit LED4 = P0^4;
sbit LED5 = P0^5;
sbit LED6 = P0^6;
sbit LED7 = P0^7;
unsigned char code LedChar[] = {0xC0,0xF9,0xA4,0xB0,0x99,0x92,0x82,0xF8,0x80,0x90,0x88,0x83,0xC6,0xA1,0x86,0x8E};
unsigned char LedBuff[7] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
unsigned int cnt = 0; //中断计时器
//数字计算部分
void main()
{
unsigned char j=0 ;
unsigned long Sec =0;
ENLCD = 1;
ENLED = 0; //使能 U3
EA = 1; //打开中断总开关
ADDR3 = 1; //设置固定位,即数码管处于开放状态
TMOD = 0x01; //计时器运行在模式1下
TH0 = 0xFC; //FC67 1ms时长
TL0 = 0x67;
ET0 = 1; //使能T0中断
TR0 = 1; //开始T0计时器
while(1)
{
if (cnt >= 100)
{
cnt = 0; //time length control
Sec++; //1x1000ms=1 second
switch (j)
{
case 0:
{
if (Sec>9)
{
j++;
}
else
{
LedBuff[0] = LedChar[Sec%10];
LedBuff[1] = 0xFF;
LedBuff[2] = 0xFF;
LedBuff[3] = 0xFF;
LedBuff[4] = 0xFF;
LedBuff[5] = 0xFF;
};
};break;
case 1:
{
if (Sec>99)
{
j++;
}
else
{
LedBuff[0] = LedChar[Sec%10];
LedBuff[1] = LedChar[Sec/10%10];
LedBuff[2] = 0xFF;
LedBuff[3] = 0xFF;
LedBuff[4] = 0xFF;
LedBuff[5] = 0xFF;
};
};break;
case 2:
{
if (Sec>999)
{
j++;
}
else
{
LedBuff[0] = LedChar[Sec%10];
LedBuff[1] = LedChar[Sec/10%10];
LedBuff[2] = LedChar[Sec/100%10];
LedBuff[3] = 0xFF;
LedBuff[4] = 0xFF;
LedBuff[5] = 0xFF;
};
};break;
case 3:
{
if (Sec>9999)
{
j++;
}
else
{
LedBuff[0] = LedChar[Sec%10];
LedBuff[1] = LedChar[Sec/10%10];
LedBuff[2] = LedChar[Sec/100%10];
LedBuff[3] = LedChar[Sec/1000%10];
LedBuff[4] = 0xFF;
LedBuff[5] = 0xFF;
};
};break;
case 4:
{
if (Sec>99999)
{
j++;
}
else
{
LedBuff[0] = LedChar[Sec%10];
LedBuff[1] = LedChar[Sec/10%10];
LedBuff[2] = LedChar[Sec/100%10];
LedBuff[3] = LedChar[Sec/1000%10];
LedBuff[4] = LedChar[Sec/10000%10];
LedBuff[5] = 0xFF;
};
};break;
case 5:
{
if (Sec>999999)
{
j=0;
Sec = 0;
}
else
{
LedBuff[0] = LedChar[Sec%10];
LedBuff[1] = LedChar[Sec/10%10];
LedBuff[2] = LedChar[Sec/100%10];
LedBuff[3] = LedChar[Sec/1000%10];
LedBuff[4] = LedChar[Sec/10000%10];
LedBuff[5] = LedChar[Sec/100000%10];
};
};break;
default: break;
};
};
};
}
//中断程序,用于显示部分,这样运算不会影响显示,保持显示的稳定性
//Timer 0 interrupt 1
void InterruptTimer0() interrupt 3
{
static unsigned char i = 0; //这个放第一行
TH0 = 0xFC; //reload initiation setting
TL0 = 0x67;
cnt++; // 加1,这个全局变量很重要,因为它是与主程序运算部分关联
ENLED = 1; //关闭LED显示,后面赋值,再开放显示
switch (i)
{
case 0: {ADDR2 = 0; ADDR1 = 0; ADDR0 = 0; i++; P0 = LedBuff[0]; }; break; //LedBuff[0]这个也是全局数组变量,用于传递运算与显示之间的值
case 1: {ADDR2 = 0; ADDR1 = 0; ADDR0 = 1; i++; P0 = LedBuff[1]; }; break;
case 2: {ADDR2 = 0; ADDR1 = 1; ADDR0 = 0; i++; P0 = LedBuff[2]; }; break;
case 3: {ADDR2 = 0; ADDR1 = 1; ADDR0 = 1; i++; P0 = LedBuff[3]; }; break;
case 4: {ADDR2 = 1; ADDR1 = 0; ADDR0 = 0; i++; P0 = LedBuff[4]; }; break;
case 5: {ADDR2 = 1; ADDR1 = 0; ADDR0 = 1; i=0; P0 = LedBuff[5]; }; break;
default: break;
};
ENLED = 0; //瞬间打开LED显示
}