系列文章目录
前言
前一段时间有小伙伴问我关于LCD的问题,看了一下LCD的原理看完头大。但是再看看MCU的手册,其实发现也没有那么难。下面就跟我一起来看看吧。一、新建工程
请参照第二章第一节新建工程
——》第二章 点亮第一个LED灯
二、LCD了解
1.LCD原理
在实际的液晶模拟驱动电压中,有几个参数非常关键:
交流电压,液晶分子是需要交流信号来驱动的,长时间的直流电压加在液晶分子两端, 会影响液晶分子的电气化学特性,引起显示模糊,寿命的减少,其破坏性为不可恢复。扫描频率,直接驱动液晶分子的交流电压的频率一般在 60~100Hz 之间,具体是依据 LCD Panel 的面积和设计而定,频率过高,会导致驱动功耗的增加,频率过低,会导致显示闪烁,同时如果扫描频率同光源的频率之间有倍数关系,
则显示也会有闪烁现象出现。
液晶分子是一种电压积分型材料,它的扭曲程度(透光性)仅仅和极板间电压的有效值有关, 和充电波形无关。电压的有效值用 COM/SEG 之间的电压差值的均方根 VRMS 表示:
LCD 类单片机内嵌的 LCD driver(液晶驱动器),正是通过系统的控制,按照用户定义的显示图案,产生点亮 LCD(Liquid Crystal Display,液晶)所需的仿真驱动波形,接到 LCD Panel(液晶显示屏)上点亮对应的像素而达到显示的效果。
占空比(Duty)
该项参数一般也称为 Duty 数或 COM 数。由于 STN/TN 的 LCD 一般是采用时分动态扫描的驱动模式,在此模式下,每个 COM 的有效选通时间与整个扫描周期的比值即占空比(Duty)是固定的,等于 1/COM 数。
偏置(Bias)
LCD 的 SEG/COM 的驱动波形为模拟信号,而各档模拟电压相对于 LCD 输出的最高电压的比例称为偏置,而一般来讲,Bias 是以最低一档与输出最高电压的比值来表示,如下图所示(1/4 Duty,1/3 Bias):
该图对应的是 1/4 duty,1/3 bias 的液晶驱动波形,COM 数为 4,每个COM 的有效选通时间与整个扫描周期的比值(Duty)=1/4,驱动波形的模拟电压共分 3 档,V3 位输出最高电压,V2、V1 为输出中间电压,并且 V1/V3=1/3,所以上述波形图对应的 Duty=1/4,Bias=1/3。
一般而言,Bias 和 Duty 之间是有一定关系的,Duty 数越多,每根 COM 对应的扫描时间变短,而要达到同样的显示亮度和显示对比度,Von 的电压就要提高,选准位和非选准位的差异需要加大,即 Bias 需要加大,Duty 和 Bias 间有一经验公式:
带 SCOM 和 SSEG 功能的 LCD
该 系 列 单 片 机 具 有 驱 动 外 部 LCD 面 板 的 能 力。LCD 驱 动 的 COM 脚 SCOM0~SCOM5 和 SEG 脚 SSEG0~SSEG19 或 SSEG0~SSEG23 与 I/O 口共用。 LCD 信号 COM 和 SEG 由应用程序实现。
LCD 操作
该系列单片机通过设置相关 I/O 引脚为 COM 引脚和 SEG 引脚,以驱动外部 LCD 面板。LCD 驱动功能是由几个 LCD 控制寄存器一起控制的,另外,这些 寄存器还可设置 LCD 的开启和关闭以及 SCOM 和 SSEG 引脚的 R-type 偏压电流,使得 LCD 驱动器 COM 和 SEG 引脚输出 VSS、(1/3)VDD、(2/3)VDD 和 VDD 的电压,从而实现 1/3 bias LCD 的显示。
SLCDC0 寄存器中的 LCDEN 位是 LCD 驱动的主控制位,它与 COMnEN 和 SEGnEN 位搭配共同选择哪些输入 / 输出引脚用于 LCD 驱动。需注意的是,输 入 / 输出端口控制寄存器不需要设置为输出以使能 LCD 驱动操作。
LCD Frames 一个完整的 LCD 波形周期包含两个 Frame, 即 Frame 0 和 Frame 1。下面将做出 详细解释:
Frame 0 :
当要输出 Frame 0 的波形,需将 SLCDC0 寄存器中的 FRAME 位设为 0。 在 Frame 0, COM 信号输出可以是 VDD, 或是 VBIAS = (1/3 )×VDD。SEG 信号输出 可以是 VSS, 或是 VBIAS = (2/3 )×VDD。
Frame 1 :
当要输出 Frame 1 的波形,需将 SLCDC0 寄存器中的 FRAME 位设为 1。 在 Frame 1, COM 信号输出可以是 VSS, 或是 VBIAS =(2/3 )×VDD。SEG 信号输出可 以是 VDD, 或是 VBIAS = (1/3 )×VDD。 COMn 的波形,由应用程序设定 SLCDC0 寄存器中的 FRAME 位控制,及相应 的 I/O 共用引脚数据位决定 COMn 引脚目前输出是 VDD, VSS 或 VBIAS。SEGm 的 波形,由应用程序设定 FRAME 位控制,及相应的 I/O 共用引脚数据位决定 SEGm 引脚目前输出是 VDD, VSS 或 VBIAS。 典型的1/3 bias LCD波形由应用程序以及LCD电压选择电路产生,波形图如下。 请注意,图中“1”代表点亮 LCD 像素。SCOM0~SCOM5 引脚的 COM 信号极 性为“0”或“1”,由相应的 I/O 共用引脚数据位产生。
2.寄存器了解
LCD 控制寄存器
LCD 驱动器 COM 和 SEG 口可以提供多种驱动电流选择以适应不同 LCD 面板 的需求。通过设置 SLCDC0 寄存器中 ISEL0 位和 ISEL1 位可以配置不同的偏压 电阻。所有 COM 和 SEG 引脚和 I/O 引脚共用,可分别通过 SLCDCn 寄存器的 相应引脚功能选择位选择 COM 和 SEG 引脚。
三、LCD显示实现
1.代码实现
以上的内容是不是让你很懵逼?看不懂没关系,跟着我的代码来一起了解吧。
我们实现的功能:点亮LCD屏从0-200滚动显示,我这里用的是TN数码显示屏。
假如我要在一号位点亮数值:1,那我们就需要选中COM1和1B、CO3和1C。在二号位点亮数值:2,那我们就需要选中COM1和2A、COM1和2B、COM3和2C、COM4和2D。
当数值需要滚动时,我们就要依次选中COM1、COM2、COM3、COM4。然后在选中的COM下,使能ABCD等。这个原理类似于点亮LDE数码管或者是矩阵式的LED灯。
man.c
#include "HT66F0185.h"
#include "LCD.h"
/*******************************************************************************
* @fn delayMs
* @brief 延时函数
* @param 延时时间 单位为ms
* @return 无
*******************************************************************************/
void delayMs(unsigned long int ms){
while(ms--)
GCC_DELAY(2000);//主频8Mhz,执行一条指令为0.5us。一条指令周期等于四条机器周期——》 1/8Mhz * 4 = 0.5us
}
/*******************************************************************************
* @fn timeBaseInit
* @brief timebase 初始化
* @param 无
* @return 无
*******************************************************************************/
void timeBaseInit(void){
_tbc=0xc4;//时基信号 tbc = fsys / 4 = 8MHz / 2 = 4MHz 溢出周期: t = 2^12 / tbc = 2.048ms
_tb0e=1;//允许时基中断
_emi=1;//打开总中断
}
/*******************************************************************************
* @fn tb0
* @brief tb0 为函数名(自己设定) 0x1c为TimeBase0中断向量 2.048ms中断一次
* @param 无
* @return 无
*******************************************************************************/
DEFINE_ISR(tb0,0x1c){
lcdScan();
}
/*******************************************************************************
* @fn main
* @brief 主函数
* @param 无
* @return 无
*******************************************************************************/
void main(){
unsigned char i;
_wdtc = 0b10101000;//关闭看门狗。直接配置看门狗寄存器,0b代表二进制。
/*关闭复用功能*/
_csel=0;//比较器共用脚PB5(C+)和PB6(C-)用作I/O
_cos=1;//设置PA3管脚为IO,而不是比较器输出
_acerl=0;//引脚(PB3、PA7、PA6、PA5、PA4、PB2、PB1、PB0)不用做A/D输入
/*LCD初始化*/
lcdInit();
/*时基初始化*/
timeBaseInit();
while(1){
setLcd(0xff);//lcd全显示
delayMs(500);//延迟500ms 为了让人眼看见变化
setLcd(0x00);//清空lcd
delayMs(500);//延迟500ms 为了让人眼看见变化
/*依次显示小数点等符号*/
for(i = 0; i < 4; i++){
dispMark(i,1);
delayMs(200);
}
/*依次消除小数点等符号*/
for(i = 0; i < 4; i++)</