使用 8 位 MCU、小型 BOM 和本文提供的可下载代码来驱动多路复用 4 段 LCD 是一件简单的事情。
无需微控制器上的专用 LCD 驱动器即可直接驱动 LCD,并且需要很少的额外资源。LCD 有两种类型——静态和多路复用。本文讨论了多路复用 LCD 与 Zilog 的 Z8 Encore!® 微控制器的编程。
Z8 安可!闪存微控制器概述
Zilog 的 Z8 安可!产品基于 eZ8™ CPU,并将闪存引入 Zilog 广泛的 8 位微控制器系列。闪存在线编程能力允许更快的开发时间和现场程序更改。eZ8 内核的高性能、基于寄存器到寄存器的架构保持与 Zilog 流行的 Z8 MCU 的向后兼容性。
Z8 安可!MCU 将 20 MHz 内核与闪存、线性寄存器 SRAM 和大量片上外设组合在一起。这些外围设备造就了 Z8 Encore!MCU 适用于各种应用,包括电机控制、安全系统、家用电器、个人电子设备和传感器。
驱动液晶显示器
静态 LCD 具有用于 LCD 的每个段的单独引脚和一个公共背板引脚。照亮分段的要求是使分段偏向背板。另一个要求是 LCD 不能让直流电 (DC) 出现在段上。
为了防止段上出现直流,背板用低频方波驱动,段相对于背板进行切换。
多路 LCD 具有多个背板,并且多个段之间共享一个段引脚。为了照亮特定的段,段引脚与背板相反驱动,未使用的背板保持空闲状态。背板再次使用低频方波驱动,以防止分段上的直流偏置。
挑战
由于段的多路复用排列,对多路复用 LCD 进行编程可能是一项艰巨的任务。多路复用 LED 通常为每个 LED 数字配备一个单独的背板。然而,多路复用 LCD 将其背板布置在数字的顶部、中间和底部。这种安排会使解码过程变得非常复杂,但重要的是,即使具有专用 LCD 驱动器的微控制器仍然需要一个困难的解码过程(见图 1)。
图 1:分段排列。
下一个工程任务与照亮一段所需的电压有关。多路复用段的 ON 驱动电平降低了,因为该段大部分时间都处于空闲状态,并且只有 25% 的时间被断言。实际上,这句话意味着在较低的工作电压下,一个段可能不会发光。
更复杂的情况是,当共享段引脚由当前活动的背板断言时,段可以在其关闭状态下感知电压电位。随着更多的背板被添加到显示器,这些对比问题可能会变得更糟,因为每增加一个背板,可用的导通电压就会降低,而剩余的关断电压会增加。
图 2 显示了每个背板的对比度如何降低,因为 ON 段和 OFF 段之间的差异较小。在图 2 中,带有一个背板的静态显示器在开启电压时接收其可用 Vcc 的 100%,在关闭电压时接收 0%。在三平面示例中,V cc的一半可用于 ON 电压,OFF 段接收 V cc的四分之一。LCD 因制造商而异,但典型阈值电压为 2.3 V RMS。
图 2:驱动电平。
由于只有一半的 V cc可用于导通电压,因此很容易看出 3.3 V 微控制器如何无法直接驱动多路复用 LCD。本文的目的是展示您可以在 3 V Z8 Encore 上驱动多路复用 LCD!单片机。
硬件架构
要使用 3 V MCU 驱动多路复用 LCD,必须提高驱动电平。为了减少门数和复杂性,只对背板进行了提升。段驱动电压摆动高于和低于 Vcc 的二分之一;因此,增强的背板信号必须使用 Z8 Encore 以相同的方式执行!MCU 的端口引脚作为两个电荷泵,参考电压为 V cc的二分之一。IC1,4050缓冲器用于提供电平转换功能。
每个背板被驱动为高电平,并在其他平面被驱动时处于空闲状态。该过程被反转以去除任何直流分量,如图 3 所示。
图 3:背板波形。
通过在有源背板的相反方向上驱动段引脚来打开段,通过在有源背板的方向上驱动引脚来关闭段。在背板的空闲状态期间,任何段上的电压都低于阈值电压。结果,这些段保持不亮。
软件实施
由于 Z8 Encore 的额外速度和内存!家庭,假设开发发生在 C 编程语言中。如果软件被编写为易于移植,则用 C 编写的应用程序可以轻松移植到不同的环境。
考虑到这一点,宏用于特定于 I/O 的操作,以便在将代码移植到另一个设备时,大部分软件将保持不变。
以下代码段维护电荷泵。
/*电荷泵定义
电荷泵提升段驱动电压并在每个定时器中断时提供服务。正泵被拉低以充电并浮动到输入状态。充电时负泵悬空。电容以 1/2 VCC 为参考,电容器上的电荷似乎是 VCC +/- 参考。该宏还初始化端口的端口模式,因此它总是被刷新。
*/
#define ChargePumpsPDADDR=PxHD;
PDCTL|= B3|B4; PDOD&=~B3;
PDOD|=B4;PDADDR=PxOC;
PDCTL&=~(B3|B4); PDADDR=PxDDR;
PDCTL&=~(B3|B4)
#define FloatPumpsPDADDR=PxDDR; PDCTL|=B4|B3
以下宏管理背板驱动器。这些宏很复杂,因为每个背板只需要一个引脚,但每个背板需要两个引脚状态。
/*背板驱动器需要三种状态:ON、OFF 和 IDLE。通过将 BP1 与 BP2、BP2 与 BP3 以及 BP3 与 BP1 混合,可以在每个平面上获得所有三种状态,而无需额外的引脚。
PlaneX123
_______________
BP11101
BP20110
BP31011
`BP10010
`BP21001
`BP30100
*/
#define SetUpBackplanePDADDR=PxOC;
PDCTL&=~(B0|B5|B6);
PDADDR=PxDDR;PDCTL&=~(B0|B5|B6)
#define BP1PDOD&=~B6; PDOD|=B0|B5
#define BP2PDOD&=~B5; PDOD|=B0|B6
#define BP3PDOD&=~B0; PDOD|=B6|B5
#define NotBP1PDOD&=~(B0|B5); PDOD|=B6
#define NotBP2PDOD&=~(B0|B6); PDOD|=B5
#define NotBP3PDOD&=~(B5|B6); PDOD|=B0
最后,用于驱动段的宏。
/*下一个宏获取存储在显示缓冲区中的各个段并将它们放在端口上。它可以在没有宏的情况下完成,但这使它更通用。将有六个平面和两个缓冲区,因为有超过 8 个段*/
#define DisplaySegmentsPAOD&=~0xF8;
PAOD|=(缓冲区[平面]&0x00F8); PCOD=0;
PCOD|=((缓冲区[平面]&0x7F00)》》8)
如前所述,多路 LCD 中涉及的困难编程是一种相当不寻常的多路复用方案。前面的宏只是将先前解码的段从缓冲区放到端口上。由于解码过程如此复杂,它不在中断服务程序 (ISR) 中执行。ISR 必须尽可能短;ISR 中所需的只是设置背板和驱动段。缓冲区是一个整数数组,其中包含我们显示中使用的 12 个段。该数组中的一维是平面。此维度中有六个平面,每个背板状态一个:A、B、C、A‘、B’ 和 C‘。解码过程完成后,缓冲区必须加载跨越六个平面的 12 段数据。
解码的第一步是定义字符的显示方式。此定义适用于所有七段显示器。因此,可以重用以下代码段。
#define Dig_0Seg_a | 段_b | 段_c | 段_d | 赛段 | Seg_f
#define Dig_1Seg_b | Seg_c
#define Dig_2Seg_a | 段_b | 段_g | 赛段 | Seg_d
#define Dig_3Seg_a | 段_b | 段_g | 段_c | Seg_d
#define Dig_4Seg_f | 段_g | 段_b | Seg_c
#define Dig_5Seg_a | 段_f | 段_g | 段_c | Seg_d
#define Dig_6Seg_a | 段_f | 段_g | 段_c | 段_d | Seg_e
#define Dig_7Seg_a | Dig_1
#define Dig_8Seg_g | Dig_0
#define Dig_9Seg_a | 段_f | 段_g | 段_b | Seg_c
#define Dig_ASeg_a | 段_b | 段_c | 段_g | 赛段 | Seg_f
#define Dig_bSeg_f | 赛段 | 段_g | 段_d | Seg_c
#define Dig_CSeg_a | 段_f | 赛段 | Seg_d
#define Dig_dSeg_b | 段_c | 段_d | 赛段 | 说_g
#define Dig_ESeg_a | 段_f | 赛段 | 段_d | Seg_g
#define Dig_FSeg_a | 段_f | 赛段 | Seg_g
#define Dig_gSeg_a | 段_f | 段_g | 段_b | 段_c | Seg_d
#define Dig_hSeg_g | 段_c | 赛段 | Seg_f
#define Dig_IDig_1
#define Dig_JDig_1 | Seg_d
#define Dig_LSeg_d | 赛段 | Seg_f
#define Dig_nSeg_c | 赛段 | Seg_g
#define Dig_ODig_0
#define Dig_PSeg_g | 段_a | 段_b | 赛段 | Seg_f
#define Dig_rSeg_g | 赛段 | Seg_f
#define Dig_SSeg_g | 段_a | 段_c | 段_d | Seg_f
#define Dig_tSeg_g | 赛段 | 段_f | Seg_d
#define Dig_USeg_b | 段_c | 段_d | 赛段 | Seg_f
这些段分散在三个独立的背板上,并且必须以三个比特的三个数据包的形式排列在一个字节中。最后一位未使用。这种排列反映了显示数字的物理布局(见表 1)
表 1:段分配。
#define Seg_a1
#define Seg_g2
#define Seg_d4
#define Seg_b8
#define Seg_c16
#define Seg_dp32
#define Seg_f64
#define Seg_e128
我们的目标是将分段数据放入三个整数中——每个显示背板一个。软件必须将代表七段字符的单个字节分成三个平面的三个段。表 2 指示整数数组如何存储各个段位。
由于 LCD 的每个数字都需要三个段,因此寻址正确的段引脚需要将每个数字的数据移位三位。最后,必须寻址微控制器的正确物理引脚。以下代码段中的分配可以根据电路板布局和其他资源进行更改。
#define Seg_1AGD8//PAOD|=B3
#define Seg_1BCDP16//PAOD|=B4
#define Seg_1FE32//PAOD|=B5
#define Seg_2AGD64//PAOD|=B6
#define Seg_2BCDP128//PAOD|=B7
#define Seg_2FE256// PCOD |=B0
#define Seg_3AGD512//PCOD|=B1
#define Seg_3BCDP1024//PCOD|=B2
#define Seg_3FE2048//PCOD|=B3
#define Seg_4AGD4096//PCOD|=B4
#define Seg_4BCDP8192//PCOD|=B5
#定义 Seg_4FE16384//PCOD|=B6
以下代码段确定哪些段为特定字符打开。
for (digit=0, shift=9; digit《4; digit++,shift-=3)
{
段[0]|=(0x07 &
CharTbl[que[digit]])《
段[1]|=((0x38 & CharTbl[que[dig
它]])》》3)《
段[2]|=((0x1C0 & CharTbl[que[di
混帐]])》》6)《
}
存储正确的段以打开需要测试每个单独的位。优点是代码变得非常可移植,如下所示:
对于(平面=0;平面《3;平面++)
{
如果(段[平面]&B0)
缓冲区[平面]|=Seg_1AGD;
如果(段[平面]&B1)
缓冲区[平面]|=Seg_1BCDP;
如果(段[平面]&B2)
缓冲区[平面]|=Seg_1FE;
如果(段[平面]&B3)
缓冲区[平面]|=Seg_2AGD;
等等
}
/*我们在这里有一个赋值,而不是在上面的语句中设置单个变量,因为在收集段时会发生计时器 IRQ,这将导致显示闪烁。最后三个缓冲区只是前三个缓冲区的补充。*/
缓冲区[0]=临时缓冲区[0];
缓冲区[1]=临时缓冲区[1];
缓冲区[2]=临时缓冲区[2];
缓冲区[3]=~缓冲区[0];
缓冲区[4]=~缓冲区[1];
缓冲区[5]=~缓冲区[2];
总结
直接驱动 LCD 所需的实际代码并不是很复杂。在这个 C 示例中,解码各个分段平面所需的时间仅为 141 µs。优点是无需额外的 LCD 驱动器或使用带有专用驱动器的微控制器即可直接驱动超大显示器。唯一的缺点是电荷泵和背板驱动需要额外的引脚,但在大多数情况下,额外的引脚比专用驱动器便宜。
图 4 显示了使用 Z8 Encore 的 LCD 驱动器的示意图!单片机。
图 4:使用 Z8 Encore 的 LCD 驱动器示意图!单片机。
评论
查看更多