51单片机:动态数码管显示
- 模块图
- 显示原理
– 消抖
静态数码管技术 + 人眼视觉停留
显示原理类似于以前的 胶片机放影视,也就是只要我切换的速度足够快你就看不出来其实我是一次次显示的(滑稽)
影视中为了流畅,我们的最低帧数为24帧,即每秒钟放24张影视图和24张黑屏,那么一张图片的周期为 T = 1s/(24+24) = 20.8ms。
而在动态数码管的显示中,假设我们为8数码管,则一张视图应该是8个数码管共同的时间,即应该在原来周期上除以8, T = 1s/(24+24)/8 = 2.6ms。
讲了这些能干啥呢?
消抖啊!不然显示出来后就跟影流之主一样。
– 数码管显示
段选控制哪个数码管亮,位选控制数码管显示的值。
– 码表
共阴极数码管码表 = ~共阳极数码管码表
共阴极数码管码表:
unsigned char code table[] = {0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,
0x07,0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71};
话不多说,上代码:
#include "reg52.h"
#include "intrins.h"
//38译码器A、B、C
sbit sA = P1^0;
sbit sB = P1^1;
sbit sC = P1^2;
//位选控制码表
unsigned char code table[] = {0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,
0x07,0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71};
//延迟1ms
void delay500us(void) //误差 0us
{
unsigned char a,b;
for(b=71;b>0;b--)
for(a=2;a>0;a--);
}
//显示八数码管
void showDigital()
{
int i;
for(i=0;i<8;i++)
{
switch(i)
{
case(0):
sA = 0;sB = 0;sC = 0;break;
case(1):
sA = 1;sB = 0;sC = 0;break;
case(2):
sA = 0;sB = 1;sC = 0;break;
case(3):
sA = 1;sB = 1;sC = 0;break;
case(4):
sA = 0;sB = 0;sC = 1;break;
case(5):
sA = 1;sB = 0;sC = 1;break;
case(6):
sA = 0;sB = 1;sC = 1;break;
case(7):
sA = 1;sB = 1;sC = 1;break;
}
P0 = table[i+1];
delay500us();
P0 = 0x00;
}
}
void main()
{
while(1)
showDigital();
}
稍微再加点小功能:用红外遥控显示静态数码管
#include "reg52.h"
#include "intrins.h"
//38译码器A、B、C
sbit sA = P1^0;
sbit sB = P1^1;
sbit sC = P1^2;
//中断0
sbit IRIN = P3^2;
//接收到的4组数据
unsigned char IrValue[4];
unsigned char Time;
//位选控制码表
unsigned char code table[] = {0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,
0x07,0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71};
//延迟1ms
void delay500us(void) //误差 0us
{
unsigned char a,b;
for(b=71;b>0;b--)
for(a=2;a>0;a--);
}
//显示八数码管
void showDigital()
{
int i;
if(IrValue[2] == 0x44)
{
for(i=0;i<8;i++)
{
switch(i)
{
case(0):
sA = 0;sB = 0;sC = 0;break;
case(1):
sA = 1;sB = 0;sC = 0;break;
case(2):
sA = 0;sB = 1;sC = 0;break;
case(3):
sA = 1;sB = 1;sC = 0;break;
case(4):
sA = 0;sB = 0;sC = 1;break;
case(5):
sA = 1;sB = 0;sC = 1;break;
case(6):
sA = 0;sB = 1;sC = 1;break;
case(7):
sA = 1;sB = 1;sC = 1;break;
}
P0 = table[i+1];
delay500us();
P0 = 0x00;
}
}
else if(IrValue[2] == 0x45)
{
for(i=0;i<8;i++)
{
switch(i)
{
case(0):
sA = 0;sB = 0;sC = 0;break;
case(1):
sA = 1;sB = 0;sC = 0;break;
case(2):
sA = 0;sB = 1;sC = 0;break;
case(3):
sA = 1;sB = 1;sC = 0;break;
case(4):
sA = 0;sB = 0;sC = 1;break;
case(5):
sA = 1;sB = 0;sC = 1;break;
case(6):
sA = 0;sB = 1;sC = 1;break;
case(7):
sA = 1;sB = 1;sC = 1;break;
}
P0 = table[6];
delay500us();
P0 = 0x00;
}
}
else
{
for(i=0;i<8;i++)
{
switch(i)
{
case(0):
sA = 0;sB = 0;sC = 0;break;
case(1):
sA = 1;sB = 0;sC = 0;break;
case(2):
sA = 0;sB = 1;sC = 0;break;
case(3):
sA = 1;sB = 1;sC = 0;break;
case(4):
sA = 0;sB = 0;sC = 1;break;
case(5):
sA = 1;sB = 0;sC = 1;break;
case(6):
sA = 0;sB = 1;sC = 1;break;
case(7):
sA = 1;sB = 1;sC = 1;break;
}
P0 = table[0];
delay500us();
P0 = 0x00;
}
}
}
void IrInit()
{
IT0=1;//下降沿触发
EX0=1;//打开中断0允许
EA=1; //打开总中断
IRIN=1;//初始化端口
}
void delay(unsigned int i)
{
while(i--);
}
void ReadIr() interrupt 0
{
unsigned char j,k;
unsigned int err;
Time=0;
delay(700); //7ms
if(IRIN==0) //确认是否真的接收到正确的信号
{
err=1000; //1000*10us=10ms,超过说明接收到错误的信号
while((IRIN==0)&&(err>0)) //等待前面9ms的低电平过去
{
delay(1);
err--;
}
if(IRIN==1) //如果正确等到9ms低电平
{
err=500;
while((IRIN==1)&&(err>0)) //等待4.5ms的起始高电平过去
{
delay(1);
err--;
}
for(k=0;k<4;k++) //共有4组数据
{
for(j=0;j<8;j++) //接收一组数据
{
err=60;
while((IRIN==0)&&(err>0))//等待信号前面的560us低电平过去
{
delay(1);
err--;
}
err=500;
while((IRIN==1)&&(err>0)) //计算高电平的时间长度。
{
delay(10); //0.1ms
Time++;
err--;
if(Time>30)
{
return;
}
}
IrValue[k]>>=1; //k表示第几组数据
if(Time>=8) //如果高电平出现大于565us,那么是1
{
IrValue[k]|=0x80;
}
Time=0; //用完时间要重新赋值
}
}
}
if(IrValue[2]!=~IrValue[3])
{
return;
}
}
}
void main()
{
IrInit();
while(1)
{
showDigital();
}
}