STM32——液晶显示中英文

目录

字符编码

ASCII编码

中文编码

GB2312编码

区位码

GBK编码

Unicode字符集和编码

UTF-32

UTF-16

UTF-8

字模

字模的构成

 字模显示原理

如何制作字模

字模寻址公式

存储字模文件

各种模式的液晶显示字符实验

显示ASCII编码的字符

代码分析

ASCII字符和中文显示函数

字符编码

由于计算机只能识别0和1,文字也只能以0和1的形式在计算机里存储,所以我们需要对文字进行编码才能让计算机处理,编码的过程就是规定特定的01数字字符串来表示特定的文字,最简单的字符编码就是ASCII编码。

ASCII编码

学习C语言的时候,我们知道在程序设计中使用的ASCII编码表约定了一些控制字符、英文及数字。他们在存储器中,本质也是二进制数,只是我们约定这些二进制数可以表示某些特殊意义,如以ASCII编码解释数字“0x41”时,它表示的是英文字符“A”。ASCII编码表可以分为两部分,第一部分是控制字符或通讯专用字符,它们的数字编码从0-31,它们并没有特定的图形显示,但会根据不同的应用程序,而对文本显示有不同的影响.ASCII表的第二部分包括空格、阿拉伯数字、标点符号、大小写英文字符以及“DEL”,这部分的数字编码从32-127,除了最后一个DEL符号外都能以图形的方式显示,具体的ASCII表这里不再赘述,读者可以网上查找。

后来,计算机推广之后,还加入了各种形状和符号,一直编号到255,从128-255的字符被称为ASCII的扩展字符集,至此,基本存储单位Byte能表示的编号已经全部用完了。

中文编码

由于汉字非常多,常用字就有6000多个,如果像ASCII编码表那样只使用1个字节最多只能表示256个汉字、所以我们使用2个字节来编码。

GB2312编码

我们首先定义的就是GB2312编码,它把 ASCII码表127之后的扩展字符集直接取消掉,并规定小于127的编码按原来的ASCII标准解释字符,当2个大于127的字符联结在一起时,就表示1个汉字。
第一个字节使用(0xA1-0xFE)编码,第2个字节使用(0xA1-0xFE)编码,这样的编码组合起来可以表示了7000多个符号,其中包括汉字6763个汉字。在这些编码里,我们还把数学符号、罗马字母、日文片假名等都编进表中,就连原来在ASCII表中原有的数字、标点以及字母也重新编了2个字节长的编码,这就是平时在输入法可以切换“全角”和“半角”符号的原因,半角就是原来的1个字节的ASCII编码。

下面的表格说明GB2312兼容ASCII码的原理,说明了GB2312是如何兼容ASCII的,当我们设定系统使用GB2312标准的时候,它遇到一个字符串时,会按字节检测值得大小,若遇到连续两个字节得数值都大于127时,就把这两个连续得字节合在一起,用GB2312解码,若遇到得数值小于127,就直接用ASCII解码。

第1字节第2字节表示的字符说明
0x680x69(hi)两个字节的值都小于127(0x7F),使用ASCII解码
0xB00xA1(啊)两个字节的值都大于127(0x7F),使用GB2312解码

区位码

在GB2312编码的实际使用中,有时会用到区位码的概念,见图GB2312的部分区位码。GB2312编码对所收录字符进行了“分区”处理,共94个区,每区含有94个位,共8836个码位。而区位码实际是GB2312编码的内部形式,它规定对收录的每个字符采用两个字节表示,第一个字节为“高字节”,对应94个区;第二个字节为低字节,对应94个位。所以它的区位码范围就是:0x0101-0x9494。为兼容ASCII码,区号和位号分别加上0xA0偏移就得到GB2312编码。在区位码上加上0xA0,可求得GB2312编码的范围:0xA1A1-0XFEFE,其中汉字的编码范围是0xB0A1-0XF7FE,第一字节0xB0-0xF7(对应位号16-87),第二字节0xA1-0XFE(对应位号01-94)。

例如,“啊”字是 GB2312 编码中的第一个汉字,它位于 16 区的 01 位,所以它的区位码就是 1601 , 加上 0xA0 偏移,其 GB2312 编码为 0xB0A1 。其中区位码为 0101 的码位表示的是“空格”符。

GBK编码

