当前位置: 代码迷 >> 综合 >> 6.0 动态数码管 _ [AT89C51/2] [从零开始的单片机]
  详细解决方案

6.0 动态数码管 _ [AT89C51/2] [从零开始的单片机]

热度:36   发布时间:2023-12-06 04:48:43.0

数码管简介

上一个实验是静态数码管实验,动态和静态所用的数码管都一样,在开发板上是2个四位一体的共阴数码管,唯一的区别是要不断更改输入的电平,从而达到动态的效果。
这里所说的动态并不完全是动态。这里的动态是说输入的电平时刻都在改变,这是动态,但是在数码管上显示出来的是多个数字,这些数字并不能变,按这样来说并不是动态的。

多位数码管简介

这里就要说到“段”和“位”了。
对于“位”,我们使用的数码管就是2给四位一体的共阴极数码管,“四位”即指四个“8”,下面就是一位数码管:一位数码管
对于“段”,段是从属于上面的位,上图的一位数码管有8个段:a,b,c,d,e,f,g,dp;如果遇到不一样的数码管,照着数一下就知道是几段了。

当数码管多位一体时,它们内部的公共端是独立的(位选线),它负责多位数码管的哪一位点亮;而负责显示什么数字的段线(段选线a~dp)是连接在一起的,它负责数码管的哪一段点亮、点亮什么数字。单片机通过控制这两条线来控制数码管输出。

(一般一位数码管有 10 个引脚, 二位数码管也是 10 个引脚, 四位数码管是
12 个引脚)

动态数码管显示原理

现在使用的多位数码管依然可以显示静态内容,静态只需要在端口输入恒定的电平即可,但要同时显示多种数字的话,显然是无法实现的。这就需要我们充分利用段选线以及位选线了。

上面说过,数码管的位选是独立分开的,而段选是连接在一起的。换言之,我们可以让位选线控制哪一个数码管整体点亮,但是段选线会使所有数码管的同一段点亮。假设我们给每一位选线都输送电平,其中一个段选线输入电平,结果使每一个数码管的相同一段都点亮了。
(点亮数码管只是一瞬间,但是人眼有余晖效应,只要切换的速度足够块,我们看来所有的数码管都点亮了)

这显然不是我们想要的效果,我们想要使8位数码管输出不一样的数字。这就意味着我们要不断更改输入的位选,再不断更改输入的段选,最后才能达到每一位数码管显示不同数字的效果。

要如何不间断更改数码管的导通呢?如果每一次都手动输入控制段选的电平,再加入循环体中,与位选再配合,那过于繁琐。想要高效编码,这就需要使用74HC24574HC138芯片了。

74HC245 和 74HC138芯片

先来接着上面所说手动输入8种不同的段选。如果你能够接受手动输入这样的电平输送的话,单片机核心可不太能接受。单片机的只有32个I/O口,资源很紧张,这时候就需要用少量的资源换得高效控制了,所以需要使用I/O拓展芯片,像74HC138、74HC164、74HC595,还可以通过级联方式甚至可拓展出更多的控制口(级联在LED点阵中使用)。我们开发板上使用的是74HC138芯片,可以通过控制3个端口输入控制8个端口输出,十分高效。

74HC245芯片简介

全称D74HC245,是一种三态输出、八路信号收发器,主要应用于大屏显示,以及其它的消费类电子产品中增加驱动。

特性:双向三态输出,八线双向收发器。

管脚定义及功能:
74HC545芯片
管脚定义
上图看出,OE是使能控制端口,给OE输入高低电平,结合DIR控制,可以改变芯片的输出方向及高阻态工作。

通常我们使用 74HC245 芯片用作驱动只会让其在一个方向输出,即 DIR 管脚为高电平,传输方向是 A->B。

(这里暂时不用下降沿输出什么的,就不讲解了,核心是下面的38译码器)

74HC138简介

38译码器的8个端口正好能适应段选线的8段,仅需要3个输入端即可。

全称D74HC138D,是一种三通道输入、八通道输出译码器,主要应用于消费类电子产品。

特性:三输入八输出

