资源描述
(word完整版)12864LCD液晶显示原理及使用方法
12864LCD液晶显示原理及使用方法
液晶简介
液晶是一种在一定温度范围内呈现既不同于固态液态又不同于气态的特殊物质态,它既具有各向异性的晶体所特有的双折射性又具有液体的流动性液晶显示器件(英文的简写为LCD)就是利用液晶态物质的液晶分子排列状态在电场中改变而调制外界光的被动型显示器件.
点阵式图形液晶显示屏是 LCD 的一种能够动态显示图形汉字以及各种符号信息为各种电子产品提供了友好的人机界面点阵式图形液晶显示屏的主要特点如下(这些特点也就是LCD 的特点):工作电压低、微功耗、体积小、可视面积大、无电磁辐射、数字接口、寿命长等特点.
12864LCD是一种图形点阵液晶显示器,它主要由行驱动器/列驱动器及128×64 全点阵液晶显示器组成。可完成图形显示,也可以显示8×4 个(16×16 点阵)汉字或者显示16×4个(8×16 点阵)ASCII码。分为两种,带字库的和不带字库的。不带字库的LCD需要自己提供字库字模,此时可以根据个人喜好设置各种字体显示风格,设计上较为灵活。带字库的LCD提供字库字模,但是只能显示GB2312的宋体。各有优缺点,根据不同应用场景灵活选择。其液晶模块原理图如下所示。
12864LCD点阵图形液晶模块原理框图
下面给出了其应用连接电路,分别介绍其各引脚的功能和作用。
如下表所示:12864LCD 的引脚说明
管脚号管脚名称LEVER 管脚功能描述
1GND 0 电源地
2VCC+5.0V 电源电压
3VLCD — 液晶显示器驱动电压
4RS (D/I) H/LD/I=“H”,表示DB7∽DB0 为显示数据
D/I=“L”,表示DB7∽DB0 为显示指令数据
5R/W H/L R/W=“H”,E=“H”数据被读到DB7∽DB0
R/W=“L”,E=“H→L”数据被写到IR 或DR
6EN H/L R/W=“L”,E 信号下降沿锁存DB7∽DB0
R/W=“H”,E=“H”DDRAM 数据读到DB7∽DB0
7DB0 H/L 数据线
8DB1 H/L数据线
9DB2 H/L 数据线
10DB3 H/L 数据线
11DB4 H/L数据线
12DB5 H/L数据线
13DB6 H/L数据线
14DB7 H/L数据线
15CS1 H/L H:选择芯片(右半屏)信号
16CS2 H/L H:选择芯片(左半屏)信号
17RET H/L复位信号,低电平复位
18VEE -10VLCD 驱动负电压
19LED+ — LED 背光板电源
20LED- — LED 背光板电源
12864LCD点阵图形液晶模块应用连接电路
液晶驱动设置
在理解12864LCD硬件原理和管脚功能之后,可以针对LCD进行驱动的编写,分两种情况:仿真环境下和实物开发板编程。
仿真驱动定义如下:
#define uint8 unsigned char
#define uint32 unsigned int
#define LCD_databus P0 //LCD8位数据口
sbitDI = P2^2; //DI为0写指令或读状态;1数据
sbit RW = P2^1; //RW为1写;0读
sbit EN = P2^0; //使能端
sbit CS1 = P2^4; //片选1低电平有效,控制左半屏
sbit CS2 = P2^3; //片选1低电平有效,控制右半屏
实物开发板驱动接线和定义如下
#define LCD_PORT_NUM 0 //LCD端口P0
#define DATA_PORT_NUM 1 //数据端口P1
#define CS1_PIN 23 //片选1低电平有效,控制左半屏
#define CS2_PIN 24 //片选1低电平有效,控制右半屏
#define RST_PIN 21 //复位信号低电平有效
#define RW_PIN 20 //RW为1写;0读
#define DI_PIN 19 //DI为0写指令或读状态;1数据
#define EN_PIN 22 //使能端
uchar DIN[8] = {24, 23, 20, 21, 28, 29, 19, 22};
//8位数据线的接线方式P2。24, P2.23,…P2.22对于D0,D1,…D7,低位到高位
涉及到的一些控制指令:
0x3E关显示,0x3F开显示;
总共有八页,一页占八行点阵点,页的首地址为0xB8;
行的起始地址为0xC0,有规律的改变起始行号可以实现滚屏的效果;
列的起始地址为0x40一直到0x7F共64列;
读状态指令时,数据位最高位D7为1内部忙,为0空闲;对应接线为P2。22;
通过GPIO_ReadValue获取P2端口的32位数据P2.0到P2.31,然后进行相应的与或操作进行判断。
仿真环境下的驱动程序编写:
void delay(uint8 i) //延时函数
{
while(——i);
}
void Read_busy() //读忙函数-—数据位的最高位D7为1则忙
{
P0 = 0X00;
DI = 0;
RW = 1;
EN = 1
while(P0 & 0x80)
{
;
}
EN = 0;
}
void write_LCD_command(uint8 value) //写命令函数
{
Read_busy(); //每次读写都要忙判断
DI = 0; //选择命令
RW = 0; //读操作
LCD_databus = value;
EN = 1; //EN由1—0锁存有效数据
_nop_();
_nop_();
EN = 0;
}
void write_LCD_data(uint8 value) //写数据函数
{
Read_busy();
DI = 1; //选择数据
RW = 0;
LCD_databus = value;
EN = 1; //EN由1—0锁存有效数据
_nop_();
_nop_();
EN = 0;
}
void Set_page(uint8 page) //设置显示起始页
{
page = 0xB8 | page; //页的首地址为0xB8
wite_LCD_command(page);
}
void Set_line(uint8 startline) //设置显示的起始行
{
startline = 0xC0 |startline;
write_LCD_command(startline);
}
void Set_column(uint8 column) //设置显示的列
{
column = column & 0x3F; //列的最大值为64
column = column | 0x40; //列的首地址为0x40
write_LCD_command(column);
}
void SetOnOff(uint8 onoff) //显示开关函数;0x3E是关显示,0x3F是开显示
{
onoff = 0x3E | onoff;
write_LCD_command(onoff);
}
void SelectScreen(uint8 screen) //选择屏幕
{
switch(screen)
{
case 0: CS1 = 0; CS2 = 0; break; //全屏
case 1: CS1 = 0; CS2 = 1; break; //左半屏
case 2: CS1 = 1; CS2 = 0; break; //右半屏
default: break;
}
}
void ClearScreen(uint8 screen) //清屏
{
uint8i, j;
SelectScreen(screen);
for(i=0;i<8;i++)
{
Set_page(i);
Set_column(0);
for(j=0;j〈64;j++)
{
write_LCD_data(0x00); //写入0,地址指针自动加1
}
}
}
void InitLCD() //LCD初始化
{
Read_busy();
SelectScreen(0);
SetOnOff(0); //关显示
SelectScreen(0);
SetOnOff(1); //开显示
SelectScreen(0);
ClearScreen(0);
Set_line(0);
}
连接开发板实物的底层应用程序:
voidLCD_Check_Busy(void)
{
unsignedint value = 0, rvalue = 0;
GPIO_SetDir(DATA_PORT_NUM, 0x31F80000L, 0);
GPIO_ClearValue(LCD_PORT_NUM, (1 〈< DI_PIN));
GPIO_SetValue(LCD_PORT_NUM, (1 << RW_PIN));
GPIO_SetValue(LCD_PORT_NUM, (1 << EN_PIN));
while (1)
{
value = GPIO_ReadValue(DATA_PORT_NUM);//获取值为32位P2.0到P2.31
/*数据位最高位D7为1内部忙,为0空闲;对应接线为P2.22*/
rvalue = value & 0x400000;
if (0x0 == rvalue)
{
break;
}
}
GPIO_ClearValue(LCD_PORT_NUM, (1 〈〈 EN_PIN));
GPIO_SetDir(DATA_PORT_NUM, 0x31F80000L, 1);
data_setpin(0);
}
其他的函数按照上面的进行设置,其中函数GPIO_SetValue将对应的位置1,;函数GPIO_ClearValue将对应的位置0;函数GPIO_ReadValue获取对应端口的数据,函数GPIO_SetDir设置相应端口的相应位的方向-—输入输出.
字库原理及其制作
在前面我们分析了如何点亮一个或者多个点阵,通过有意识的点亮一些点阵可以在液晶屏上看到数字、字母和汉字的显示。那么一个字母或者汉字对应着那些位置的点阵呢,是否可以通过计算得到其字模数据?
现在可以在网上下载到各种字模软件,对单个的字符取模,也可以对ASCII码、汉字库取模生成字库bin文件。在取模之前要对其进行相应的设置,以便能够正确的显示(当取模方式和液晶屏的设置不一样时会显示出乱码)。需要注意的是横纵向取模的区别,字节正序和字节倒序的差别。
下面介绍字模的数据的获取,字节正序和倒序、横纵向取模的差别.
字模是一组数字,但它的意义却与数字的意义有了根本的变化,它是用数字的各位信息来记载英文或汉字的形状,如英文的'A'在字模的记载方式如图1 所示:8×16的ASCII码点阵,左边的为横行取模,字节正序(即高位在前),右边的为纵向取模,字节倒序(即高位在下)。
图1 “A”字模图
而中文的“你"在字模中的记载却如图2 所示:下面的取模方式只介绍了横向取模、字节正序.如果要对其进行纵向取模、字节倒序,方法类似于“A”字模。
图2 “你”字模图
当通过字模软件生成字库bin文件之后如何对其进行应用?
可以通过以下方法:
1. 把字库放入SD卡中。需要带SD卡,需要使用文件系统,软硬件成本较高。
2. 把字库放入代码中一起编译,后下载到单片机中.对单片机的FLASH要求比较大,而且代码编写调式速度比较慢。
3. 购买字库IC。不够灵活。
4. 把字库放入FLASH IC 中。这种方法比较灵活,可以设置各种字体风格。
下面详细介绍将字库放入FLASH IC 中的步骤.
在写入字库到FLASH IC之前,先擦除原FLASH IC中的内容,此时可以根据字库文件大小计算所需檫除扇区大小,待擦除完毕之后,开始写入bin文件,写入时采用USB传输到FLASH IC中去。首先设置好USB相应的驱动、初始化工作,调用写数据函数。之后download程序到单片机中,待程序运行起来之后,通过USB数据线连接FLASH IC,打开HIDDriver程序,选择bin文件,设置传输速度,开始传输.
机内码、区位码
对于英文、数字等字符的显示,由于其种类较少,只需要一个字节表示即可,ASCII码的低128专供其使用,当计算机读取字符时,其存储的8为二进制大小为其ASCII码值,同时称为字符的内码,那么其字符的字模首地址在字库中存储位置为内码乘以16。首地址开始的16个字节数据为该字符的字模数据.
一个汉字由2个字节组成,那么其在计算机中是如何存在?
计算机中只能识别01二进制编码,而国家标准信息交换用汉字字符集GB 2312—80共收录了汉字、图形符号等共7445个,其中汉字6763个,按照汉字使用的频度分为两级,其中一级汉字3755个,二级汉字3008个。由于英文字符较少加上其他字符也不到128个,采用ASCII码的低128个表示足够,而ASCII码的高128个却很少用,因此可以采用两个高128ASCII码组合表示一个汉字。
汉字在计算机中是采用机内码的形式进行存储的,每一个汉字占2个字节,其中第一个字节为机内码的区码,汉字、各种图形符号机内码的区码范围是从0A1H(十六进制)开始,对应区位码中区码的第一区;而机内码的第二个字节为机内码的位码,范围也是从0A1H(十六进制)开始,对应某区中的第一个位码.就是说将汉字机内码减去0A0AH就得到该汉字的区位码。例如汉字“北”的机内码是十六进制的“B1B1",其中前两位“B1”表示机内码的区码,后两位“B1”表示机内码的位码。所以“北"的区位码为0B1B1H-0A0A0H=1111H,将区码和位码分别转换为十进制,得汉字“北”的区位码为“1717”。即“北"的点阵位于第17区的第17个字的位置,在文件HZK16中的位置为第32×[(17-1)×94+(17-1)]=48640D以后的32个字节为“北"的显示点阵。用RF—1800编程器读入二进制文件hzk16j.bin后利用其编辑功能中的缓冲区编辑查找到BE00 H(48640D是十进制,将其转变为十六进制后得BE00 H)开始的32个字节:04 80 04 80 04 88 04 98 04 A0 7C C0 04 80 04 80 04 80 04 80 04 80 04 80 1C 82 E4 82 44 7E 00 00(以上全为十六进制),将其写在16×16点阵方格纸上。
汉字、图形符号根据其位置将其分为94个“区",每个区包含94个汉字字符,每个汉字字符又称为“位".其中“区"的序号由01区至94区,“位"的序号也由01位至94位。若以横向表示“位"号,纵向表示“区” 号,则“区"和“位”构成一个二维坐标.给定一个“区”值和“位”值就可以确定一个惟一的汉字或图形符号。即4位阿拉伯数字就可以惟一地确定一个汉字或符号。如“北”字的区位码是“1717”(区位码是十进制表示,机内码是十六进制表示)。前两位是“区”号,后两位是“位"号。其中1至15区是各种图形符号、制表符和一些主要国家的语言字母,16区至87区是汉字,其中16区至55区是一级汉字,56至87区是二级汉字。
那么计算机是如何识别汉字和ASCII字符呢?当其读到的ASCII码值大于0A1H时,先暂不处理而是继续读取下一字节,如果也是大于0A1H时,则识别为汉字或者图形符号,两个合起来组成机内码。
计算机读取一个汉字的机内码时,先将其转换为区位码(第一个字节减去0B1H,得到区码;第二节字节也减去0B1H,得到位码),再根据区位码计算该汉字字模在字库中的存储首地址(计算公式为32×[(区码-1)×94+(位码-1)]).分别读取其后的32个字节数据在液晶屏相应位置点亮其点阵,从而得到我们想要的效果。
GUI图形用户界面
GUI为Graphics User Interface的缩写,即图形用户界面,已经广泛的应用于嵌入式产品中。通过窗口、图标和菜单等图形界面方便快捷的实现人机交互功能.
移植GUI到LCD12864液晶上,我们采用的是ZLG/GUI(周立功开发的)。里面提供一些基本图形操作、颜色转换、ASCII码和汉字显示、菜单和窗口操作函数等等。
ZLG/GUI可以分为三个层次,第一层为硬件驱动层,也即是底层驱动.它主要负责硬件驱动,将显示数据转换并发送给图形显示设备.第二层为基本图形层。它提供一些基本的作图功能,如画线、圆形、矩形和椭圆等.第三层为高级接口层.主要是在基本绘图之上为用户提供窗口、图标和菜单等图形接口。
移植过程中我们主要是针对底层驱动的基本函数进行修改,在驱动头文件中根据实际液晶屏的大小设置X,Y轴的大小,定义相应的操作地址(主要用于写命令和数据),设置相应操作命令字的宏定义。在驱动源文件中根据液晶屏大小修改缓冲区大小.由于前面已经介绍过LCD12864液晶基本显示原理,因此可以直接采用其中的驱动设置,完成基本的读写命令和数据的功能,然后调用GUI的上层函数实现窗口、菜单等复杂功能。
在ZLG/GUI中主要是针对横向字节正序字模的显示设置,高位在前,因此其字节设置如下uint8 const DCB_HEX_TAB[8] = {0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01};而在我们所采用的LCd12864中主要是纵向字节倒序,高位在下,因此其字节设置为uint8 const DCB_HEX_TAB[8] = {0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80};
同时应注意X轴的八位组成一个字节应改为Y轴的八位构成一个字节.
在编写画线函数时应分四种情况考虑,水平线,垂直线,X轴增长较大的斜线,Y轴增长较大的斜线。在绘画直线时应注意覆盖的问题,对于垂直线,由于我们采用的12864LCD是纵轴8位组成一个字节,而对于水平线,直接画线,这样直线上下原有的内容会被覆盖。为了避免这个问题,我们在对数据进行操作时要先读取原位置上的数据,然后对其做或运算,这样可以在不破换原数据图形的基础上绘画我们想要的直线.其他斜线的绘画也应考虑相同的问题。
由前面的介绍可知,我们定义P1口作为数据口,总共有32位,而我们只连接其中的八位进行数据的输入输出.
uchar DIN[8] = {24, 23, 20, 21, 28, 29, 19, 22};
//8位数据线的接线方式P2。24, P2.23,…P2.22对于D0,D1,…D7,低位到高位
而我们采用GPIO_ReadValue函数可以获得P1口的数据,但是为32为数据,对于我们有用的是上面定义的8位,通过移位操作(主要高地位)得到正确的原液晶显示数据.同理,写入数据到LCD的方式也是一样的,根据数据位的01状态分别设置LCD点阵的开关.
知识要点与技巧
1. 开辟缓冲区,更快的显示图形
在没有移植ZLG/GUI到12864LCD上时,都是直接在液晶屏上进行显示操作,显示出来的效果和采用GUI时一样的,但是从显示速度上来看,相差太远,直接绘画水平线,需要逐点的绘画,由于其读/写操作速度较慢会使显示速度很慢.
而在RAM中开辟一块显示缓冲区缓冲区,大小一般与实际图形显示设备的点像素对应,如128×64 点的单色图形LCD 开辟显示缓冲区大小为1024 字节(即128×64/8 一字节数据对应8 个点像素) 。在RAM 开辟显示缓冲区进行图形操作时可以获得较高的速度,待操作完毕后再将显示缓冲区的数据发送到显示设备中。
在RAM 中建立显示缓冲区画图操作先对显示缓冲区相应点的数据进行设置然后控制数据输出更新LCD显示保证LCD显示及缓冲区数据同步(注意显示缓冲区只有硬件驱动层使用)
2.注意操作符优先级
在调用ZLG/GUI进行图形绘画时,有个地方不能正确显示,通过逐步调试发现i*3+j>>3应该写成i*3+(j>〉3),因为“>〉"的优先级小于“+”,通过对其修改,可以在液晶屏上输入正确的结果。
展开阅读全文