51单片机初学2-数码管动态扫描

数码管在生活中很常见,也常作为单片机的显示方式。今天我们来介绍数码管的原理及其单片机如何控制它的。

数码管虽然简单,但如果对其原理足够了解,也能玩出一些花样。

数码管有很多封装,有的只有一位,有的两位,但他们结构基本相同。现在我们以四位数码管3461BS为例。

3461BS为共阳极数码管,他有12个引脚,其中4个引脚控制位,8个引脚控制段。下图是其内部构(上为3461AS共阴,下为3461BS共阳)

我们先看单位数码管,可以看到,‘8.’的字样被分成了8段,他们每一段都就是一个小LED灯,而且每段都有一个名字,分别叫“a,b,c,d,e,f,g,dp”,其排列如图。我们先看一位数码管,可以发现,八个小LED灯的阳极是连在一起的(我们称之为公共阳极端,简称公共端),阴极则通过八个引脚引出来。如果我们要显示数字“1”,首先给公共端加入高电平(这里的高电平指能让LED灯正常工作的电压),然后把b、c段的阴极引出脚接地,这时候就会发现,8个LED灯,只有b、c段亮了,我们看到数码管上显示的正是数字1。

同样的方法,我们只要改变阴极接地的引脚就可以显示出其他数字,甚至一些字母或者符号,例如“E、L、F、H、S、C、b、n、p、d”等。

现在设想,如果我们把阴极的8个引脚按顺序与单片机的I/O口相连,不就可以通过单片机控制八段LED,从而显示出特定的字符。

假设我们选用P0口,按顺序把a,b,c,d,e,f,g,分别与P0.0~P0.7相连,只要P0口输出特定八位二进制数,就能控制数码管显示了。如此,我们就得到了数码管的编码表。

现在我们开始讨论四位数码管。

四位数码管就是四个一位数码管并联而成。不过这里的并联只并联了阴极相同名字的端口。(如四个数码管的a段阴极是相连的),它的情况要比一位的复杂一些。

静态显示:假如我们要在第一位数码管显示一个数字“1”,那我们只要给第一位数码管公共端加高电位,其他数码管的共阳极悬空,然后把第一位数码管的b,c段接地,这样,第二、三、四位数码管因为阳极没有高电位而不能电亮,第一位数码管a.b段有低电位而亮,最后的结果是:第一位显示了数字“1”,其他数码管不显示。

同理,如果要在某位数码管显示某个数,首先给该位数码管阳极加高电位,然后在阴极给对应的段加低电位。但是这种显示方式的缺点是,四个位不能同时显示不同的数字,只能显示这样的数码,例如:1___,_2__,333_,4444(_代表无显示)。

如果要显示这样的数:1234,静态显示则无法实现。这时就需要动态扫描了。

动态扫描:这种显示方式与老式电视机的显示原理类似,利用的是人眼的视觉暂留效应
回到刚才的问题,现在我们要在数码管上显示1234。四位数码管都有显示,所以四位数码管的阳极应该都要加高电位,然后在阴极给对应的段接地。现在问题来了,四位数码管显示的数字各不相同,如果把数字“1”对应的段接地,则四位数码管显示的都是1,给“2”对应的段接地,则数码管显示的都是2,根本不可能同时显示1234,似乎陷入了僵局。
解决方案是:首先我们给第一位阳极加高电位,然后把阴极数字“1”对应的段加低电位,结果是第一位显示了“1”,其他位不显示;然后把第一位阳极的高电位移除,再给第二位阳极加高电位,同时把阴极数字“2”对应的段加低电位,结果是,第二位显示了“2”,其他位不显示;接着又通过同样的方式分别在第三位显示“3”,第四位显示“4”;然后又回到第一位,如此循环。

从电位角度来看:高电位在阳极位之间循环移动,阳极的段按照“1-2-3-4-1”循环。连起来的结果是:第一位显示“1”,(其他位不显示),然后第二位显示“2”(其他位不显示),然后第三位显示“3”(其他位不显示),然后第四位显示“4”(其他位不显示),以此循环下去。

