《51单片机动态数码管消影问题研究》
前文:
自学习单片机的路上 在网上查的资料很多不好理解甚至有些是有错误的,后面通过学习网课咨询学长有了自己的理解,现想发布文章表达自己的见解。
此次开发板采用的是普中51A2实验板,编程软件是Keil uVision5,烧录软件采用的STC-SIP(V6.86O),编译语言选择的是C语言。
本文将介绍实现动态数码管的原理,如何解决消隐问题及其原理。
正文:
Ⅰ:
(数码管工作模板图)
在学习过静态数码管之后,我们都知道为了节省使用管脚的个数,将数码管内的LED模块的阴极(ps:有些开发板是阳极)接到一块,我们称之为共阴极(共阳极)。每个LED模块内的8个LED灯又分别接在一起,分别由同一个管脚控制(P0_0~P0_7)。
要点亮LED灯的话就要有电位差,因为LED模块是共阴极,那么通过译码器给公共端高电平,就相当于正极与负极直接相连接,无论位选部分给予高电平还是低电平LED模块里都不会有电流经过,不会被点亮。所以在公共端给予低电平,再给予八个LED小灯不同的高低电平,达到显示出不同的数字。
那么在硬件上各个模块的两端都连接在一起,改变了一个管脚就是改变了数码管的电平,根本无法达到让不同的LED模块显示不同的数字。在硬件上行不通只能在软件上动手,利用人的视觉暂留现象,通过各个模块不停的快速变换数字达到一种不同数字同一时间显示的现象。那么让我们来看看具体的代码是如何实现的。
#include<regx52.h>
//自定义延时函数
void delay(unsigned int num)
{
unsigned char i, j;
while(num)
{
i = 2;
j = 199;
do
{
while (--j);
} while (--i);
num--;
}
}
//定义段选数组
unsigned char shape[9]={0x7f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x7,0xff};
//定义函数
void led(unsigned int num,unsigned int num_1)
{
switch(num)//位选
{
case 1:P2_4=1;P2_3=1;P2_2=1;break;
case 2:P2_4=1;P2_3=1;P2_2=0;break;
case 3:P2_4=1;P2_3=0;P2_2=1;break;
case 4:P2_4=1;P2_3=0;P2_2=0;break;
case 5:P2_4=0;P2_3=1;P2_2=1;break;
case 6:P2_4=0;P2_3=1;P2_2=0;break;
case 7:P2_4=0;P2_3=0;P2_2=1;break;
case 8:P2_4=0;P2_3=0;P2_2=0;break;
}
P0=shape[num_1];//段选
}
//主函数
void main()
{
while(1)
{
//led("第几个LED模块","显示什么数字")
led(1,1);led(2,2);led(3,3);led(4,4);
}
}
编译以上代码,进行烧录。
仔细去看的话不难看出除了应该被点亮的LED小灯外也有出现不同程度的亮光,而且是有规律的,例如1号位有‘4’的模样,2号位有‘1’的模样,3号位有‘2’的模样,4号位有‘3’的模样。那为什么会出现这种现象。
Ⅱ:
根据数码管显示的原理,显示的顺序是 位选 –>段选–>位选–>段选–>位选 这样循环,而问题就出现在段选–>位选这里,虽然单片机工作频率很快但是也是需要一定的时间来工作,当完成一个操作内的位选之后,段选之前的这段单片机还在工作的时间里,我称之为“空白时间”。在“空白时间”内,由于还未进行下一个段选,此时的段选还是上一个操作里的段选,导致LED模块显示的是上一个LED模块的样子。
那么应该如何解决这种现象呢,也就是我所说的消影。
解决办法有两种:
一:利用延时达到减缓的效果。
1.可以在主函数内依次调用延时函数。
void main()
{
while(1)
{
//led("第几个LED模块","显示什么数字")
led(1,1);delay(5);led(2,2);delay(5);led(3,3);delay(5);led(4,4);delay(5);
}
}
2.可以在位段选函数内调用延时函数。
void led(unsigned int num,unsigned int num_1)
{
switch(num)//段选
{
case 1:P2_4=1;P2_3=1;P2_2=1;break;
case 2:P2_4=1;P2_3=1;P2_2=0;break;
case 3:P2_4=1;P2_3=0;P2_2=1;break;
case 4:P2_4=1;P2_3=0;P2_2=0;break;
case 5:P2_4=0;P2_3=1;P2_2=1;break;
case 6:P2_4=0;P2_3=1;P2_2=0;break;
case 7:P2_4=0;P2_3=0;P2_2=1;break;
case 8:P2_4=0;P2_3=0;P2_2=0;break;
}
P0=shape[num_1];//位选
delay(5);
}
通过百度了解到人的视觉暂留视觉大概是0.05-0.2s,所以我调用的是采用的是5毫米的延时。
进行烧录。
可以看出消影得到了较好的结果,那么我们将延时5毫秒改成0.5毫秒呢。话不多说,开烧!
可以看到把时间改为0.5毫秒之后就寄掉了,单片机工作频率很高,处理时间很快,0.5毫秒时间人根本来不及反应。残影现象还是很严重。
同样把延时时间改为50毫秒后就出现了明显的停顿。
小总结:利用延时来抵消人的视觉暂留现象达到消影的只能说是治标不治本。问题的根本没有得到解决,效果也不是很好。(其实拍摄延时函数为5毫秒的现象的时候,由于手机摄像头刷新率比人眼低,通过手机看数码管的时候,我可以明显的看到残影部分也在跟着闪烁)
现在介绍彻底解决这种现象的办法
二:重置段选代码。
在段选和下一位选之间添加一段重置代码即可彻底消影。具体代码如下:
void led(unsigned int num,unsigned int num_1)
{
switch(num)//段选
{
case 1:P2_4=1;P2_3=1;P2_2=1;break;
case 2:P2_4=1;P2_3=1;P2_2=0;break;
case 3:P2_4=1;P2_3=0;P2_2=1;break;
case 4:P2_4=1;P2_3=0;P2_2=0;break;
case 5:P2_4=0;P2_3=1;P2_2=1;break;
case 6:P2_4=0;P2_3=1;P2_2=0;break;
case 7:P2_4=0;P2_3=0;P2_2=1;break;
case 8:P2_4=0;P2_3=0;P2_2=0;break;
}
P0=shape[num_1];//位选
delay(1);
P0=0x00;
}
这里调用延时函数也是为了消隐,只不过是一种“空白的影”,不加的话亮度会比较暗,原理也是一样的。
效果图如下:
可以看到残影已经得到了完全消除,达到了我们想要的效果。
后文:
文章到这里就结束啦!本人语文不是很好有些地方可能没有表达清楚,或者是哪里用词不当,这也是我第一次写文章,可能做的不是很好看,布局什么的也不均衡,请大家多多谅解,还是要多向大佬学习!