51单片机之外设——玩转数码管
2020-04-06 来源:eefocus
这篇博文,将对数码管进行介绍和驱动,与之所关联的芯片,亦是前面所讲的74HC138译码器、74HC02或非门、74HC573锁存器,所用的 I/O 口,依然是11个——P2.5P.6P2.7以及P0~P7。
首先,什么是数码管?
数码管是由多个发光二极管封装在一起,而组成的“8”字型元器件。一般开发板上所用到的是四位共阳极(或者共阴极)的数码管,也就是说,是将数码管四个四个的连在一起,并将引脚引出。下面附上四位一体的数码管以及单个数码管的原理图:
其实物图如下所示:
可见,四位一体的数码管,只是将四个数码管封装在一起,同时将所有数码管的段选引脚一起引出,位选引脚仍然单独引出而已(什么是段选?位选?接下来会介绍)。
上面说到了共阳极,那自然会有共阴极吧?是的!那什么是共阳极和共阴极呢?让我们看看他们的内部原理图就一目了然了!
其中a,b,c,d,e,f,g,dp即为数码管中每个 LED 灯(共8个),COM口是位选端。单个数码管(一位数码管)的COM口有两个(可以起到分流以及让引脚分布均匀的作用,因为元器件的引脚分布多为偶数个)。
再来看下,数码管显示的工作状态:静态数码管和动态数码管。
静态数码管:当多位数码管连接在一起时,它们的“位选”是可单独控制的,但是他们的“段选”都是连接在一起的(比如说,我们控制四位数码管的“a”灯亮,假如我们位选是选择了四位,那么四个数码管的“a”灯都会亮)。所以当我们将所有的位选一起控制时的数码管显示的模式即为“静态数码管”,此时所有的数码管显示的值都相同。
动态数码管:数码管工作时,让数码管显示出来的数值不尽相同(意思就是,我们不把所有数码管的位选一起控制)。但是这里我们会想到,明明段选是在一起的,为什么会显示的不一样呢?这里我们利用数码管的余晖效果以及人眼视觉的暂时停留现象,使人们感觉各位数码管同时再显示。而实际上,我们每次单独对一位数码管操作,再给出段选,本质上是一位一位轮流显示的,只是速度十分快,我们看不出来而已。当然,假如时不时控制位选和段选,就会造成一起不清晰的现象——这样就是我们所说的“鬼影”。所以我们在使用数码管工作时,时常要注意的操作就是“消影”。意思是每次操作完一个数码管的位选和整个数码管的段选后,操作所有的数码管进行短暂的“熄灭”。这里在后面的代码会有有分析。
下面看一下,开发板上对应的数码管的原理图(所用的是共阳极数码管):
可见,我们仍是通过138和或非门,锁存器进行控制。其中箭头所指的是网络标号的连接处,锁存器输出端的“abcdefgdp”并不是直接连接数码管的段选的“abcdefgdp”。
下面,将数码管动态显示的部分代码给出:(P2口控制数码管位选和段选的选择,P0口负责往数码管送相应的位选和段选码)
#define unsigned char
//数码管的段码:0 1 2 3 4 5 6 7 8 9 消影
uchar tab[]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90,0xff}; //用一个数组,存好数码管的十六进制段选编码
uchar dspbuf[]={10,10,10,10,10,10,10,10}; //
uchar dspcom = 0;
void display()
{
P2 = (P2 & 0x1f)|0xE0; //通过138,或非门,打开Y7C所在的锁存器,操作数码管的段选
P0 = 0xff; //通过P0口给数码管送段码0xff,让数码管熄灭,也就是“消影”操作
P2 &= 0x1f; //关闭段选锁存器
P2 = (P2 & 0x1f)|0xC0; //打开Y6C所在锁存器,操作数码管位选
P0 = (1 << dspcom); //通过P0口给数码管送位码,每次只选中一位数码管(共阳极数码管,给1是选中)
P2 &= 0x1f; //关闭位选锁存器
P2 = (P2 & 0x1f)|0xE0; //打开段选锁存器
P0 = tab[dspbuf[dspcom]; //通过P0给数码管送段码,具体数值由dspbuf[]数组而定
P2 &= 0x1f; //关闭段选锁存器
if(++dspcom == 8)
dspcom = 0; //上面的代码每次选中一位数码管,当display函数操作了7次之后,dspcom的值为8(每次先让dspbuf自加1,再与“8”做比较),若满足条件,则让dspcom重新置零,再让数码管从第一位开始扫描至最后一位,以此类推……
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
由上可见,每次通过P0 = (1 << dscom)选中数码管一位,经过dspcom加1后,再选中下一位数码管(1左移dspcom位,1后面的二进制数都是0,例如 1 << 5,即为 0010 0000;1 << 2 ,即为 0000 0100)。
而一直以来未被操作的数码管(未被位选)的段码值一直默认为“tab[dspbuf[10]]”,也就是0xff(熄灭状态),这也是一开始就把dspbuf[]数组全部赋值为“10”的原因。
例如我们这样这样写:
void main()
{
while(1)
{
dspbuf[0] = 1;
dspbuf[1] = 2;
dspbuf[2] = 3;
dspbuf[3] = 10; //其实也要我们未对第4位数码管进行操作,则其段码默认为tab[dspbuf[10]]
dsobuf[4] = 4;
dspbuf[5] = 5;
dspbuf[6] = 6;
dspbuf[7] 7;
display();
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
则,以上现象便是让数码管第1~3位分别显示“0、1、3”,第四位熄灭,第5~8位分别显示“4、5、6、7”。
而静态数码管,一般用的很少,它的存在只是为了引出动态数码管。对于它的操作,那需要把位选全部选中,再控制段选即可。当然,这样下来我们也不需要“消影”的处理了。
未完待续……
下一篇:51例程---字模