STM32之LCD屏GBK字库制作与调用
1.字库编码简介
在开发嵌入式系统时,需要显示不同大小或类型字体的汉字。显然,对于嵌入式系统,不太可能使用矢量字体,在这种情况下,点阵字体就显现出了它的优点。
字符编码就是以二进制的数字来对应字符集的字符,目前用得最普遍的字符集是 ANSI,对应 ANSI 字符集的二进制编码就称为 ANSI码,DOS 和 Windows 系统都使用了 ANSI 码,但在系统中使用的字符编码要经过二进制转换,称为系统内码。
汉字内码:ANSI 码是单一字节(8 位二进制数)的编码集,最多只能表示 256 个字符,不能表示众多的汉字字符,各个国家和地区在 ANSI 码的基础上又设计了各种不同的汉字编码集,以能够处理大数量的汉字字符。这些编码使用单字节来表示 ANSI 的英文字符(即兼容 ANSI 码),使用双字节来表示汉字字符。由于一个系统中只能有一种汉字内码,不能识别其它汉字内码的字符,造成了交流的不便。
GB2312 码是中华人民共和国国家汉字信息交换用编码,全称《信息交换用汉字编码字符集–基本集》,由国家标准总局发布,1981 年5 月 1 日实施,通行于大陆。新加坡等地也使用此编码。
GB2312 收录简化汉字及符号、字母、日文假名等共 7445 个图形字符,其中汉字占 6763 个。GB2312 规定<对任意一个图形字符都采用两个字节表示,每个字节均采用七位编码表示>,习惯上称第一个字节为<高字节>,第二个字节为<低字节>。GB2312-80 包含了大部分常用的一、二级汉字,和 9 区的符号。该字符集是几乎所有的中文系统和国际化的软件都支持的中文字符集,这也是最基本的中文字符集。其编码范围是高位0xa1-0xfe,低位也是0xa1-0xfe;汉字从0xb0a1开始,结束于 0xf7fe。
GB2312 将代码表分为 94 个区,对应第一字节(0xa1-0xfe);每个区 94 个位(0xa1-0xfe),对应第二字节,两个字节的值分别为区号值和位号值加 32(2OH),因此也称为区位码。01-09 区为符号、数字区,16-87 区为汉字区(0xb0-0xf7),10-15 区、88-94 区是有待进一步标准化的空白区。GB2312 将收录的汉字分成两级:第一级是常用汉字计 3755 个,置于 16-55 区,按汉语拼音字母/笔形顺序排列;第二级汉字是次常用汉字计 3008 个,置于 56-87 区,按部首/笔画顺序排列。故而 GB2312 最多能表示 6763 个汉字。
GBK 对 GB2312 进行了扩展。第一字节为 0x81~0xFE,第二字节分两部分,一是 0x40~0x7E,二是 0x80~0xFE。其中和 GB2312 相同的区域,字完全相同。扩展部分大概是按部件(部首)和笔顺(笔画)从 GB13000 中取出再排列入 GBK 中。在我的点阵字库中定位方法如下。第一个字节减去 0x81,则是正确的区位,每个区的大小要根据每个字所占用的字节×190。
在我的点阵字库中定位方法如下。第一个字节减去 0x81,则是正确的区位,每个区的大小要根据每个字所占用的字节×190(0x7f-0x40+0xff-0x80)即可。如果第二个字节小于 0x7f 则减去 0x40,
如果第二个字节大于等于 0x80 则减去 0x41。简化计算公式如下:
u8 H=*font;//汉字高字节
u8 L=*(font+1);//汉字低字节
if(L<0x7f)L=L-0x40;
else L=L-0x41;
H=H-0x81;
u16 csize=size*size/8;//汉字占用的点阵字节数
u32 Addr=(190*H+L)*csize;//汉字在GBK中的偏移量
2.点阵字库生成软件
字库生成软件可以在 WINDOWS 系统下生成任意点阵大小的 ASCII,GB2312(简体中文)、GBK(简体中文)、BIG5(繁体中文)、HANGUL(韩文)、SJIS(日文)、Unicode 以及泰文,越南文、俄文、乌克兰文,拉丁文,8859 系列等共二十几种编码的字库,不但支持生成二进制文件格式的文件,也可以生成 BDF 文件,还支持生成图片功能,并支持横向,纵向等多种扫描方式,且扫描方式可以根据用户的需求进行增加。
3.GBK字库取模示例
以16*16电子字库为例,可以设置字体大小,字体宽度和取模方式,设置成功后直接点创建即可。
4.GBK字库烧写
4.1字库文件分割
将生成的GBK字库烧写到单片机W25Q64中,便于后续LCD屏幕字符串显示调用。
烧写字库方式可以通过多种方式实现,如串口字库更新、SD卡字库更新、直接以数组方式写入等等。
首先我们先介绍一下如何以数组方式写入。由于汉字取模工具生成的字库文件为二进制格式,若生成的GBK16的字库文件大小约760KB,直接一次性写入STM32将空间不足(STM32F103ZE的flash空间仅512KB),因此我们可以使用winhex软件将字库文件分割成多个数组,采用分段方式写入。操作方式如下:
- 打开winhex软件,导入字库文件。
- 将文件分为两部分保存到工作中。首先右键,选则编辑,再选择定义选块。
- 选中后再右键编辑,复制选块,并保存为C源码。
- 最后打开KEIL工程,复制到对应.c文件中即可。
- 后一半数据按照如上操作即可完成。
4.2分段写入
由于STM32的FLASH空间有限,因此该字库文件需要分两次写入,第一次写入前半部分。写入方式如下:
#include "main.h"
//GBK16点阵字库
extern const unsigned char gbk_16_1[383040];
extern const unsigned char gbk_16_2[383040];
int main()
{
Led_Init();
Beep_Init();
Key_Init();
Usartx_Init(USART1,115200,72);
W25Q64_Init();
printf("串口初始化完成\r\n");
printf("ID=%#x\n",W25Q64_ReadID());
LCD_Init();
//写入GBK字库
printf("写GBK第一段数据\r\n");
W25Q64_WriteData(GBK_16_ADDR,(u8*)gbk_16_1,383040);
//printf("写GBK第二段数据\r\n");
//W25Q64_WriteData(GBK_16_ADDR+383040,(u8*)gbk_16_2,383040);
BEEP=1;
Delay_Ms(1000);
BEEP=0;
LCD_DisplayStr(10,200,16,WHITE,"TFT LCD屏幕16点阵字库测试示例,hello,world");
while(1)
{
LED1=!LED1;
Delay_Ms(100);
}
}
第一部分写入成功即可听到蜂鸣器响,接下来写入第二部分数据,写入方式如下:
#include "main.h"
//GBK16点阵字库
extern const unsigned char gbk_16_1[383040];
extern const unsigned char gbk_16_2[383040];
int main()
{
Led_Init();
Beep_Init();
Key_Init();
Usartx_Init(USART1,115200,72);
W25Q64_Init();
printf("串口初始化完成\r\n");
printf("ID=%#x\n",W25Q64_ReadID());
LCD_Init();
//写入GBK字库
//printf("写GBK第一段数据\r\n");
//W25Q64_WriteData(GBK_16_ADDR,(u8*)gbk_16_1,383040);
printf("写GBK第二段数据\r\n");
W25Q64_WriteData(GBK_16_ADDR+383040,(u8*)gbk_16_2,383040);
BEEP=1;
Delay_Ms(1000);
BEEP=0;
LCD_DisplayStr(10,200,16,WHITE,"TFT LCD屏幕16点阵字库测试示例,hello,world");
while(1)
{
LED1=!LED1;
Delay_Ms(100);
}
}
当两部分均写入成功后,即可看到屏幕上显示字符串信息。运行效果如下:
LCD屏幕驱动参示例:LCD屏幕驱动