3.6. 字符显示原理

3.6.1. 字符与字模

驱动程序当中,字符库(也就是字模的集全)的数据采用了与一般的单色点阵LCD 的数据组成方式,即字模当中的一个位代表LCD 显示中的一个像素点,取点方式为从左到右,自上到下的顺序。对于这点,驱动中自带的ASCII 码西文字库的字模和用户可自定义的中文字库中的字模是一样的。

字模采用了以Byte 为单位的位流结构,即当一行取点不为8 的整数倍时,补齐数据至8 位,无用位填零。

下面用几个字符取字模的例子来解释一下其对应的关系。所有的字符都可以将其栅格化,化成一个点的阵列来表示,比如下图:

此主题相关图片如下61mcu102901.jpg:

上图为取字模工具中输入字符’A’后显示的栅格情况,字体选择较小,整个字用8*12 的点阵表示。其实在取这个字符的字模时,只需要取6*12 的就够了;但如前面所述的,为了补齐8 位的byte 数据,才用了8*12 的点阵规模。

至于数据位补齐的原则,与取模的方向有关,本驱动当中的字模取向为:从左到右,自上到下;是以横向为基准的,所以要在横向满足最小存储单元的位数倍数要求,才补齐字模为8*12。如果取字模的方向为:自上至下、从左到右(纵向优先),则补齐字模就会为6*16的了。

字模数据的补齐只是针对于字模将要存储在MCU 的存储空间的,实际在显示字符时仍然可以根据字符最合适的尺寸来显示,比如在本驱动当中的ASCII 码西文字库的字模就为6*10的,但占用的数据位数为8*10。

采用从左到右,自上至下的顺序取的字模数据如下所示:

/*-- 文字: A --*/
    /*-- MS Gothic9; 此字体下对应的点阵为:宽x 高=6x12 --*/
    /*-- 宽度不是8 的倍数,现调整为:宽度x 高度=8x12 --*/
    0x00,0x20,0x20,0x50,0x50,0x50,0x88,0xF8,0x88,0x88,0x00,0x00

将上面的数据配入前面的图中,其实就很简单了,图中的一行栅格点对应一个byte 的数据,左边的点对应高位,右边的点对应低位,如下图所示:

此主题相关图片如下61mcu102902.jpg:

再取一个点阵大一点的汉字字模,如下图:

此主题相关图片如下61mcu102903.jpg:

从图中,可以看出,这次取的汉字“中”字的横向点数依然不为8 的整倍,所以也是需要进行对齐调整的;取出的字模数据如下:
    /*-- 文字: 中 --*/
    /*-- 黑体15; 此字体下对应的点阵为:宽x 高=20x20 --*/
    /*-- 宽度不是8 的倍数,现调整为:宽度x 高度=24x20 --*/
    0x00,0x60,0x00,0x00,0x60,0x00,0x00,0x60,0x00,0x00,0x60,0x00,0x1F,0xFF,0xC0,0x1F,
    0xFF,0xC0,0x18,0x60,0xC0,0x18,0x60,0xC0,0x18,0x60,0xC0,0x18,0x60,0xC0,0x1F,0xFF,
    0xC0,0x1F,0xFF,0xC0,0x18,0x60,0xC0,0x00,0x60,0x00,0x00,0x60,0x00,0x00,0x60,0x00,
    0x00,0x60,0x00,0x00,0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00

每一行的点利用3 个byte 的数据表示,最后不足8 整倍数的,在后面补齐0;所以上面的“中”字的字模数据所占用的存储单元(byte)数为3*20,共和60 个byte。

我们再取一个小一点字号的“中”字字模,如下图:

此主题相关图片如下61mcu102904.jpg:

利用工具所取得的数据为:
    /*-- 文字: 中 --*/
    /*-- 黑体12; 此字体下对应的点阵为:宽x 高=16x16 --*/
    0x01,0x80,0x01,0x80,0x01,0x80,0x3F,0xFC,0x3F,0xFC,0x31,0x8C,0x31,0x8C,0x31,0x8C,
    0x3F,0xFC,0x3F,0xFC,0x31,0x8C,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x00,0x00

3.6.2. 字模与字库

