使用DS89C450作为静态LCD显示控制器

描述

该公司的许多微控制器集成了用于LCD显示器的控制器,这些控制器在硬件中实现。DS89C450等微控制器不提供此功能,但可以在软件中实现简单的显示控制器。本应用笔记介绍如何使用DS7C89超高速闪存微控制器驱动450段数字的静态LCD面板。

概述

液晶显示器 (LCD) 面板用于各种现代电子设备,如计算器、手持式血糖仪、加油站泵和电视机。由于LCD功耗低,在直射光下易于查看,因此在许多应用中取代了旧的LED显示器。一系列微控制器(如MAXQ2000)集成了LCD控制器,能够以高达<>/<>多路复用占空比驱动LCD面板。但在某些情况下,特定应用的理想微控制器可能未集成LCD控制器。对于这些情况,可以使用微控制器的端口引脚驱动显示器,从而在软件中实现显示控制器。

本应用笔记介绍如何利用DS7C89超高速闪存微控制器为具有450段数字的简单静态LCD面板实现显示控制器。由于不使用DS89C450特有的特性,因此本示例代码可以很容易地移植到任何兼容8051的微控制器上,只要该微控制器具有足够数量的端口引脚来驱动应用中使用的LCD面板。

本应用笔记的示例代码可供下载(ASM)。

选择液晶面板

为应用选择 LCD 面板时,请注意将 LCD 与兼容的微控制器或 LCD 显示控制器匹配。做出此决定时应考虑以下问题。

LCD的工作电压范围是多少?由于DS89C450是5V微控制器,其端口引脚工作在5V电平,因此必须选择5V LCD面板。请注意,许多集成LCD控制器的微控制器使用专用电源输入(VLCD)来设置该LCD控制器使用的电压范围。

LCD的占空比是多少?静态的LCD 面板将显示器中的每个部分连接到专用驱动线。这意味着段驱动器的数量必须等于要驱动的LCD段的数量。复 用但是,LCD 面板使用每个段驱动线 (SEG) 驱动多个 LCD 段。这些面板使用多个公共背板 (COM) 输出,并根据所使用的占空比在 SEG 和 COM 线路上的 VLCD 和 GND 之间驱动多个电平。由于DS89C450(我们的8051微控制器示例)只能将其端口引脚线驱动至5V和GND,因此我们的示例仅限于静态LCD。有关驱动多路复用LCD的更多信息,请参阅以下文档:

应用笔记 3548 “使用带有MAXQ微控制器的LCD”"

MAXQ系列用户指南:MAXQ2000补充®

操作LCD面板需要多少个段和常用驱动器?控制静态LCD面板时,要驱动的每个段都需要一条驱动线(端口引脚),外加一个用于公共(COM)背板线的附加端口引脚。

在本应用笔记中,选择了Lumex LCD-S401C52TR显示器。此 LCD 是一个 5V 静态显示面板,具有四个 7 段数字和三个报警器段(一个冒号和三个小数点)。LCD上的每个数字都由七个段组成,如图1所示,其中A、B、G、E和D段打开以显示“2”位数字。

微控制器

图1.七段式液晶显示数字。

LCD-S401C52TR显示器具有单个COM背板(连接到两个引脚)和32个显示段,每个段连接到一个段驱动引脚。在本例中,我们仅使用7段数字中的89位,这意味着DS450C21需要驱动22条SEG线(三位数字各有89段)和450条COM线,因此总共需要24个端口引脚。当不在扩展存储器总线配置下工作时,DS0C<>提供<>个推挽式端口引脚。因此,微控制器具有足够的 I/O 容量来完成此任务。(端口 <> 上提供额外的 <> 个端口引脚。但是,这些引脚是漏极开路的,需要额外的上拉电阻才能用作通用I/O)。

硬件设置