据统计, GB2312 编码中表示的 6763 个汉字已经覆盖中国大陆 99.75% 的使用率,单看这个数字
已经很令人满意了,但是我们不能因为那些文字不常用就不让它进入信息时代,而且生僻字在人
名、文言文中的出现频率是非常高的。为此我们在 GB2312 标准的基础上又增加了 14240 个新汉
( 包括所有后面介绍的 Big5 中的所有汉字 ) 和符号,这个方案被称为 GBK 标准。增加这么多字
符,按照 GB2312 原来的格式来编码, 2 个字节已经没有足够的编码,我们聪明的程序员修改了
一下格式,不再要求第 2 个字节的编码值必须大于 127 ,只要第 1 个字节大于 127 就表示这是一
个汉字的开始,这样就做到了兼容 ASCII GB2312 标准。
表格 GBK 兼容 ASCII GB2312 的原理 说明了 GBK 是如何兼容 ASCII GB2312 标准的,当我 们设定系统使用 GBK 标准的时候,它按顺序遍历字符串,按字节检测字符值的大小,若遇到一
个字符的值大于 127 时,就再读取它后面的一个字符,把这两个字符值合在一起,用 GBK 解码,
解码完后,再读取第 3 个字符,重新开始以上过程,若该字符值小于 127 ,则直接用 ASCII 解码。
第1字节第2字节第3字节表示的字符说明
0x68(<7F)0xB0(>7F)0xA1(>7F)h啊第1字节小于127,使用ASCII解码,第2字节大于127直接使用GBK解码,兼容GB2312
0xB0(>7F)0xA1(>7F)0X68(<7F)啊h第1字节大于127,直接使用GBK解码,第3字节小于127直接使用ASCII解码
0XB0(>7F)0X56(<7F)0X68(<7F)痴h第1字节大于127,第2字节虽然小于127,直接使用GBK解码,第3字节小于127直接使用ASCII解码

后面还有GB18030编码,使用4字节编码,Big5繁体中文编码,由于篇幅原因,可以有兴趣的网上了解。

Unicode字符集和编码

由于各个国家或地区都根据使用自己的文字系统制定标准,同一个编码在不同的标准里表示不
一样的字符,各个标准互不兼容,而又没有一个标准能够囊括所有的字符,即无法用一个标准表
达所有字符。国际标准化组织 (ISO) 为解决这一问题,它舍弃了地区性的方案,重新给全球上所
有文化使用的字母和符号进行编号,对每个字符指定一个唯一的编号 (ASCII 中原有的字符编号
不变 ) ,这些字符的号码从 0x000000 0x10FFFF ,该编号集被称为 Universal Multiple-Octet Coded CharacterSet,简称 UCS ,也被称为 Unicode 。最新版的 Unicode 标准还包含了表情符号 ( 聊天软件 中的部分 emoji 表情 ) ,可访问 Unicode 官网了解: http://www.unicode.org
Unicode 字符集只是对字符进行编号,但具体怎么对每个字符进行编码, Unicode 并没指定,因此
也衍生出了如下几种 unicode 编码方案 (Unicode Transformation Format)。

UTF-32

对Unicode字符集编码,最自然的就是UTF-32方式。编码时,它直接对Unicode字符集里的每个字符都使用4字节来表示,转换方式很简单,直接将字符对应的编号数字转换为4字节的二进制数。如表格所示,由于UTF-32把每个字符都用4字节来存储,因此UTF-32不兼容ASCII码,也就是说ASCII编码使用的文件用UTF-32打开会乱码。
字符GBK编码Unicode编号UTF-32编码
A0x410x0000 0041 大端格式0x0000 0041
0xB0A10x0000 554A大端格式0x0000 554A

对UTF-32数据进行解码的时候,以4字节为单位进行解析即可,根据编码可直接找到Unicode字符集中对应编号的字符。

UTF-32的优点是编码简单,解码方便,读取编码的时候每次都直接读4字节,不需要加其他的判断。它的缺点是浪费存储空间,大量常用的字符的编号只需要两个字节就能表示。其次在存储的时候需要指定字节顺序,是高位字节存储在前(大端格式),还是低位字节存储在前(小端格式)。

UTF-16

针对UTF-32的缺点,人们改进了UTF-16的编码方式,如表格UTF-16编码示例,它采用2字节或4字节的变长编码方式(UTF-32为定长编码方式)。对Unicode字符编号在0-65535的统一使用2字节来表示,将每个字符的编号转换为2字节的二进制数,即从0x0000到0xFFFF.而由

Unicode 字符集在 0xD800-0xDBFF 这个区间是没有表示任何字符的,所以 UTF-16 就利用这段 空间,对 Unicode 中编号超出 0xFFFF 的字符,利用它们的编号做某种运算与该空间建立映射关 系,从而利用该空间表示 4 字节扩展,感兴趣的读者可查阅相关资料了解具体的映射过程。

 

字符GB18030编码Unicode编号UTF-16编码
A0x410X0000 0041        大端格式0x0041
0xB0A10x0000 554A大端格式0x554A
𧗌0x9735 F8320x0002 75CC大端格式0xD85D DDCC
UTF-16 解码时,按两个字节去读取,如果这两个字节不在 0xD800 0xDFFF 范围内,那就是
双字节编码的字符,以双字节进行解析,找到对应编号的字符。如果这两个字节在 0xD800
0xDFFF 之间,那它就是四字节编码的字符,以四字节进行解析,找到对应编号的字符。
UTF-16 编码的优点是相对 UTF-32 节约了存储空间,缺点是仍不兼容 ASCII 码,仍有大小端格
式问题。

UTF-8