管脚简介:
管脚说明
上表看出,A0-A2是输入端口,Y0-Y7是输出端口,但E1,E2,E3使能控制是什么原理呢?在下表中给出了输入电平差异所形成输出电平的不同:
真值表
(表中H为高电平,L为低电平,X为任意电平)
在表的前3行中,使能控制E0-E2如果以表中的形式给出,不管输入什么电平,输出的永远是高电平,这不符合我们更改段选控制的想法。所以在编写程序时,我们直接把使能控制的端口E0,E1,E2设为低低高即可。

把使能端口恒定输入低低高之后,8个输出端就取决于A0-A2三个输入端了,控制3个端口的电平输入,便能得到8种输出形式,仔细观察发现,它们输出存在一定的规律:低电平逐渐后移。

这里给大家总结一个方法:A0、A1、A2 输入就相当于 3 位 2 进制数,A0 是
低位,A1 是次高位,A2 是高位。而 Y0-Y7 具体哪一个输出有效电平,就看输入二进制对应的十进制数值。比如输入是 101(A2,A1,A0),其对应的十进制数是 5,所以 Y5 输出有效电平(Y5段选线点通)。

硬件设计

38译码器
动态数码管模块
上图更加直观地显示出,38译码器的8个输出端口与下面动态数码管模块的8个段选是连接在一起的,所以在上面提到的74HC38译码器很重要。在编写程序是,对应真值表逐个编写A0-A2输入电平,再不断循环即可。

软件设计

#include "reg52.h"//虽然叫做动态显示,实际看起来是所有8个数码管全部点亮,因为位选是独立控制的,而段选是并在一起的,要使所有数码管输出想要的数字
//就要使每一个位选和段选轮流点亮,因此叫做动态显示typedef unsigned char u8;
typedef unsigned int u16;#define SMG_A_DP_PORT P0//定义3A0-A2三个输入端电平
sbit LSA = P2^2;
sbit LSB = P2^3;
sbit LSC = P2^4;//注意位选和段选:(两者共同作用使数码管循环导通)
//位选:哪个数码管整体导通(74HC38译码器的数据输入端)
//段选:数码管的哪一段(a~dp)选通
//位选是分开控制的,而段选是并在一起的u8 smg_code[] = {
    0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71};//共阴极数码管u8 smg_code1[] = {
    0xc0,0xf9,0xa4,0xb0,0x99,0x92,0xc0,0xf9,								 				             0xa4,0xb0,0x99,0x92,0xc6,0xa1,0x86,0x8e};//共阳极数码管void delay(u16 i)
{
    while(i--);
}void smg_display(void)
{
    u8 i = 0;for(i = 0;i<=7;i++)//for循环内不断改变输入端电平{
    switch(i)//对应74HC38译码器真值表{
    case 0: LSC=1;LSB=1;LSA=1;break;case 1: LSC=1;LSB=1;LSA=0;break;case 2: LSC=1;LSB=0;LSA=1;break;case 3: LSC=1;LSB=0;LSA=0;break;case 4: LSC=0;LSB=1;LSA=1;break;case 5: LSC=0;LSB=1;LSA=0;break;case 6: LSC=0;LSB=0;LSA=1;break;case 7: LSC=0;LSB=0;LSA=0;break;}SMG_A_DP_PORT = smg_code[i];//这里的i和上面的switch相对应,i相同delay(100);}
}void main()
{
    while(1){
    SMG_A_DP_PORT = 0x00;//消隐smg_display();}
}

让人摸不着头脑的点
在编写程序时,很容易在for循环和switch语句使用同一个循环变量i而感到疑惑。不要忘了在上面写过的数码管数组:

u8 smg_code[] = {
    0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71}//共阴数码管

在for循环内,每一次改变i都可以使数组内的十六进制数字改变,就是上一节中静态数码管中输出的数字,从0到E共16种情况;这些情况再结合上38译码器控制每一段输出,当两者同时输入一个数码管时,就已经把数字显示出来了。

(我还是觉得我的理解并不完善,如有误区请指出)

  相关解决方案