字库就是字模数据的集合,比如ASCII 码西文字库就是根据ASCII 码的编码顺序将127 个ASCII 码字符的字模数据组成一个数组;当然字库与字模一样也是要有规定每个字模的尺寸大小的,同一字库当中的字模都是一样的点阵大小的,这样才能在字库当中方便的检索到所需要的字符的字模数据。

比如,在MzL02 的MCS51 版通用LCD 驱动程序当中,集成在驱动程序里面的ASCII 码西文字库统一为6*10 的点阵,而针对byte 进行对齐后,每个字模占用的点阵位数为8*10;此外,为了节省空间的占用,这里并没有把全部的127 个ASCII 码字符的字模都用上,而是把前32 个编号的字符去掉了,只取后面的。该字库定义如下:

code unsigned char Asii0610[] =
    {
    //-- MS Gothic8; 此字体下对应的点阵为:宽x 高=6x10 --
    //-- 宽度不是8 的倍数,现调整为:宽度x 高度=8x10 --
    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x40,0x40,0x40,0x40,0x40,0x00,0x60,0x00,0x00,
    0xA0,0xA0,0xA0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x28,0x28,0xFC,0x50,0xFC,0x50,0x50,0x00,0x00,
    0x20,0x70,0xA8,0xA0,0x70,0x28,0xA8,0x70,0x20,0x00,
    0x00,0xC8,0xD0,0xD0,0x20,0x58,0x58,0x98,0x00,0x00,0x00,0x20,0x50,0x20,0x60,0x98,0x90,0x68,0x00,0x00,
    0x40,0x40,0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x10,0x20,0x40,0x40,0x40,0x40,0x40,0x20,0x10,0x00,
    0x80,0x40,0x20,0x20,0x20,0x20,0x20,0x40,0x80,0x00,0x00,0x20,0xA8,0x70,0x70,0xA8,0x20,0x00,0x00,0x00,
    0x00,0x00,0x20,0x20,0x70,0x20,0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xC0,0x40,0x80,0x00,
    0x00,0x00,0x00,0x00,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xC0,0x00,0x00,
    0x10,0x10,0x20,0x20,0x40,0x40,0x80,0x80,0x00,0x00,0x00,0x60,0x90,0x90,0x90,0x90,0x90,0x60,0x00,0x00,
    0x00,0x20,0x60,0x20,0x20,0x20,0x20,0x20,0x00,0x00,0x00,0x60,0x90,0x10,0x20,0x40,0x80,0xF0,0x00,0x00,
    0x00,0x60,0x90,0x10,0x60,0x10,0x90,0x60,0x00,0x00,0x00,0x30,0x30,0x50,0x50,0x90,0xF8,0x10,0x00,0x00,
    0x00,0xF0,0x80,0xE0,0x10,0x10,0x90,0x60,0x00,0x00,0x00,0x60,0x90,0x80,0xE0,0x90,0x90,0x60,0x00,0x00,
    0x00,0xF0,0x10,0x20,0x20,0x40,0x40,0x40,0x00,0x00,0x00,0x60,0x90,0x90,0x60,0x90,0x90,0x60,0x00,0x00,
    0x00,0x60,0x90,0x90,0x70,0x10,0x90,0x60,0x00,0x00,0x00,0x00,0x60,0x00,0x00,0x00,0x00,0x60,0x00,0x00,
    0x00,0x00,0x60,0x00,0x00,0x00,0x60,0x20,0x40,0x00,0x00,0x10,0x20,0x40,0x80,0x40,0x20,0x10,0x00,0x00,
    0x00,0x00,0x00,0xF0,0x00,0xF0,0x00,0x00,0x00,0x00,0x00,0x80,0x40,0x20,0x10,0x20,0x40,0x80,0x00,0x00,
    0x00,0x60,0x90,0x10,0x20,0x20,0x00,0x20,0x20,0x00,0x00,0x70,0x88,0xB8,0xA8,0xB8,0x80,0x70,0x00,0x00,
    0x00,0x60,0x60,0x90,0x90,0xF0,0x90,0x90,0x00,0x00,0x00,0xE0,0x90,0x90,0xE0,0x90,0x90,0xE0,0x00,0x00,
    0x00,0x60,0x90,0x80,0x80,0x80,0x90,0x60,0x00,0x00,0x00,0xE0,0x90,0x90,0x90,0x90,0x90,0xE0,0x00,0x00,
    0x00,0xF0,0x80,0x80,0xE0,0x80,0x80,0xF0,0x00,0x00,0x00,0xF0,0x80,0x80,0xE0,0x80,0x80,0x80,0x00,0x00,
    0x00,0x60,0x90,0x80,0xB0,0x90,0x90,0x70,0x00,0x00,0x00,0x90,0x90,0x90,0xF0,0x90,0x90,0x90,0x00,0x00,
    0x00,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x00,0x00,0x00,0x10,0x10,0x10,0x10,0x10,0x90,0x60,0x00,0x00,
    0x00,0x90,0x90,0xA0,0xC0,0xA0,0x90,0x90,0x00,0x00,0x00,0x80,0x80,0x80,0x80,0x80,0x80,0xF0,0x00,0x00,
    0x00,0x88,0x88,0xD8,0xD8,0xA8,0xA8,0xA8,0x00,0x00,0x00,0x90,0x90,0xD0,0xD0,0xB0,0xB0,0x90,0x00,0x00,
    0x00,0x60,0x90,0x90,0x90,0x90,0x90,0x60,0x00,0x00,0x00,0xE0,0x90,0x90,0x90,0xE0,0x80,0x80,0x00,0x00,
    0x00,0x60,0x90,0x90,0x90,0xD0,0xA0,0x50,0x00,0x00,0x00,0xE0,0x90,0x90,0xE0,0x90,0x90,0x90,0x00,0x00,
    0x00,0x60,0x90,0x80,0x60,0x10,0x90,0x60,0x00,0x00,0x00,0xF0,0x40,0x40,0x40,0x40,0x40,0x40,0x00,0x00,
    0x00,0x90,0x90,0x90,0x90,0x90,0x90,0x60,0x00,0x00,0x00,0x88,0x88,0x88,0x50,0x50,0x20,0x20,0x00,0x00,
    0x00,0xA8,0xA8,0xA8,0xA8,0x50,0x50,0x50,0x00,0x00,0x00,0x90,0x90,0x60,0x60,0x60,0x90,0x90,0x00,0x00,
    0x00,0x88,0x88,0x50,0x20,0x20,0x20,0x20,0x00,0x00,0x00,0xF0,0x10,0x20,0x20,0x40,0x80,0xF0,0x00,0x00,
    0x30,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x30,0x00,0x00,0x88,0x50,0x20,0xF0,0x20,0xF0,0x20,0x00,0x00,
    0xC0,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0xC0,0x00,0x40,0xA0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xF8,0x00,0x80,0x40,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
    0x00,0x00,0x00,0xE0,0x10,0x70,0x90,0x70,0x00,0x00,0x00,0x80,0x80,0xE0,0x90,0x90,0x90,0xE0,0x00,0x00,
    0x00,0x00,0x00,0x60,0x90,0x80,0x90,0x60,0x00,0x00,0x00,0x10,0x10,0x70,0x90,0x90,0x90,0x70,0x00,0x00,
    0x00,0x00,0x00,0x60,0x90,0xF0,0x80,0x70,0x00,0x00,0x00,0x60,0x40,0xF0,0x40,0x40,0x40,0x40,0x00,0x00,
    0x00,0x00,0x00,0x50,0xA0,0xA0,0x40,0xB0,0x90,0x60,0x00,0x80,0x80,0xE0,0x90,0x90,0x90,0x90,0x00,0x00,
    0x00,0x20,0x00,0x20,0x20,0x20,0x20,0x20,0x00,0x00,0x00,0x20,0x00,0x20,0x20,0x20,0x20,0x20,0xE0,0x00,
    0x00,0x80,0x80,0x90,0xA0,0xE0,0x90,0x90,0x00,0x00,0x00,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x00,0x00,
    0x00,0x00,0x00,0xD0,0xA8,0xA8,0xA8,0xA8,0x00,0x00,0x00,0x00,0x00,0xE0,0x90,0x90,0x90,0x90,0x00,0x00,
    0x00,0x00,0x00,0x60,0x90,0x90,0x90,0x60,0x00,0x00,0x00,0x00,0x00,0xE0,0x90,0x90,0xE0,0x80,0x80,0x00,
    0x00,0x00,0x00,0x70,0x90,0x90,0x70,0x10,0x10,0x00,0x00,0x00,0x00,0xA0,0xC0,0x80,0x80,0x80,0x00,0x00,
    0x00,0x00,0x00,0x70,0x80,0x60,0x10,0xE0,0x00,0x00,0x00,0x40,0x40,0xF0,0x40,0x40,0x40,0x60,0x00,0x00,
    0x00,0x00,0x00,0x90,0x90,0x90,0x90,0x60,0x00,0x00,0x00,0x00,0x00,0x90,0x90,0x90,0x60,0x60,0x00,0x00,
    0x00,0x00,0x00,0xA8,0xA8,0xA8,0x50,0x50,0x00,0x00,0x00,0x00,0x00,0x90,0x60,0x60,0x90,0x90,0x00,0x00,
    0x00,0x00,0x00,0x90,0x90,0x50,0x20,0x20,0x40,0x00,0x00,0x00,0x00,0xF0,0x20,0x40,0x80,0xF0,0x00,0x00,
    0x30,0x20,0x20,0x20,0x40,0x20,0x20,0x20,0x30,0x00,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,
    0xC0,0x40,0x40,0x40,0x20,0x40,0x40,0x40,0xC0,0x00,0x50,0xA0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
    };