UTF-8 也是一种变长的编码方式,它的编码有 1 2 3 4 字节长度的方式,每个 Unicode 字符根
据自己的编号范围去进行对应的编码,见表格 UTF-8 编码原理 _x 的位置用于填充 Unicode 编号 
它的编码符合以下规律:
对于 UTF-8 单字节的编码,该字节的第 1 位设为 0( 从左边数起第 1 位,即最高位 ) ,剩余
的位用来写入字符的 Unicode 编号。即对于 Unicode 编号从 0x0000 0000 - 0x0000 007F 的字
符, UTF-8 编码只需要 1 个字节,因为这个范围 Unicode 编号的字符与 ASCII 码完全相同,
所以 UTF-8 兼容了 ASCII 码表。
对于 UTF-8 使用 N 个字节的编码 (N>1) ,第一个字节的前 N 位设为 1 ,第 N+1 位设为 0
后面字节的前两位都设为 10 ,这 N 个字节的其余空位填充该字符的 Unicode 编号,高位用
0 补足。
Unicode(16进制)UTF-8(2进制)
编号范围第1字节第2字节第3字节第4字节第5字节
00000000-0000007F0xxxxxxx
00000080-000007FF110xxxxx10xxxxxx
00000800-0000FFFF1110xxxx10xxxxxx10xxxxxx
00010000-0010FFFF11110xxx10xxxxxx10xxxxxx10xxxxxx
...111110xx10xxxxxx10xxxxxx10xxxxxx10xxxxxx
注:实际上 utf-8 编码长度最大为四个字节,所以最多只能表示 Unicode 编码值的二进制数为 21
位的 Unicode 字符。但是已经能表示所有的 Unicode 字符,因为 Unicode 的最大码位 0x10FFFF 也 只有 21 位。
UTF-8 解码的时候以字节为单位去看,如果第一个字节的 bit 位以 0 开头,那就是 ASCII 字符,以
单字节进行解析。如果第一个字节的数据位以“ 110 ”开头,就按双字节进行解析, 3 4 字节的
解析方法类似。

字模

如果有字符编码、计算机还不知道如何表达该字符,因为字符实际上是一个个独特的图形,计算机必须把字符编码转化成对应的字符图形人类才能正常识别,因此我们要给计算机提供字符的图形数据,这些数据就是字模,多个字模数据组成的文件就是字库。

字模的构成

已知字模是图形数据,而图形在计算机中是由一个个像素点组成的,所以字模实质是一个个像素
点数据。为方便处理,我们把字模定义成方块形的像素点阵,且每个像素点只有 0 1 这两种状
( 可以理解为单色图像数据 ) 。见图 字模 ,这是两个宽、高为 16x16 的像素点阵组成的两个汉字
图形,其中的黑色像素点即为文字的笔迹。计算机要表示这样的图形,只需使用 16x16 个二进制
数据位,每个数据位记录一个像素点的状态,把黑色像素点以“
1 ”表示,无色像素点以“0”表 示即可。这样的一个汉字图形,使用 16x16/8=32 个字节来就可以记录下来。

 字模显示原理

如果使用 LCD 的画点函数,按位来扫描这些字模数据,把为 1 的位以黑色来显示 ( 也可以使用其
它颜色 ) ,为 0 的数据位以白色来显示,即可把整个点阵还原出来,显示在液晶屏上。

如何制作字模

以上只是某几个字符的字模,为方便使用,我们需要制作所有常用字符的字模,如程序只需要英
文显示,那就需要制作包含 ASCII 码表 ASCII 码中的字符和数字 中所有字符的字模,如程序只需
要使用一些常用汉字,我们可以选择制作 GB2312 编码里所有字符的字模,而且希望字模数据与
字符编码有固定的映射关系,以便在程序中使用字符编码作为索引,查找字模。在网上搜索可找
到一些制作字模的软件工具,可满足这些需求。在我们提供的《液晶显示中英文》的工程目录下
提供了一个取模软件“ PCtoLCD ”,这里以它为例讲解如何制作字模,其它字模软件也是类似的。
  1. 配置字模格式
  2. 生成GB2312字模

字模寻址公式

使用字模软件制作的字模数据一般会按照编码格式排列。如我们利用以上软件生成的字模文件
GB2312_H2424.FON 》中的数据,是根据 GB2312 的区位码表的顺序存储的,它存储了区位码
0101-9494 的字符,每个字模的大小为 16x16/8=32 字节。其中第一个字符“空格”的区位码为
0101 ,它是首个字符,所以文件的前 32 字节存储的是它的字模数据;同理, 32-64 字节存储的则
0102 字符“、”的字模数据。所以我们可以导出任意字符的寻址公式
Addr = (((Code H -0xA0-1)*94) +(Code L -0xA0-1))*16*16/8
其中 Code H Code L 分别是 GB2312 编码的第一字节和第二字节; 94 是指一个区中有 94 个位 ( 即 94 个字符 ) 。公式的实质是根据字符的 GB2312 编码,求出区位码,然后区位码乘以每个字符占 据的字节数,求出地址偏移。

存储字模文件

上面生成的《 GB2312_H1616.FON 》文件的大小为 256KB ,比很多 STM32 芯片内部的所有 FLASH
空间都大,如果我们还是在程序中直接以 C 语言数组的方式存储字模数据, STM32 芯片的程序空
间会非常紧张,一般的做法是把字模数据存储到外部存储器,如 SD 卡或 SPI-FLASH 芯片,当需
要显示某个字符时,控制器根据字符的编码算好字模的存储地址,再从存储器中读取,而 FLASH
芯片在生产前就固化好字模内容,然后直接把 FLASH 芯片贴到电路板上,作为整个系统的一部