但是这样似乎还是没有同时显示“1234”。办法还是有的,刚才我们是慢动作演示,如果我们把速度加快,利用人眼的视觉暂留效应,就可以得到我们需要的效果。
视觉暂留效应:说白了就是人眼的采样速率和反应速度有限,假设你的桌上写了一个数字“1”,你正在看着它。某个时候,数字“1”突然消失(我们把这个状态记为0),实际上你在视觉上并没有立刻发觉它已经消失了,你看到的仍然是1 并维持了0.1~0.4秒,之后才发现消失;假如在很短的时间(低于0.1s)1又突然出现了,那你根本就不知道它曾经变成了0。在这段时间里,这个数字经历了1-0-1的动态过程,而在你眼里,它是一直处于“1”的静态过程。同理,当阳极的高电位从一位数码管移动到另一位数码管,经过一个循环再回到这位数码管,也就是这个数码管在一个周期里只亮了一次,理论上,只要这个数码管在灭了之后的0.1S里再次被点亮,那我们在视觉上就会觉得他是一直处于亮的静态过程。也就是把循环周期为设定小于等于0.1秒,那就能得到能需要的动态显示。单片机可以控制数码管的循环周期变得很小,小到微秒级。
另一个需要考虑的是:如果一个周期定为0.1S,对于一个数码管来说,在这段时间不是亮就是灭,控制亮灭的时间比就可以实现控制数码管的亮度,亮的时间比例越大,数码管越亮,反之越暗。这点类似于OLED屏幕的PWM调光。所以数码管也可以通过软件层面进行亮度调节。

原理已经知道,接下来我们以两片3461BS数码管显示“12345678”为例写出其控制程序。
这里我们设置P0口作为数码管段控制,P2口作为数码管位控制。

思路:

先给第一位阳极置1(P2=0x01),段输入数字1(P0=cf);延时1ms;清空段(P0=0xff);

二位阳极置1(P2=0x02);段输入数字2(P0=a4);延时1ms;清空段(P0=0xff);

三位阳极置1(P2=0x04);段输入数字3(P0=0xb0);延时1ms;清空段(P0=0xff);

四位阳极置1(P2=0x08);段输入数字4(P0=0x99);延时1ms;清空段(P0=0xff);

.........

八位阳极置1(P2=0x80);段输入数字8(P0=0x80);延时1ms;清空段(P0=0xff);

一位阳极置1(P2=0x01),段输入数字1(P0=0xcf);延时1ms;清空段(P0=0xff);

以此循环。

include <reg51.h>               //定义头文件
char codeduan[]={0xcf,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80};//段编码,使用char数据类型可以减少空间占用,除非特别需要,一般使用char类型
char codebie[]={0x01,0x02,0x04,0x10,0x20,0x40,0x80};      //位编码
void Delay1ms()		//1ms延时子函数,其值需要计算得到
{
	unsigned char i, j;
	i = 2;j = 239;
	do
	{
		while (--j);
	} while (--i);
}

void main()//   主函数
{
   char i;
   while(1)           
   {
    for(i=0;i<8;i++)
       {
        P0=codebit[i];         //PO送位
        P2=codeduan[i];        //P2送段
        Delay1ms();           //调用延时1ms函数
        P2=0xff;              //清空段防止串码
         }
   }
}


这里设置延时1ms,一个循环周期为4ms,也就是刷新一次屏幕4ms,一秒钟可以刷新1000/4=250次,相当于帧率为250FPS(从这个角度来说,已经超越很多电竞屏的刷新率)

当然这是数码管最简单的使用,因为要显示的数据是不变的,如果要显示变化的数据,则需要引入中间变量,其使用,以后会做介绍。

以上纯属个人理解,如有错误,还请指出.

猜你喜欢

转载自blog.csdn.net/qq_55203246/article/details/114437044