字库定义为一个unsigned char 的数组,数组的名称Asii0610 即为该字库的首地址;所以当要检索字库中的某一个字符的字模数据时,可以利用它来找到具体的地址。

如要检索字符’A’的字模数据,则该字符的字模数据首地址等于如下代码计算的结果:
    ‘A’字符的首地址= Asii0610-(10*32)+’A’*10

减去10*32 是因为该字库删减掉了前32 个字符的字模,而每个字符的字模所占用的byte 数为10 个;’A’的ASCII 码值为0x41。

驱动程序中自带的ASCII 码西文字库用户不需要改动,此外驱动程序中还为用户定义了一个汉字字库的数组,放置在文件GB_Table 当中,用户需要显示中文字符或自提取的图像字模时可以将数据放置在这处,或者另起一个字库数组。与ASCII 码西文字库一样,放置在同一个中文字库中的字模也是需要尺寸是相同的才可;

而需要索引这些字模时,用户需要知道自己在定义这个它库时每个汉字(或者图像)字模在数组中的偏移位置。

如下面的定义,即为驱动程序当中所提供的几个汉字字模:

code unsigned char GB1716[] =
    {
    /*-- 文字: 铭 --*/
    /*-- 幼圆12; 此字体下对应的点阵为:宽x 高=17x16 --*/
    /*-- 宽度不是8 的倍数,现调整为:宽度x 高度=24x16 --*/
    0x00,0x00,0x00,0x00,0x00,0x00,0x30,0x60,0x00,0x3E,0x7E,0x00,0x60,0xC6,0x00,0x61,
    0xC6,0x00,0x7E,0x66,0x00,0x18,0x3C,0x00,0x18,0x18,0x00,0x18,0x30,0x00,0xFF,0xFE,
    0x00,0x19,0xC3,0x00,0x18,0xC3,0x00,0x18,0xC3,0x00,0x1E,0xC3,0x00,0x1C,0xFF,0x00,
    /*-- 文字: 正 --*/
    /*-- 幼圆12; 此字体下对应的点阵为:宽x 高=17x16 --*/
    /*-- 宽度不是8 的倍数,现调整为:宽度x 高度=24x16 --*/
    0x00,0x00,0x00,0x00,0x00,0x00,0x3F,0xFF,0x00,0x00,0xC0,0x00,0x00,0xC0,0x00,0x00,
    0xC0,0x00,0x18,0xC0,0x00,0x18,0xC0,0x00,0x18,0xFE,0x00,0x18,0xC0,0x00,0x18,0xC0,
    0x00,0x18,0xC0,0x00,0x18,0xC0,0x00,0x18,0xC0,0x00,0x18,0xC0,0x00,0xFF,0xFF,0x00,
    /*-- 文字: 同 --*/
    /*-- 幼圆12; 此字体下对应的点阵为:宽x 高=17x16 --*/
    /*-- 宽度不是8 的倍数,现调整为:宽度x 高度=24x16 --*/
    0x00,0x00,0x00,0x00,0x00,0x00,0x3F,0xFE,0x00,0x60,0x03,0x00,0x6F,0xFB,0x00,0x60,
    0x03,0x00,0x67,0xF3,0x00,0x6C,0x1B,0x00,0x6C,0x1B,0x00,0x6C,0x1B,0x00,0x6C,0x1B,
    0x00,0x6C,0x1B,0x00,0x6F,0xFB,0x00,0x60,0x03,0x00,0x60,0x03,0x00,0x60,0x3E,0x00,
    /*-- 文字: 创 --*/
    /*-- 幼圆12; 此字体下对应的点阵为:宽x 高=17x16 --*/
    /*-- 宽度不是8 的倍数,现调整为:宽度x 高度=24x16 --*/
    0x00,0x00,0x00,0x00,0x00,0x00,0x0E,0x03,0x00,0x1B,0x1B,0x00,0x19,0x9B,0x00,0x30,
    0xDB,0x00,0xFF,0x7B,0x00,0x31,0x9B,0x00,0x31,0x9B,0x00,0x31,0x9B,0x00,0x31,0x9B,
    0x00,0x37,0x9B,0x00,0x30,0x7B,0x00,0x30,0x63,0x00,0x30,0x63,0x00,0x1F,0xDE,0x00
    };