各种模式的液晶显示字符实验

显示ASCII编码的字符

编程要点

(1)获取字模数据

(2)根据字模格式,编写液晶显示函数

(3)编写测试程序,控制液晶

代码分析

ASCII字模数据

要显示的字符首先要有字库数据,在工程中fonts,c文件我们定义了一系列大小为24x32、16x24、16x16的ASCII码表的字模数据:如下

/*
*常用ASCII表,偏移量32,大小为8(宽度)*16(高度)
*/
const uint8_t ASCII8x16_Table[] = {       //@consolas字体,阴码点阵格式,逐行顺向取摸
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x18,0x18,0x18,0x18,0x18,0x18,0x08,0x00,0x08,0x18,0x00,0x00,0x00,
0x00,0x00,0x00,0x34,0x24,0x24,0x24,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x16,0x24,0x7f,0x24,0x24,0x24,0x7e,0x24,0x24,0x00,0x00,0x00,
0x00,0x00,0x00,0x08,0x3e,0x68,0x48,0x68,0x1c,0x16,0x12,0x12,0x7c,0x10,0x10,0x00,
0x00,0x00,0x00,0x61,0xd2,0x96,0x74,0x08,0x10,0x16,0x29,0x49,0xc6,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x3c,0x64,0x64,0x38,0x72,0x4a,0xce,0x46,0x7f,0x00,0x00,0x00,
0x00,0x00,0x00,0x18,0x18,0x18,0x18,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x04,0x08,0x18,0x10,0x30,0x30,0x30,0x30,0x10,0x10,0x18,0x0c,0x04,
0x00,0x00,0x00,0x20,0x10,0x08,0x08,0x0c,0x04,0x04,0x04,0x0c,0x08,0x18,0x10,0x20,
0x00,0x00,0x00,0x08,0x0a,0x34,0x1c,0x6a,0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x18,0x18,0x18,0x7f,0x18,0x18,0x18,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x18,0x18,0x08,0x30,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x3c,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x18,0x18,0x00,0x00,0x00,
0x00,0x00,0x00,0x02,0x06,0x04,0x0c,0x08,0x08,0x10,0x10,0x20,0x20,0x40,0x00,0x00,
0x00,0x00,0x00,0x00,0x3c,0x66,0x42,0x47,0x5b,0x73,0x42,0x66,0x3c,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x18,0x78,0x48,0x08,0x08,0x08,0x08,0x08,0x7e,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x3c,0x46,0x06,0x06,0x04,0x08,0x10,0x20,0x7e,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x7c,0x06,0x06,0x04,0x3c,0x02,0x02,0x06,0x7c,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x0c,0x1c,0x14,0x24,0x64,0x44,0xff,0x04,0x04,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x7e,0x60,0x60,0x60,0x7e,0x02,0x02,0x06,0x7c,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x1e,0x30,0x60,0x48,0x76,0x42,0x42,0x62,0x3c,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x7e,0x02,0x06,0x04,0x0c,0x08,0x18,0x10,0x30,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x3c,0x62,0x42,0x36,0x1c,0x66,0x42,0x42,0x3c,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x3c,0x66,0x42,0x42,0x66,0x1a,0x02,0x04,0x78,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x18,0x18,0x00,0x00,0x00,0x18,0x18,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x18,0x18,0x00,0x00,0x00,0x18,0x18,0x08,0x30,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x04,0x18,0x30,0x60,0x10,0x0c,0x06,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x7e,0x00,0x7e,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x30,0x18,0x04,0x06,0x0c,0x10,0x20,0x00,0x00,0x00,
0x00,0x00,0x00,0x30,0x1c,0x06,0x06,0x06,0x18,0x10,0x00,0x10,0x10,0x00,0x00,0x00,
0x00,0x00,0x00,0x1c,0x22,0x41,0x41,0xdd,0xb5,0xa5,0xa5,0xaf,0x94,0xc0,0x40,0x3c,
0x00,0x00,0x00,0x00,0x18,0x1c,0x34,0x24,0x26,0x62,0x7e,0x43,0xc1,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x7c,0x46,0x42,0x46,0x7c,0x42,0x42,0x42,0x7c,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x1e,0x20,0x40,0x40,0x40,0x40,0x40,0x60,0x3e,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x7c,0x46,0x42,0x43,0x43,0x43,0x42,0x46,0x78,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x7e,0x60,0x60,0x60,0x7e,0x60,0x60,0x60,0x7e,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x7e,0x60,0x60,0x60,0x7e,0x60,0x60,0x60,0x60,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x1e,0x60,0x40,0x40,0xce,0x42,0x42,0x62,0x3e,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x42,0x42,0x42,0x42,0x7e,0x42,0x42,0x42,0x42,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x7e,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x7e,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x7c,0x04,0x04,0x04,0x04,0x04,0x04,0x44,0x78,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x42,0x44,0x48,0x50,0x70,0x58,0x4c,0x44,0x42,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x3e,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x62,0x66,0x67,0x5f,0x5b,0x5b,0xc1,0xc1,0xc1,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x62,0x62,0x72,0x52,0x5a,0x4a,0x4e,0x46,0x46,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x3c,0x62,0x43,0xc3,0xc3,0xc3,0x43,0x62,0x3c,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x7c,0x46,0x42,0x42,0x46,0x78,0x40,0x40,0x40,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x3c,0x62,0x43,0xc3,0xc3,0xc3,0x43,0x62,0x3c,0x18,0x0f,0x00,
0x00,0x00,0x00,0x00,0x7c,0x66,0x62,0x66,0x7c,0x6c,0x64,0x66,0x62,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x3e,0x60,0x40,0x60,0x1c,0x06,0x02,0x02,0x7c,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x7f,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x42,0x42,0x42,0x42,0x42,0x42,0x42,0x62,0x3c,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0xc1,0x43,0x42,0x62,0x26,0x24,0x34,0x1c,0x18,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0xc1,0xc1,0x41,0x49,0x5b,0x5b,0x76,0x66,0x66,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x43,0x66,0x34,0x18,0x18,0x1c,0x24,0x66,0xc3,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0xc1,0x42,0x66,0x34,0x1c,0x18,0x18,0x18,0x18,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x7e,0x02,0x04,0x0c,0x18,0x10,0x20,0x60,0x7e,0x00,0x00,0x00,
0x00,0x00,0x00,0x1c,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x1c,
0x00,0x00,0x00,0x40,0x20,0x20,0x10,0x10,0x08,0x08,0x0c,0x04,0x06,0x02,0x00,0x00,
0x00,0x00,0x00,0x3c,0x0c,0x0c,0x0c,0x0c,0x0c,0x0c,0x0c,0x0c,0x0c,0x0c,0x0c,0x3c,
0x00,0x00,0x00,0x00,0x18,0x1c,0x24,0x62,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,
0x00,0x00,0x00,0x20,0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x3c,0x06,0x02,0x3e,0x42,0x46,0x7a,0x00,0x00,0x00,
0x00,0x00,0x00,0x40,0x40,0x40,0x5c,0x62,0x42,0x42,0x42,0x42,0x7c,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x1e,0x20,0x60,0x40,0x60,0x20,0x3e,0x00,0x00,0x00,
0x00,0x00,0x00,0x02,0x02,0x02,0x3e,0x62,0x42,0x42,0x42,0x66,0x3a,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x3c,0x62,0x42,0x7e,0x40,0x60,0x3e,0x00,0x00,0x00,
0x00,0x00,0x00,0x0f,0x18,0x10,0x10,0x7e,0x10,0x10,0x10,0x10,0x10,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x3f,0x66,0x42,0x66,0x58,0x40,0x3e,0x43,0x42,0x3c,
0x00,0x00,0x00,0x40,0x40,0x40,0x5c,0x62,0x42,0x42,0x42,0x42,0x42,0x00,0x00,0x00,
0x00,0x00,0x00,0x18,0x18,0x00,0x78,0x08,0x08,0x08,0x08,0x08,0x7e,0x00,0x00,0x00,
0x00,0x00,0x00,0x04,0x0c,0x00,0x7c,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x0c,0x78,
0x00,0x00,0x00,0x60,0x60,0x60,0x62,0x6c,0x78,0x70,0x68,0x64,0x62,0x00,0x00,0x00,
0x00,0x00,0x00,0x78,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x7e,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x76,0x4b,0x4b,0x4b,0x4b,0x4b,0x4b,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x5c,0x62,0x42,0x42,0x42,0x42,0x42,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x3c,0x62,0x42,0x43,0x42,0x62,0x3c,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x5c,0x62,0x42,0x42,0x42,0x42,0x7c,0x40,0x40,0x40,
0x00,0x00,0x00,0x00,0x00,0x00,0x3e,0x62,0x42,0x42,0x42,0x66,0x3a,0x02,0x02,0x02,
0x00,0x00,0x00,0x00,0x00,0x00,0x6e,0x72,0x63,0x60,0x60,0x60,0x60,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x3e,0x20,0x20,0x3c,0x06,0x02,0x7c,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x10,0x10,0xfe,0x10,0x10,0x10,0x10,0x10,0x1e,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x42,0x42,0x42,0x42,0x42,0x66,0x3a,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x43,0x42,0x66,0x24,0x34,0x18,0x18,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0xc1,0xc1,0x5b,0x5a,0x5e,0x66,0x66,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x62,0x26,0x1c,0x18,0x1c,0x26,0x62,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x43,0x42,0x66,0x24,0x34,0x1c,0x18,0x18,0x30,0xe0,
0x00,0x00,0x00,0x00,0x00,0x00,0x7e,0x06,0x0c,0x18,0x10,0x20,0x7e,0x00,0x00,0x00,
0x00,0x00,0x00,0x0e,0x18,0x10,0x10,0x10,0x30,0x70,0x10,0x10,0x10,0x10,0x18,0x0e,
0x00,0x00,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,
0x00,0x00,0x00,0x30,0x18,0x08,0x08,0x08,0x0c,0x0e,0x08,0x08,0x08,0x08,0x18,0x30,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x71,0x4b,0x06,0x00,0x00,0x00,0x00,0x00,
};  

