点阵屏原理图(点阵式液晶屏的显示原理与驱动设计)
点阵屏原理图(点阵式液晶屏的显示原理与驱动设计)早期字库提供的字号比较少,如HZK12、HZK16、HZK24等字库本身只提供10号、12号等少数几个字号字体,提供字体也比较少,只有宋体、仿宋等几种。如果文字处理软件想要其他字号,就需要用软件的方法,插值算出来其他数据,然后送LCD显示,不可避免的字体放大后有毛刺、锯齿的问题,所以后来出现了矢量字体。所谓矢量字体,其实就是存储的128x128点阵的字体,只要字体原始数据够大,放大以后就能保证足够清晰。前辈们有办法,提出了区位码的概念。用一个16位的数,高8位代表区码,有256个区,低8位代表位码,每个区有256个位。这样256x256就可以表示65536个汉字呢,足够了。这也是我们现在用的汉字输入法的基础。无论哪种输入法,拼音也好,五笔也好,键盘输入对应汉字表示后,输入法软件会通过查询区位码,列出来该表示的所有候选字组合,用户再选择后,就从字库里面选择对应汉字的点阵数据,如果是HZK16
第一部分介绍了控制器是如何将CGRAM中的存储数据显示到LCD面板上的。下面继续,介绍下单片机或者电脑如何将一个汉字的信息发送到控制器,也就是驱动代码的编写。
这部分驱动代码是针对单片机来说的,但是即使是对于Linux操作系统来说,它的显示驱动部分,如果不考虑操作系统接口相关部分的处理,核心部分的代码跟单片机的驱动代码还是非常类似的。
LCD驱动设计,首先要解决的就是汉字的点阵化问题。因为从上一节的介绍,已经可以知道,LCD面板显示的图形或者汉字,实际上就是存储在GCRAM里面的数据,而我们的汉字,是一种图形化的文字工具,所以汉字或者图形想要在LCD面板上显示出来,就首先要点阵化,或者说数字化,如图 1所示。
图 1 点阵化的汉字
我国早期的计算机工作者们,就是这么解决汉字的问题的。最早可以追溯到DOS时代,80年代的时候就推出了汉字点阵的字库标准GB2312,例如早期的12号宋体汉字字库HZK16,现在还在广泛使用。
那么字库里面存储的是什么内容呢,实际上就是点阵化的汉字字体。还拿HZK16为例,在这个字库里面,所有汉字都标准化成了16x16点阵的汉字。如果LCD显示还是以8像素为单位的话,那么一个汉字就变成了32个字节的数据。这样的话,计算机就可以进行处理了。
汉字放在了字库里面,那么如何提取出来呢?相对于西文字符,中文字符就比较麻烦。因为拿英文来说,只有26个英文字母,存进去就可以了,然后使用ASCII码,连同各种标点符号和控制符号在内,总共才128个字节,输入一个单字节16进制数就能表示某个字符。但是汉字不行,有几千个汉字呢。
前辈们有办法,提出了区位码的概念。用一个16位的数,高8位代表区码,有256个区,低8位代表位码,每个区有256个位。这样256x256就可以表示65536个汉字呢,足够了。这也是我们现在用的汉字输入法的基础。无论哪种输入法,拼音也好,五笔也好,键盘输入对应汉字表示后,输入法软件会通过查询区位码,列出来该表示的所有候选字组合,用户再选择后,就从字库里面选择对应汉字的点阵数据,如果是HZK16字库的话,就是32个字节数据,然后数据发送到屏幕上,我们就能看到汉字了。
早期字库提供的字号比较少,如HZK12、HZK16、HZK24等字库本身只提供10号、12号等少数几个字号字体,提供字体也比较少,只有宋体、仿宋等几种。如果文字处理软件想要其他字号,就需要用软件的方法,插值算出来其他数据,然后送LCD显示,不可避免的字体放大后有毛刺、锯齿的问题,所以后来出现了矢量字体。所谓矢量字体,其实就是存储的128x128点阵的字体,只要字体原始数据够大,放大以后就能保证足够清晰。
上面说的都是PC机里面的汉字的处理,很多驱动的工作都由操作系统完成了,用户只是使用就行了。但是单片机不行,由于没有操作系统支持,所以很多处理就需要自己做。下面说说单片机如何显示汉字。
首先是汉字存储。由于大多数单片机存储比较小,所以很难存储下整个字库文件,所以在使用的汉字较少的时候,都是使用字库提取软件,如图 2,将需要的汉字从字库里提取出来,存放到ROM中去。
图 2 字库提取软件
很多LCD供货商会研发一个类似字模提取软件,可以免费使用。由于LCD面板在显示的时候,可以横向8个像素对应一个字节,也可以竖向8个像素对应一个字节,所以很多字库软件也提供了对应的选项,可以横向取模或者纵向取模。有些软件甚至还可以选择取模的顺序。比如在横向取模模式下,选择按照1、2、3、4、5。。。的顺序取模还是按照1、3、5、7.。。2、4、6、8的顺序,如图 3所示。不同的取模方式,不同的顺序,提取出来的数据肯定就不一样了。那么做驱动的时候,就要把提取时候的顺序跟在屏幕上的显示位置一一对应起来,这样才能把一个汉字在屏幕上还原出来。
图 3 取模顺序
然后是字库数据的使用,字库提取出来以后,一般是以ROM数组的方式存放在FLASH中,使用的时候根据汉字存放次序,将单个汉字的点阵数据读出来,发送到CGRAM中,供CGRAM显示。这部分功能也是LCD显示驱动主要做的工作。
图4 nokia 7110 LCD
以SED1565控制器的NOKIA7110手机黑白LCD屏为例,屏幕的分辨率为95x65,它的16x16汉字显示的驱动代码如下:
/************************************************
**函数名称:LCD_HZ()
**函数功能:显示一个汉字16*16点阵
**函数入口:x y 汉字的坐标; *s 字库入口
**函数出口:
***********************************************/
void lcd_HZ(char x char y char *s)
{
char i;
y=y*16;
for(i=0;i<16;i )
{
lcdpixel(x y i s[i]);
}
for(i=16;i<32;i )
{
lcdpixel(x 1 y i-16 s[i]);
}
}
其中x y参数,是汉字在屏幕的显示位置(注意x坐标是8个像素为单位计算的),s是存储汉字数据的数组名字,是个二位数组。很明显两个16次的for循环,是发送了32个字节的数据到CGRAM,正好是一个汉字的数据。这是一个横向取模的16x16点阵汉字的点阵数据,所以看到x、y坐标的变换情况,第一个循环发送汉字的左半边,x不变,y不停在加一;第二个循环发送汉字的右半边。所以第二次循环的时候,x坐标要加一,代表右边的8个像素,然后y从0开始数,因为发送左半边的时候,y已经到了汉字的最底下。
这样使用的时候,通过输入汉字的坐标,以及存储的汉字的次序,就可以在屏幕上打印汉字了。
lcd_HZ(0 i HZ1[i]);
其中HZ1[1]就是汉字的存储数组。
unsigned char code HZ1[][32]=
{/*-- 文字: 你 --*/
/*-- 宋体12; 此字体下对应的点阵为:宽x高=16x16 --*/
0x00 0x80 0x60 0xF8 0x07 0x40 0x20 0x18 0x0F 0x08 0xC8 0x08 0x08 0x28 0x18 0x00
0x01 0x00 0x00 0xFF 0x00 0x10 0x0C 0x03 0x40 0x80 0x7F 0x00 0x01 0x06 0x18 0x00
/*-- 文字: 好 --*/
/*-- 宋体12; 此字体下对应的点阵为:宽x高=16x16 --*/
0x10 0x10 0xF0 0x1F 0x10 0xF0 0x00 0x80 0x82 0x82 0xE2 0x92 0x8A 0x86 0x80 0x00
0x40 0x22 0x15 0x08 0x16 0x61 0x00 0x00 0x40 0x80 0x7F 0x00 0x00 0x00 0x00 0x00
这样就完成了一个汉字的显示。由于汉字是一种简单的图形,所以图形在LCD的显示方式跟汉字还是非常相似的,只要可以把点阵提取出来,就能显示。特别是对于bmp图形的显示,由于bmp图像没有压缩,本身文件内容就是每个像素点的坐标位置跟颜色信息,所以bmp图像是可以直接读取然后显示在彩色LCD屏幕上的。至于其他的图形文件由于经过了压缩,所以需要特殊处理,获取图形的点阵信息后才能显示。