在该字库中,每个汉字的字模数据为3*16 个byte,所以这四个汉字我们可以为它们定下一个查旬的序号就可以检索到它们的字模数据的首地址了;分别是:铭——0,正——1,同——2,创——3。

当然,这里所说的中文字库与GB 的二级汉字库之类的不是一个概念的,二级汉字库有换算的算法,可以根据汉字的GB 码值以及该字库的字符尺寸大小来检索到汉字的字模数据。这里就不多作解释。

在驱动程序当中有一个函数与定义的字库是息息相关的,就是FontSet 函数,用户如果要定义新的字库的话,就需要在该函数修改相关的代码,同时在LCD_Dis.c 当中对自定义的字库数组进行外部声明。下面来看看一些相关的定义:

在LCD_Dis.c 文件当中有如下的定义和声明:
    extern code unsigned char Asii0610[]; //6X10 的ASII 字符库
    extern code unsigned char GB1716[]; //17*16 自定义的汉字库
    unsigned char X_Witch; //字符写入时的宽度
    unsigned char Y_Witch; //字符写入时的高度
    unsigned char Font_Wrod; //字体的每个字模占用多少个存储单元数
    unsigned char *Char_TAB; //字库指针
    unsigned char BMP_Color;
    unsigned char Char_Color;

在前面的两个外部声明,就是分别在LCD_ASCII.c 和GB_Table.c 中定义好的字库;如果用户自己又额外定义了别的字库的话,同样也需要在这里加上它的外部声明。