管理英文字模的结构体

为了方便使用各种不同的字体,工程中定义了一个sFONT的结构体类型,并利用它定义了存储不同字体信息的结构体变量。

typedef struct _tFont
{
	const uint8_t *table;
	uint16_t Width;
	uint16_t Height;

}sFONT;

sFONT ASCII_8x16 = {
											ASCII8x16_Table,
											8,
											16,
										};

sFONT ASCII_16x16 = {
											ASCII16x24_Table,
											16,
											24,
										};

sFONT ASCII_24x32 = {
											ASCII24x32_Table,
											24,
											32,
					};
这个结构体类型定义了三个变量,第一个是指向字模数据的指针,即前面提到的 C 语言数
组,每二、三个变量存储了该字模单个字符的像素宽度和高度。利用这个类型定义了 Font8x16
Font16x24 之类的变量,方便显示时寻址。

ASCII字符和中文显示函数

/**************************以下是ASCII英文字符显示相关的函数**********************************/
/*
*@brief 显示字符
*@param usX:在特定扫描方向字符显示的X起始位置
				usY:在特定扫描方向字符显示的Y起始位置
				Chara:要显示的字符数据
*@revtal:None			
*/
void ILI9341_LCD_DisChar_EN(uint16_t usX,uint16_t usY,const char Chara)
{
	uint8_t byteCount,bitCount,fontLength;
	uint16_t usRelativePosition;
	uint8_t *Pfont;
	
	/*对ASCII表的偏移(注意:字模表不包含ASCII表的前32个非图形符号)*/
	usRelativePosition	=	Chara - ' ';
	
	/*一个字符的字模数据所占的字节数*/
	fontLength	=	((*LCD_Currentfonts).Width*(*LCD_Currentfonts).Height)/8;
	
	/*字模的首地址,ASCII表偏移乘以每个字模的字节数,求出字模的偏移位置*/
	Pfont	=	(uint8_t *)&LCD_Currentfonts->table[usRelativePosition*fontLength];
	
	/*设置显示窗口*/
	ILI9341_Open_Window(usX,usY,LCD_Currentfonts->Width,LCD_Currentfonts->Height);
	
	/*按字节读取字模数据显示*/
	ILI9341_Write_Cmd(CMD_SetPixel);
	/*由于前面设置了显示窗口,显示数据会自动换行*/
	for(byteCount=0;byteCount<fontLength;byteCount++)
	{	/*一位一位处理要显示的颜色*/
		for(bitCount=0;bitCount<8;bitCount++)
		{
			if((*Pfont)&(0x80>>bitCount))
			{
					ILI9341_Write_Data(CurrentTextColor);
			}
			else
			{
					ILI9341_Write_Data(CurrentBackColor);
			}
		}
		Pfont++;
	}
}

