购买
下载掌阅APP,畅读海量书库
立即打开
畅读海量书库
扫码下载掌阅APP

第7章
LED数码管动态显示:驱动设计

接下来我们在图6.6所示仿真电路的基础上编程以实现数码管显示数字的功能,首先梳理一下动态扫描驱动的主要流程,如图7.1所示。

图7.1 4位数码管扫描流程

其中,初始化的主要工作是取消所有位选(对于共阳数码管,可以设置所有位选通为全0),这样能够使所有数码管都无任何显示,然后按照一定顺序循环显示每一位数字即可。需要注意的是,每位数码管显示数毫秒后都会取消显示,然后才进行下一位数字的显示,这就是为了避免前面提到的显示串位现象。

下面来看相应的源代码,如清单7.1所示。

首先给P1(段显示驱动引脚)与P3(位选通驱动引脚)分别定义别名为SEGMENT_PORT与COM_SELECT_PORT,这样就无需死记那些没有意义的引脚名了。然后定义了两个数组,其中display_char数组保存了数字0~9对应的共阴数码管显示字型码,而com_select数组保存了四位数码管的位选通数据,每一个数据只有1位为1,表示任意时刻仅有一位(共阳)数码管处于选通有效状态。例如,当索引为0时,bit_select [0]为0x8,表示最右侧的数码管处于选通状态。当索引为1时,bit_select [1]为0x4,表示右起第2位数码管处于选通状态,其他依此类推(注意单片机与数码管位选通的对应方式: P3.0对应数码管最左侧数字位选通,P3.3对应数码管最右侧数字位选通 )。

重点还是segment_display显示函数,只要给它输入一个十进制数字,就可以在数码管上显示出来。前面已经说过,动态扫描其实是循环依次驱动每个数码管显示数字,所以必须首先获取十进制数字的个、十、百、千四位数字,为此我们在代码中使用了除法“/”与求余“%”两个运算符,现在只需要知道两点:

清单7.1 动态驱动四位共阳数码管

其一 ,一个多位(十进制)数字与10(十进制)相除相当于该数字右移一位 ,因为除10后原来的个位数成了小数,转换为整数后就会被丢弃。例如,9527/10=952。

其二, 一个多位(十进制)数字对10(十进制)求余可以得到个位数字 。例如9527%10=7。

清单7.1所示源代码中获取个、十、百、千四位数字的过程如图7.2所示。

图7.2 获取十进制的各位数字

接下来按一定顺序分别显示个、十、百、千位数字即可。首先使用for语句表示将要显示4位数字,在switch分支语句中,先通过查找display_char数组将需要显示的字型码进行推送,之后再通过查找bit_select数组把(刚刚推送字型码对应的)位选通进行推送,也就能够让数字在显示在相应的数码管。

然后延时约3ms后取消了所有位选通(置0),接下来继续显示下一位,直到4位数码管都依次完成扫描。

在main主函数中,首先将显示的数字初始化为“9527”,并且将所有位选通设置为全0,这也就意味着所有数码管默认都不显示。while循环中的语句需要特别注意: 我们调用了100次segment_display函数,再对数字进行加1 。这样就可以获得“数码管显示的数字每隔约1s就会累加”的效果。

为什么要调用100次segment_display函数呢?其实它所起的作用就是延时约1s。那为什么不使用delay_ms函数来延时呢?因为我们之前已经提过,动态扫描是不停地对多位数码管的每一位进行循环点亮过程,调用delay_ms函数延时1s本没有错,但是单片机在这1s却什么事都没有做(也就是说,数码管并未处于动态扫描状态),所以就根本看不到有数字显示,因为segment_display函数调用一遍后就把所有位选通都关闭了,随后就进入了刚调用的那个“1s什么事都不做”的delay_ms函数。为此我们使用多次调用segment_display函数的方式达到延时的目的,同时也完成了动态扫描的工作,实在是太完美了!

图6.6所示电路使用的元器件还是有点多,下面来看看另一种驱动8位共阴数码管的电路,相应的Proteus仿真效果如图7.3所示。

与图6.6所示电路主要有一点不同,那就是使用了一块芯片74HC138代替了位选通三极管,它是一个3-8译码器,也就是说,给它输入相应的BCD码,相应某一位就会被拉低,也就是输出低有效(原理图上的输出引脚有个圈圈)。换句话说,使用74HC138只能用来驱动共阴数码管。

下面来看看74HC138的真值表,见表7.1。