而接下来的两个变量的定义:X_Witch 和Y_Witch,分别是存放当前设置的字符类型的宽和高的点数大小,而Font_Wrod 保存的是当前设置的字符的每个字模所占用的存储单元数量,指针Char_TAB 则保存当前设置的字库数组的首地址。

BMP_Color 和Char_Color 这两个变量分别保存当前设置的绘图前景色和字符色,其实对于黑白的单色LCD 屏也就是零和非零的区别。

下面来看看FontSet 函数中的设置:
    //========================================================================
    // 函数: void FontSet(unsigned char Font_NUM,unsigned char Color)
    // 描述: 文本字体设置
    // 参数: Font_NUM 字体选择,以驱动所带的字库为准
    // Color 文本颜色,仅作用于自带字库
    // 返回: 无
    // 版本:
    // 2006/10/15 First version
    //========================================================================
    void FontSet(unsigned char Font_NUM,unsigned char Color)
    {
    switch(Font_NUM)
    {
    case 1: Font_Wrod = 10; //ASII 字符B
    X_Witch = 6;
    Y_Witch = 10;
    Char_Color = Color;
    Char_TAB = (unsigned char *)(Asii0610 - (32*10));
    break;
    case 2: Font_Wrod = 48; //汉字A
    X_Witch = 17;
    Y_Witch = 16;
    Char_Color = Color;
    Char_TAB = (unsigned char *)GB1716;
    break;
    default: break;
    }
    }