/*
*@brief  显示一串英文字符串
*@param  usX:要显示的英文字符串的起始X位置
				 usY:要显示的英文字符串的起始Y位置
				 Str:要显示的英文字符串
*@retval:None
*/
void ILI9341_LCD_DisStr_EN(uint16_t usX,uint16_t usY, char *Str)
{
	/*先要根据字符串的字符找到对应的字模数据*/
	while(*Str != '\0')
	{
		if((usX + LCD_Currentfonts->Width)>LCD_X_LENGTH)
		{
			usX	=	ILI9341_DispWindow_X_Star;
			usY	+=	LCD_Currentfonts->Height ;
		}
		if((usY + LCD_Currentfonts->Height)>LCD_Y_LENGTH)
		{
			usX	=	ILI9341_DispWindow_X_Star;
			usY	=	ILI9341_DispWindow_Y_Star;
		
		}
		ILI9341_LCD_DisChar_EN(usX,usY,*Str);
		
		Str++;
		
		usX	+= LCD_Currentfonts->Width;
	}
}

/*
*@brief 在显示屏上显示英文字符(沿着Y轴方向,前面默认是沿着X轴方向)
*@param	usX:在特定的扫描方向上要显示英文字符串的X位置
			  usY:在特定的扫描方向下要显示英文字符串的Y位置
				
*@retval:None				
*/		
void ILI9341_LCD_DisStr_EN_Ydir(uint16_t usX,uint16_t usY,char *Str)
{
	while(*Str	!= '\0')
	{
		if((usY	+ LCD_Currentfonts->Height)>LCD_Y_LENGTH)
		{
			usX	+= LCD_Currentfonts->Width;
			usY	=	ILI9341_DispWindow_Y_Star;
			
		}
		if((usX	+ LCD_Currentfonts->Width)>LCD_X_LENGTH)
		{
			usX	=	ILI9341_DispWindow_X_Star;
			usY	=	ILI9341_DispWindow_Y_Star;
		}
		
		ILI9341_LCD_DisChar_EN(usX,usY,*Str);
		Str++;
		
		usY	+= LCD_Currentfonts->Height;
	
	}
}	
/*
*@brief 在ILI9341显示器上显示英文字符串
*@param line:在特定扫描方向上英文字符串的起始Y坐标
*@note:本参数可以使用宏定义LINE(0)、LINE(1)等指定方式的文字坐标
				其中宏LINE会根据选择的当前字体来计算Y坐标值
				Str:要显示的英文字符串的首地址
*@retval:None
*/	
void ILI9341_LCD_DisStrLine_EN(uint16_t line,char *Str)
{
	uint16_t usX	=	0;
	
	while(*Str	!= '\0')
	{
		if((usX	+ LCD_Currentfonts->Width)>LCD_X_LENGTH)
		{
			usX	=	ILI9341_DispWindow_X_Star;
			line	+= LCD_Currentfonts->Height;
		}
		if((line	+ LCD_Currentfonts->Height)>LCD_Y_LENGTH)
		{
			usX	=	ILI9341_DispWindow_X_Star;
			line	=	ILI9341_DispWindow_Y_Star;
		}
		ILI9341_LCD_DisChar_EN(usX,line,*Str);
		Str++;
		
		usX	+= LCD_Currentfonts->Width;
		
	}

}