本例的硬件设置基于DS89C450评估(EV)板(Rev B),去掉了存储器接口CPLD(U5),并移除了两个外部存储器芯片(U6和U7)。此修改释放了许多额外的端口引脚供我们的应用程序使用,否则这些引脚将用于实现扩展的内存总线,特别是端口 0(所有八行)、端口 2(所有八行)、端口 3.6 和 3.7。请参阅表 1。(注意:此示例应用程序中不使用端口 0。DS89C450包括64kB的内部码空间和1kB的内部数据SRAM,对于本例来说已经绰绰有余了。

LCD-S401C52TR显示器上的段和公共线路通过使用与原型区域相邻的J89接头连接到DS450C4上的端口引脚。段线通过1kΩ电阻连接到端口引脚,而不是直接连接到端口引脚。后一步是因为DS89C450的端口引脚具有比LCD面板驱动线通常使用的更高的驱动容量(0状态为强下拉,1状态为单触发强上拉,然后为<>状态为弱上拉)。由于COM线具有更大的电容,并且需要更强的驱动器,因此它直接连接到其端口引脚。但是,此应用不建议段线直接由端口引脚驱动。在这种配置中会出现一个问题:随着越来越多的段打开,段和公共平面之间通过LCD显示器的电容耦合往往会将COM线从其预期状态拉开。(发生此问题的原因是有源段始终与公共平面的电压相反。因此,应该关闭的段将部分打开。因此,通过电阻连接端口引脚以降低其驱动强度可消除此问题。

 

DS89C450 端口引脚 J4 针座引脚 液晶屏引脚 液晶信号 笔记
P1.0 1 21 4A 通过 1kΩ
P1.1 2 20 4B 通过 1kΩ
P1.2 3 19 4C 通过 1kΩ
P1.3 4 18 4D 通过 1kΩ
P1.4 5 17 4E 通过 1kΩ
小1.5 6 22 4F 通过 1kΩ
P1.6 7 23 4G 通过 1kΩ
P1.7 8 1, 40 COM 直接连接
P2.0 22 25 3A 通过 1kΩ
P2.1 22 24 3B 通过 1kΩ
P2.2 23 15 3C 通过 1kΩ
P2.3 24 14 3D 通过 1kΩ
P2.4 25 13 3E 通过 1kΩ
P2.5 26 26 3F 通过 1kΩ
P2.6 27 27 3G 通过 1kΩ
P3.0 10 30 2A 通过 1kΩ
P3.1 11 29 2B 通过 1kΩ
P3.2 12 11 2C 通过 1kΩ
P3.3 13 10 2D 通过 1kΩ
P3.4 14 9 2E 通过 1kΩ
P3.5 15 31 2F 通过 1kΩ
P3.6 16 32 2G 通过 1kΩ

 

关于硬件设置,还有一些其他事项需要注意:

标准16.384MHz晶体(插入Y1)为DS89C450提供时钟。

运行应用程序时,DIP 开关 SW1.1 和 SW4.2 应打开;所有其他设备都应关闭。

加载应用时(使用MAXQ微控制器工具包(MTK)或其他开发工具),DIP开关SW1.1、SW1.2、SW1.3、SW4.1和SW4.2应开启;所有其他设备都应关闭。

当 LCD 显示屏运行时,端口 1 的活动也将在 LED 条形图显示器 U10 上看到。这是正常现象,并且由于LCD显示屏是缓冲的,因此不会影响应用程序。

P3.0 和 P3.1 也用于串行端口 0 的 Tx/Rx 线路。因此,当应用程序加载(使用串行端口引导加载程序)时,由于这些线路上的活动,LCD上的一个或两个段可能会闪烁。这是正常的。当应用程序运行时,应关闭DIP开关SW1.2和SW1.3以禁用串口功能。

LCD 显示屏上任何未使用的段都应显式驱动到 OFF 状态,不允许浮动。通过将一个或多个未使用的段连接到驱动到 OFF 状态(与 COM 相同的电压波形)的端口引脚,或者通过将未使用的段直接连接到 COM 来完成此任务。

驱动 LCD 段

液晶屏段的默认状态为关闭(即清除);当未施加电压时,段变为透明,并且在LCD面板中的背景中不可见。此外,当对段线(SEG)和公共背板(COM)施加相同的电压时,段保持关闭状态。仅当该段的SEG引脚与COM平面之间施加电压差时,该段才会切换到其ON(即不透明)状态。当该电压通过特定电平(称为阈值电压)时,该段变暗并最终变得完全不透明。阈值电压是LCD面板指定工作电压的百分比,因LCD而异。

压差的极性对于驱动LCD段无关紧要。例如,以 3V 阈值电压驱动 LCD 的控制器可以通过将 COM 设置为地并将 SEG n 设置为 3V 或将 COM 设置为 3V 并将 SEG n 设置为地来打开段 n。这一事实很重要,因为如果静态直流电压长时间留在LCD段上,该段可能会损坏并且无法再正确切换。为避免此问题,无论段处于ON还是OFF状态,LCD段始终由交替波形驱动,以确保每个段的总直流电压始终为零(图2)。

微控制器

图2.静态LCD段的交替驱动波形。

如图2所示,静态显示器上的COM引脚始终由VLCD(我们的设置为50V)和GND之间的5%占空比方波驱动。然后,每条线段线由两种模式之一驱动。

要关闭段,应由与用于驱动COM引脚的波形相同的波形驱动。这将确保 SEG/COM 对上的直流电压始终为零,这意味着该段将保持关闭状态。

要将段切换到ON,应由COM波形的反数驱动。这意味着该段的一半时间将由正电压驱动,另一半时间由负电压驱动。这两种状态具有相同的视觉外观,因此该段似乎一直处于打开状态。由于电压差的平均直流值为零,因此不会留下可能损坏LCD玻璃的静态直流偏置。

驱动LCD的频率(称为帧频率)因LCD面板而异。给定应用程序的正确值通常是通过对特定硬件设置的试验得出的。由于LCD段改变状态的速率受段总电容的限制,因此LCD只能在特定的帧频率范围内正常工作。通常,此范围从20Hz到200Hz。本应用笔记的示例代码以大约30Hz的频率运行LCD。对于特定显示器而言,帧速率过高或过低都会导致LCD段闪烁或视觉变暗。

驱动LCD段的示例应用的主回路如下所示。

 

 

Main:
   mov    IE, #080h          ; Disable timer 0 interrupt temporarily
   mov    R2, DigitP1        ; Grab local copies of digit variables
   mov    R3, DigitP2
   mov    R4, DigitP3 
   mov    IE, #082h          ; Re-enable timer 0 interrupt

   mov    A, R2               
   call   getDigit           ; Calculate segment pattern for ones digit
   anl    A, #01111111b      ; Ensure that COM (P1.7) is driven low
   mov    P1, A

   mov    A, R3       
   call   getDigit           ; Calculate segment pattern for tens digit
   mov    P2, A

   mov    A, R4
   call   getDigit           ; Calculate segment pattern for hundreds digit
   mov    P3, A

;;;;  Delay loop  ;;;;

   mov    R0, #0FFh
L1A:
   mov    R1, #0FFh
L1B:
   djnz   R1, L1B
   djnz   R0, L1A

;;;;;;;;;;;;;;;;;;;;;;

   mov    A, R2               
   call   getDigit           ; Calculate segment pattern for ones digit
   cpl    A                  ; Inverse of the pattern driven on the first frame half
   orl    A, #10000000b      ; Ensure that COM (P1.7) is driven high
   mov    P1, A
 

   mov    A, R3
   call   getDigit           ; Calculate segment pattern for tens digit
   cpl    A                  ; Inverse of the pattern driven on the first frame half
   mov    P2, A

   mov    A, R4
   call   getDigit           ; Calculate segment pattern for hundreds digit
   cpl    A                  ; Inverse of the pattern driven on the first frame half
   mov    P3, A

;;;;  Delay loop  ;;;;

   mov    R0, #0FFh
L2A:
   mov    R1, #0FFh
L2B:
   djnz   R1, L2B
   djnz   R0, L2A

;;;;;;;;;;;;;;;;;;;;;;

   ljmp   Main               ; Go back for another frame cycle (endless loop)

 

 

请注意,COM线(连接到P1.7)始终使用相同的波形驱动:帧的前半部分为低电平,后半部分为高电平。对于线段线,帧前半部分驱动的图案在后半部分是反转的。三个数字中的每一个都以相同的方式连接到三个端口中的每一个,因此段 A 始终连接到 Px.0,段 B 始终连接到 Px.1,依此类推。此配置允许示例代码使用 getDigit 例程计算三个 LCD 面板数字中每个数字的段模式。

 

 

;***************************************************************************
;*
;*  getDigit
;*  
;*  Returns an LCD segment pattern (in Acc) for the decimal digit (0 to 9)
;*  input (also in Acc)
;*

getDigit:
   cjne   A, #0, getDigit_not0
;             xgfedcba
   mov    A, #00111111b         ; Zero
   ret
getDigit_not0:
   cjne   A, #1, getDigit_not1
;             xgfedcba
   mov    A, #00000110b         ; One
   ret
getDigit_not1:
   cjne   A, #2, getDigit_not2
;             xgfedcba
   mov    A, #01011011b         ; Two
   ret
getDigit_not2:
   cjne   A, #3, getDigit_not3
;             xgfedcba
   mov    A, #01001111b         ; Three
   ret

getDigit_not3:
   cjne   A, #4, getDigit_not4
;             xgfedcba
   mov    A, #01100110b         ; Four
   ret
getDigit_not4:
   cjne   A, #5, getDigit_not5
;             xgfedcba
   mov    A, #01101101b         ; Five
   ret
getDigit_not5:
   cjne   A, #6, getDigit_not6
;             xgfedcba
   mov    A, #01111101b         ; Six
   ret
getDigit_not6:
   cjne   A, #7, getDigit_not7
;             xgfedcba
   mov    A, #00000111b         ; Seven
   ret
getDigit_not7:
   cjne   A, #8, getDigit_not8
;             xgfedcba
   mov    A, #01111111b         ; Eight
   ret
getDigit_not8:
   cjne   A, #9, getDigit_not9
;             xgfedcba
   mov    A, #01101111b         ; Nine
   ret
getDigit_not9:
   mov    A, #0
   ret   

 

 

运行计数器

示例代码在LCD上显示的图案是一个3位十进制计数器,上电时从000开始,递增到001、002等,直到达到999并翻转。由于程序的主循环驱动LCD段和常见模式,因此我们必须找到另一种方法来定期增加计数器值。一种解决方案是使用计时器 0 定期触发中断。

 

 

 mov    TMOD, #021h        ; Timer 1: 8-bit autoreload from TH1
                             ; Timer 0: 16-bit
   mov    TCON, #050h        ; Enable timers 0 and 1
   mov    CKMOD, #038h       ; Use system clock for all timer inputs

   mov    IE, #082h          ; Enable timer 0 interrupt

 

 

每次发生定时器中断时,寄存器存储器中的延迟计数器都会递减。当此延迟计数器达到零时,LCD 3位计数器值递增0(每个数字根据需要滚动);延迟计数器重新初始化为其最大值。由于计时器 16 的宽度为 20 位,并且示例代码将延迟计数器设置为 3,因此 <> 位计数器大约每增加一次(1/16.384兆赫) × (216) × 20 = 0.08s,或每秒约 12 次。

 

 

  org     000Bh             ; Timer 0 interrupt
   ljmp    IntTimer0


;***************************************************************************
;*
;*  IntTimer0 (INTT0)
;*  
;*  Timer interrupt service routine
;*

IntTimer0:
   push    ACC               ; Save off accumulator and R0
   push    R00

   mov     R0, Count         ; Only increment LCD digits every [CountMax]
                             ; interrupt cycles
   djnz    R0, INTT0_Done 
   
   inc     DigitP1           ; Increment ones digit on display
   mov     A, DigitP1
   cjne    A, #10, INTT0_Continue      ; Check for rollover

   mov     DigitP1, #0
   inc     DigitP2           ; Increment tens digit on display
   mov     A, DigitP2
   cjne    A, #10, INTT0_Continue      ; Check for rollover

   mov     DigitP2, #0
   inc     DigitP3           ; Increment hundreds digit on display
   mov     A, DigitP3
   cjne    A, #10, INTT0_Continue      ; Check for rollover

   mov     DigitP3, #0

INTT0_Continue:
   mov     R0, CountMax      ; Reset to starting cycle count
INTT0_Done:
   mov     Count, R0         ; Update cycle counter
   pop     R00
   pop     ACC               ; Restore accumulator and R0
   reti

 

 

结论

与微控制器上的许多专用数字外设一样,如有必要,可以在软件中实现静态或多路复用LCD显示控制器。静态显示的简单性使此实现特别简单。DS8051C89等450微控制器的标准通用I/O功能可用于驱动LCD上的SEG和COM波形。使用高性能DS89C450可确保即使在软件中实现LCD控制器后,也能为大部分应用保留足够的处理能力。

审核编辑:郭婷

打开APP阅读更多精彩内容
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉

全部0条评论

快来发表一下你的评论吧 !

×
20
完善资料,
赚取积分