74HC138有 、E 3 为三个使能引脚,只有它们全部处于使能状态的前提下,其中一个输出引脚才会根据对应的输入数据拉为低电平,否则输出均为高电平,为此我们将 与公共地连接,而E 3 与电源连接。

我们来看一下相应的驱动程序,如清单7.2所示。

图7.3 动态驱动8位共阴数码管

表7.1 74HC138真值表

清单7.2 动态驱动8位共阴数码管

大部分代码与清单7.1相同,为了避免清单过长占用过多篇幅,函数没有输入十进制数字,而是直接使用常数对display_char数组进行查表,这样显示的数字就是不变的,读者可自行更改代码使其实现数字累加1的显示功能。

有一点需要注意,在“使所有数码管不亮”时并不是使用取消位选通的方式,而是取消字型码输出(对于共阴数码管就是设置全0,对于共阳数码就是设置全1),因为按照我们的硬件连接方式,74HC138的输出总会至少有一个是低电平,无法做到全部位选通取消的功能。当然,也可以修改一下硬件电路,由单片机来控制74HC138的使能引脚,继而达到使74HC138输出全1的目的,读者可自行琢磨一下。

还有一个问题需要明确的是: 使用动态扫描方式驱动数码管时,是否需要添加限流电阻呢 ?尽管仿真时我们并未这么做(为了简化电路),但答案仍然是肯定的。

有人可能会反驳:我亲手用元器件搭建的驱动电路也没有使用限流电阻,可是数码管的显示效果好着呢!对此只能回复:如果只是自己在家里玩玩还可以,但是作为商用却是不成熟的。不添加限流电阻可能会导致数码管发光单元的峰值电流超过额定值,虽然一时半会产生的影响不会马上显现,然而一旦长时间工作很有可能会引起光衰现象,并将导致数码管的寿命提前终结。

有人又抬扛说:我见过很多专门用来驱动数码管的动态扫描芯片都不需要连接限流电阻呀!这就是只知其一,不知其二了,因为专用芯片基本都是采用 恒流 驱动方案,后续我们会详细讨论。

限流电阻应该设置为多大呢 ?首先需要说明的是,在保证显示亮度一致的前提下,采用动态扫描方式驱动数码管时,流过发光单元的正常峰值电流会比静态驱动时要大得多,因为LED的发光亮度取决于注入电流的平均值时。假设同样的LED被注入如图7.4所示的两种电流波形。

图7.4 两种不同的电流波形

图7.4a给LED注入10mA的直流电流,而图7.4b给LED注入的却是40mA的脉冲电流(假设脉冲周期为 T ,脉冲宽度为 T /4),虽然后者的电流峰值比前者要大4倍,但是它们的平均电流却是一样的,所以LED的发光亮度也是相同的。

也就是说,在考虑给动态扫描驱动电路添加限流电阻时,应该以 峰值电流 为依据,而不再是平均电流。假设LED发光单元的正向导通电压为2V,供电电源为5V,峰值电流为40mA,根据式(1.1)则可计算出相应的限流电阻为(5V-2V)/40mA=75Ω。

有心人可能会突发奇想:既然LED发光亮度由流过其中的平均电流决定,那我不就可以通过软件编程控制每个数码管的选通时间来调节亮度吗?这比拿铬铁更换限流电阻可要方便得多呀!

你真是太有才了!因为这种调节亮度的方法是现如今广泛使用的 脉冲宽度调制 (Pulse Width Modulation,PWM)技术。具体来说,它就是在调节周期信号的占空比(Duty Ratio)。占空比的定义是周期信号的高电平宽度与周期的比值,如图7.5所示。

图7.5 占空比的定义

假设周期信号的周期为 t ,每个周期中高电平宽度为 t on ,低电平宽度为 t o ,则相应的占空比则为 t on / t t on /( t on + t off )。例如,方波的占空比就是0.5,因为它的高低电平宽度是相同的。而PWM就是 在信号周期保持不变的前提下 调节高电平(或低电平)的宽度。

我们来看看如图7.6所示动态扫描时序。

图7.6 不同的驱动占空比动态扫描时序

假设扫描每位数码管的最大时间为 t ,而实际每位数码管的显示时长 t on ,则 t on / t 就是位选通的占空比。很明显,COM 1 的占空比要大于COM 2 ,所以数字“5”比数字“2”的亮度会更大一些,因为流过前者的LED发光单元的平均电流更大。需要指出的是, PWM并不影响数码管扫描帧率 jFY61zJWDRGphZOwaT+ibJv6UkQwugGml7lvB9q62juFSxr1oXh9JDeVqosTR8Nh

点击中间区域
呼出菜单
上一章
目录
下一章
×