/*
*@brief 设置当前要显示的字体大小
*@param	fonts:指定要选择的字体
*@note:参数可以为以下选择之一:
*@arg:ASCII_8x16
*@arg:ASCII_8x16
*@arg:ASCII_8x16
*@retval:None
*/
void LCD_SetFont(sFONT *fonts)
{
	LCD_Currentfonts	=	fonts;
}

/*
*brief	读取当前字体的类型
*param	None
*retval:返回当前字体的类型
*/
sFONT *LCD_GetFont(void)
{
	return LCD_Currentfonts;

}


/**************************以下是有关GB2312中文字符显示相关的函数********************************************/

/*
*@brief	显示GB2312中文字符
*@param	usX:在当前扫描方式下的要显示的中文字符的X起始位置
				usY:在当前扫描方式下的要显示的中文字符的Y起始位置
*@retval:None			
*/
void ILI9341_LCD_DisChar_CH ( uint16_t usX, uint16_t usY, uint16_t usChar )
{
	uint8_t rowCount, bitCount;
	uint8_t ucBuffer [ CH_WIDTH*CH_HEIGHT/8 ];	
  uint16_t usTemp; 	

	//设置显示窗口
	ILI9341_Open_Window ( usX, usY, CH_WIDTH, CH_HEIGHT );
	
	ILI9341_Write_Cmd ( CMD_SetPixel );
	
	//取字模数据  
  GetGBKCode ( ucBuffer, usChar );	
	
	for ( rowCount = 0; rowCount < CH_HEIGHT; rowCount++ )
	{
    /* 取出两个字节的数据,在lcd上即是一个汉字的一行 */
		usTemp = ucBuffer [ rowCount * 2 ];
		usTemp = ( usTemp << 8 );
		usTemp |= ucBuffer [ rowCount * 2 + 1 ];
		
		for ( bitCount = 0; bitCount < CH_WIDTH; bitCount ++ )
		{			
			if ( usTemp & ( 0x8000 >> bitCount ) )  //高位在前 
			  ILI9341_Write_Data ( CurrentTextColor );				
			else
				ILI9341_Write_Data ( CurrentBackColor );			
		}		
	}
	
}
/*
*@brief 在ILI9341显示器上显示中文字符串
*@param usX:在当前扫描方式下的显示中文字符串的X起始位置
			  usY:在当前扫描方式下的显示中文字符串的Y起始位置
*@retval:None			
*/
void ILI9341_LCD_DisStr_CH(uint16_t usX,uint16_t usY,char *uStr)
{
	uint16_t usCh;
	while(*uStr!='\0')
	{
		if((usX + CH_WIDTH)>LCD_X_LENGTH)
		{
			usX	=	ILI9341_DispWindow_X_Star;
			usY	+= CH_HEIGHT;
		}
		if((usY + CH_HEIGHT)>LCD_Y_LENGTH)
		{
			usX	=	ILI9341_DispWindow_X_Star;
			usY	=	ILI9341_DispWindow_Y_Star;
		}
		usCh	=	*(uint16_t *)uStr;
		usCh	=	(usCh<<8) + (usCh>>8);
		
		ILI9341_LCD_DisChar_CH(usX,usY,usCh);
		uStr+=2;
		
		usX	+= CH_WIDTH;
	
	}

}

/**
 * @brief  在 ILI9341 显示器上显示中英文字符串
 * @param  usX :在特定扫描方向下字符的起始X坐标
 * @param  usY :在特定扫描方向下字符的起始Y坐标
 * @param  pStr :要显示的字符串的首地址
 * @note 可使用LCD_SetBackColor、LCD_SetTextColor、LCD_SetColors函数设置颜色
 * @retval 无
 */