FontSet 函数的两个参数分别是表示要选择的字符类型、设置字符色;字符类型的选择实际上就看代码当中的switch 分支怎么分配了,如上代码,设置为1 时表示选择ASCII 西文字符,为2 时则为GB_Table 中定义的自定义汉字库;当然如果用户还要另外上自定义的字库的话,可以多增加几个case 选项。

在上面的代码中的case 1 分支项里面,对选择的字库进行了参数的设置,跟前面我们分析过的ASCII 码西文字库中的一样,每个字模所占用的存储单元数量为10 个byte,所以Font_Wrod 设置为10,X_Witch 和Y_Witch 分别设置字符的实际宽度和高度,即6*10;而设置Char_TAB 值时,这里对驱动中删减掉的前32 个ASCII 字符进行了补齐,以便于在后面的字符显示程序中计算字模地址利用。

3.6.3. 用点来绘制字符

如前面所言,本版驱动程序的字符显示程序将以绘点函数为基础,简化字符显示程序的结构,使之更容易被读懂,同时也将为彩色的LCD 模块驱动相兼容打下基础。

以绘点来显示字符,实际上就是将一个字符的字模数据的每个位都进行里判断,如果查询到哪个位上的值非零则对该位所对应的点的位置进行绘点操作。可以看看以下代码:

//========================================================================
    // 函数: void PutChar(unsigned char x,unsigned char y,char a)
    // 描述: 写入一个标准字符
    // 参数: x X 轴坐标 y Y 轴坐标
    // a 要显示的字符在字库中的偏移量
    // 返回: 无
    // 备注: ASCII 字符可直接输入ASCII 码即可
    // 版本:
    // 2006/10/15 First version
    // 2007/01/11 V1.1
    //========================================================================
    void PutChar(unsigned char x,unsigned char y,char a)
    {
    unsigned char i,j; //数据暂存
    unsigned char *p_data;
    unsigned char Temp;
    unsigned char Index = 0;
    p_data = Char_TAB + a*Font_Wrod; //要写字符的首地址
    j = 0;
    while((j ++) < Y_Witch)
    {
    if(y > Dis_Y_MAX) break;
    i = 0;
    while(i < X_Witch)
    {
    if((i&0x07)==0)
    {
    Temp = *(p_data+Index);
    Index++;
    }
    if((Temp & 0x80) > 0) Write_Dot_LCD/*Writ_Dot*/(x+i,y,Char_Color);
    Temp = Temp << 1;
    if((x+i) >= Dis_X_MAX)
    {
    Index += (X_Witch-i)>>3;
    break;
    }
    i++;
    }
    y ++;
    }
    }

函数的一开始便利用前面介绍的Char_TAB(保存有当前选择的字库的首地址)、Font_Wrod(每个字符的字模数据长度)以及传递进来的参数a 计算出要显示的字符的字模数据首地址,并保存于指针当中。

随后while((j ++) < Y_Witch)的循环意思就很明了了,也就是指明了要一行一行的显示,Y_Witch 在前面已经介绍过了。在循环里面每次都会判断是否超出了Y 轴的最大值,如超出则跳出循环。

while(i < X_Witch)的小循环里则是对一行的点进行扫描,即对字模当中的一行的数据位进行扫描判断;循环里面if((i&0x07)==0)则是调整指向字模数据的指针,每个数据位数为8 位表示8 个点,也就是每8 个点的扫描后要使指针指向下一个数据,而Index 变量中保存的是针对于当前字符字模数据的偏移量。

接下来的对字模数据从高位开始进行判断,如果非零则进行绘点的操作(由此可了解到,在我们的驱动程序当中,字符的显示会与之前在该位置上的已经显示了的图形进行重叠的)。调用的绘点函数为:Write_Dot_LCD (x+i,y,Char_Color),参数x 和y 是传递进来的要显示字符的位置,即左上角的坐标值,当然y 值在每一行的扫描显示结束后会自加1,i 的变量为当前点在当前行中的列偏移。

字符的显示控制程序其实原理非常简单,无非就是将字模数据对应的位图点矩阵从左上角开始扫描,一行一行的扫描,直到结束,其间如要绘点的地方则绘制点就可以。

在字符显示程序的基础之上,又设计了一个字符串显示的子程序,很简单,代码如下:

//========================================================================
    // 函数: void PutString(unsigned char x,unsigned char y,char *p)
    // 描述: 在x、y 为起始坐标处写入一串标准字符
    // 参数: x X 轴坐标 y Y 轴坐标
    // p 要显示的字符串
    // 返回: 无
    // 备注: 仅能用于自带的ASCII 字符串显示
    // 版本:
    // 2006/10/15 First version
    //========================================================================
    void PutString(unsigned char x,unsigned char y,char *p)
    {
    while(*p!=0)
    {
    PutChar(x,y,*p);
    x += X_Witch;
    if((x + X_Witch) > Dis_X_MAX)
    {
    x = 0;
    if((Dis_Y_MAX - y) < Y_Witch) break;
    else y += Y_Witch;
    }
    p++;
    }
    }

3.6.4. Mz 的驱动中提供的字符显示

要在MzL02 的通用版驱动程序的基础上显示字符,操作非常简单,只需要在显示字符之前设置好选择的字符类型(即选择字库),然后再调用单个字符显示程序(PutChar)或者字符串显示程序(PutString)即可。

要显示驱动当中自带的ASCII 码西文字符的话,则要去了解驱动当中定义ASCII 码西文字库的类型序号(要给FontSet 函数的参数);如果显示用户自行提取的其它字符的字库,则要按上前面所介绍的规则去提取字模并将字模数据加入程序当中形成正确的字库,并作好相关的代码修改,然后调用的方法与ASCII 码西文字符的显示是差不多的。

如在MzL02 的通用版LCD 驱动程序当中就定义ASCII 码西文字符库的序号为1,而定义四个汉字“铭正同创”的自定义汉字库序号为2,显控的示意代码如下:

……
    FontSet(1,1);                     //选择ASCII 码西文字库,并设字符色为黑色
    PutChar(10,10,’A’);             //在坐标位置10,10 的地方为左上角开始显示字符’A’
    PutString(10,20,”MzDesign!”); //在坐标位置10,20 的地方为左上角开始显示字符串”MzDesign!”
    FontSet(2,1);                     //选择自定义的汉字字库, 并设字符色为黑色
    PutChar(20,30,0);                 //在坐标位置20,30 的地方为左上角开始显示字符“铭”
    PutChar(40,30,1);                 //在坐标位置40,30 的地方为左上角开始显示字符“正”
    PutChar(60,30,2);                 //在坐标位置60,30 的地方为左上角开始显示字符“同”
    PutChar(80,30,3);                 //在坐标位置80,30 的地方为左上角开始显示字符“创”
    ……

注:以上代码当中,汉字“铭正同创”的字模数据在该字库中的序号分别为0~3。如果用户需要到的话,可以自行提取要显示的其它字符的字模,并制成字库存放在MCU 当中(本驱动仅针对于字库存放在MCU 内部的存储器当中,当然如果字库存放在外存的话,也是可以在一定程度上参考的,其实也就是读取字模数据的地方作一下修改即可),然后定义好相关的变量修改相关的设置代码,就可以跟驱动当中自带的字库一样去调用显示了。具体的操作方法这里就不多介绍了,希望读者在前面的介绍的基础之上,去理解显示字符的原理,这样的话是无需教条主义式的按照一条一条一例一例的跟随做法去做;在理解的基础之上做实践操作,这才是目的所在。