void ILI9341_DispString_EN_CH ( 	uint16_t usX , uint16_t usY, char * pStr )
{
	uint16_t usCh;
	
	while( * pStr != '\0' )
	{
		if ( * pStr < 127 )	           	//英文字符
		{
			if ( ( usX - ILI9341_DispWindow_X_Star + LCD_Currentfonts->Width ) > LCD_X_LENGTH )
			{
				usX = ILI9341_DispWindow_X_Star;
				usY += LCD_Currentfonts->Height;
			}
			
			if ( ( usY - ILI9341_DispWindow_Y_Star + LCD_Currentfonts->Height ) > LCD_Y_LENGTH )
			{
				usX = ILI9341_DispWindow_X_Star;
				usY = ILI9341_DispWindow_Y_Star;
			}			
		
		  ILI9341_LCD_DisChar_EN ( usX, usY, * pStr );
			
			usX +=  LCD_Currentfonts->Width;
		
		  pStr ++;

		}
		
		else	                            //汉字字符
		{
			if ( ( usX - ILI9341_DispWindow_X_Star + CH_WIDTH ) > LCD_X_LENGTH )
			{
				usX = ILI9341_DispWindow_X_Star;
				usY += CH_HEIGHT;
			}
			
			if ( ( usY - ILI9341_DispWindow_Y_Star + CH_HEIGHT ) > LCD_Y_LENGTH )
			{
				usX = ILI9341_DispWindow_X_Star;
				usY = ILI9341_DispWindow_Y_Star;
			}	
			
			usCh = * ( uint16_t * ) pStr;	
			
			usCh = ( usCh << 8 ) + ( usCh >> 8 );		

			ILI9341_LCD_DisChar_CH ( usX, usY, usCh );
			
			usX += CH_WIDTH;
			
			pStr += 2;           //一个汉字两个字节 
		
    }
		
  }	
} 

/*
*@brief 
*@param 
*@retval
*/
void ILI9341_LCD_DisStr_CH_EN_Line(uint16_t line,char *pStr)
{	
	uint16_t usCh;
	uint16_t usX=0;
	while(*pStr!='\0')
	{
		if(*pStr<127)
		{
			if((usX+LCD_Currentfonts->Width)>LCD_X_LENGTH)
			{
				usX	=	ILI9341_DispWindow_X_Star;
				line	+= LCD_Currentfonts->Height;
				
			}
			if((line+LCD_Currentfonts->Height)>LCD_Y_LENGTH)
			{
				usX	=	ILI9341_DispWindow_X_Star;
				line	=	ILI9341_DispWindow_Y_Star;
			}
			ILI9341_LCD_DisChar_EN(usX,line,*pStr);
			usX	+=	LCD_Currentfonts->Width;
			pStr++;
		}
		else
		{
			if((usX+CH_WIDTH)>LCD_X_LENGTH)
			{
				usX	=	ILI9341_DispWindow_X_Star;
				line	+= CH_HEIGHT;
				
			}
			if((line+CH_HEIGHT)>LCD_Y_LENGTH)
			{
				usX	=	ILI9341_DispWindow_X_Star;
				line	=	ILI9341_DispWindow_Y_Star;
			}
			
			usCh	=	*(uint16_t *)pStr;
			
			usCh	=	(usCh<<8) + (usCh>>8);
			
			ILI9341_LCD_DisChar_CH(usX,line,usCh);
			
			usX	+= CH_WIDTH;
			
			pStr	+=	2;
			
		}
	}

}

/**
 * @brief  在 ILI9341 显示器上显示中英文字符串(沿Y轴方向)
 * @param  usX :在特定扫描方向下字符的起始X坐标
 * @param  usY :在特定扫描方向下字符的起始Y坐标
 * @param  pStr :要显示的中英文字符串的首地址
 * @note 可使用LCD_SetBackColor、LCD_SetTextColor、LCD_SetColors函数设置颜色
 * @retval 无
 */
void ILI9341_DispString_EN_CH_YDir (  uint16_t usX,uint16_t usY , char * pStr )
{
	uint16_t usCh;
	
	while( * pStr != '\0' )
	{			
			//统一使用汉字的宽高来计算换行
			if ( ( usY - ILI9341_DispWindow_Y_Star + CH_HEIGHT ) >LCD_Y_LENGTH  )
			{
				usY = ILI9341_DispWindow_Y_Star;
				usX += CH_WIDTH;
			}			
			if ( ( usX - ILI9341_DispWindow_X_Star + CH_WIDTH ) >  LCD_X_LENGTH)
			{
				usX = ILI9341_DispWindow_X_Star;
				usY = ILI9341_DispWindow_Y_Star;
			}
			
		//显示	
		if ( * pStr <= 126 )	           	//英文字符
		{			
			ILI9341_LCD_DisChar_EN ( usX, usY, * pStr);
			
			pStr ++;
			
			usY += CH_HEIGHT;		
		}
		else	                            //汉字字符
		{			
			usCh = * ( uint16_t * ) pStr;	
			
			usCh = ( usCh << 8 ) + ( usCh >> 8 );		

			ILI9341_LCD_DisChar_CH ( usX,usY , usCh );
			
			usY += CH_HEIGHT;
			
			pStr += 2;           //一个汉字两个字节 
		
    }
		
  }	
} 

/**
  * @brief  清除某行文字
  * @param  Line: 指定要删除的行
  *   本参数可使用宏LINE(0)、LINE(1)等方式指定要删除的行,
  *   宏LINE(x)会根据当前选择的字体来计算Y坐标值,并删除当前字体高度的第x行。
  * @retval None
  */
void LCD_ClearLine(uint16_t Line)
{
  ILI9341_Clear(0,Line,LCD_X_LENGTH,((sFONT *)LCD_GetFont())->Height);	/* 清屏,显示全黑 */

}
/*********************end of file*************************/

  • 1
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值