【点阵液晶编程连载三/B】点阵LCD 的驱动与显控相关推荐

  1. 【点阵液晶编程连载三】点阵LCD 的驱动与显控

    3. 点阵LCD 的驱动与显控 在适当的硬件的基础介绍之后,这里将以MzDesign 所提供的针对MzL02 的通用版LCD 驱动程序为对像介绍一种LCD 驱动程序的设计思想:将以在LCD 上的绘点功 ...

  2. 【点阵液晶编程连载二】LCD 驱动的基本流程

    2. LCD 驱动的基本流程 介绍基本的流程控制方法,这里重在介绍方法,从时序的模拟或者是总线的连接,到利用LCD 的特性来做一些显示的处理,如单色液晶如何显示一个点,彩色LCD 如何显示一个点的关系 ...

  3. 【点阵液晶编程连载四】MenuGUI 菜单应用

    4. Mz_MenuGUI 菜单应用 4.1. Mz_MenuGUI 在一些带有点阵LCD 显示界面的产品当中,通常会涉及到一些菜单界面的应用,特别是一些带有设置功能的仪器仪表产品:结合自己的设计经验 ...

  4. 【点阵液晶编程连载一】写在前面

    1. 写在前面 1.1. 本书更适合什么样的LCD 模块? 在本书的开始之处,先将本书将要介绍的LCD 圈定一个小的范围,即本书所说的LCD 指的是哪类型的LCD? 在这里将主要针对单色的点阵液晶屏( ...

  5. 【点阵液晶编程连载五】液晶驱动代码的移植

    5. 移植通用版LCD 驱动程序到另一颗MCU 将通用版的LCD 驱动程序移植到另外的MCU 上并不复杂,而需要做的工作也很少,在前面介绍驱动程序代码时已经介绍过了,基本上只需要修改驱动当中与MCU ...

  6. ESP8266-Arduino编程实例-1.44寸LCD(ST7735)驱动

    1.44寸LCD(ST7735)驱动 1.LCD介绍 液晶显示器 (LCD) 是一种平板显示器或其他电子调制光学设备,它利用液晶与偏振器的光调制特性.液晶不直接发光,而是使用背光或反射器来产生彩色或单 ...

  7. zybo的linux开发教程,Zybo全栈开发入门教程——连载三:创建Linux设备驱动和应用程序...

    作者:Commanderfranz,编译: kenshin 通过前面两篇文章我们不仅创建的自定义IP模块还移植了Linux操作系统,今天这篇文章的内容是将这两部分联系起来,其实我们创建的myLed I ...

  8. 什么是点阵液晶屏和段码液晶屏

    液晶屏的叫法非常多样,主要分为点阵液晶屏和段码液晶屏,今天我们就来聊聊这两类的区别在哪. 点阵液晶屏是依照一定的标准排序起來的阵列,比较普遍的是图型点阵lcd屏模组.点阵液晶屏是由许多个显示点(等同于 ...

  9. 点阵液晶屏和段码液晶屏有何区别

    液晶屏的叫法非常多样,主要分为点阵液晶屏和段码液晶屏,今天我们就来聊聊这两类的区别在哪. ​ 点阵液晶屏是依照一定的标准排序起來的阵列,比较普遍的是图型点阵lcd屏模组.点阵液晶屏是由许多个显示点(等 ...

最新文章

  1. python之6-3嵌套函数
  2. html5的网页布局工具,HTML5网站响应式布局的主流设计方法介绍及工具推荐
  3. java.lang.NoClassDefFoundError: org/springframework/dao/support/PersistenceE解决方法
  4. SPL - 写着简单跑得又快的数据库语言
  5. 产品经理十大悲催错误
  6. SSE instruction set not enabled
  7. 设计模式---状态模式(C++实现)
  8. ORACLE的程序包1-程序包的基
  9. maven依赖和传递
  10. 关联分析中FPGrowth算法原理及实战
  11. PLC编程时三个注意事项
  12. 基于HTML5+CSS制作 H5移动端电商购物网页设计35页面(包括主页,商品详情,转账,付款,购物车等页面) 功能齐全...
  13. 图像双立方插值——C实现
  14. html多个背景音乐自动播放,多个背景音乐同时自动播放?
  15. 我的世界服务器如何修改天气,我的世界怎么切换天气 原来这么简单
  16. Centos 在 Selenium 使用中的异常:chrome not reachable
  17. 保弘实业|成功投资理财要做到那几点
  18. MaratonIME plays Cîrokime
  19. 一周信创舆情观察(1.11~1.17)
  20. 【攻防世界 level2】

热门文章

  1. Android 性能优化---(8)APP启动时间优化指南
  2. 智能音箱“好耳朵”的设计奥秘
  3. 轻松实现全国高校地理位置数据爬取(文末附源码和数据集)
  4. 我的 8 年投资心路历程
  5. 69. 二叉树的层次遍历Python实现
  6. python常见安装
  7. 担心网络崩溃并非杞人忧天
  8. Redmi K50评测:顶级2K屏加持 无愧全价位焊门员
  9. 苹果下周将推出紫色版iPhone 13 但只有高端版本
  10. 荣耀50系列将增全新配色:尽显时尚艺术张力