第25章全字库在S T e m W i n上的实现(G B2312编码)本章节为大家讲解GB2312编码全字库的实现,对于习惯了GB2312编码的用户来说,使用本章节的方法非常合适。
emWin本身是不支持GB2312编码字符显示的,本章节是新创建一种字体类型来实现GB2312编码字符的显示,所采用的方式是早期UCGUI3.98时期遗留下来,但对那种方法进行了修改,以适合高版本emWin5.xx的使用。
25.1 初学者重要提示25.2 GB2312编码全字库说明25.3 GB2312全字库的移植方法25.4 移植文件简易说明25.5 GB2312字库使用方法25.6 实验例程说明(RTOS)25.7 实验例程说明(裸机)25.8总结25.1初学者重要提示◆对于不习惯前面章节讲解的XBF格式和SIF格式的Unicode编码全字库的用户来说,使用GB2312编码是很好的选择,很适合初学者,汉字操作方式与大家使用裸机代码(没有使用GUI)时是一样的。
◆GB2312编码的全字库文件可以存到任何外部存储介质中。
本章节配套例子是将其存储到SPI Flash里面了。
◆使用GB2312编码也是有缺点的,相比前面章节使用FontCvt生成的XBF格式和SIF格式全字库,GB2312编码全字库不支持抗锯齿效果,且仅支持等宽字体(仅支持等宽是因为当前新字体的创建方法不支持非等宽字体)。
25.2G B2312编码全字库说明本章节配套例子使用的字库是从字库芯片提取出来的,下面是点阵字库相关信息,仅列出了要用到的点阵字符:1 11x12点阵 GB2312 A1A1-F7FE 6763+846 0000 24字节3 24x24点阵 GB2312 A1A1-F7FE 6763+846 68190 72字节4 32x32点阵 GB2312 A1A1-F7FE 6763+846 EDF00 128字节5 6x12点ASCII ASCII 20-7F 96 1DBE00 12字节6 8x16点ASCII ASCII 20-7F 96 1DD780 16字节7 12x24点ASCII ASCII 20-7F 96 1DFF00 36字节8 16x32点ASCII ASCII 20-7F 96 1E5A50 64字节了解了点阵字体的相关信息后,剩下就是寻址算法了。
汉字点阵在汉字库中的地址计算:汉字库种类繁多,但都是按照区位的顺序排列的。
前一个字节为该汉字的区号,后一个字节为该字的位号,位号是该字在该区中的位置。
GB2312编码区范围是A1A1到F7FE,一共F7-A1+1 = 87个区,每区有FE-A1+1=94个字符,因此GB2312可以表示87*94=8178个字符。
计算公式为:(94 * (区号 - 1) + 位号 - 1) * 一个汉字字模占用字节数 我们在计算机中常用的汉字编码为汉字内码,不是区位码,需要进行转换。
因此最终的计算公式为:ADDRESS = [(内码1 - 0xa1) * 94 + (内码2 - 0xa1)] *一个汉字字模占用字节数 (内码1对应区号,内码2对应位号)ASCII区,GB2312编码的全角字符区和汉字区的所有字符可以看下这个帖子:/read.php?tid=201,初学者务必看下,非常有必要。
下面对这8种点阵依次做下说明:汉字点阵GB2312编码字库地址计算GBCode表示汉字内码。
MSB 表示汉字内码GBCode的高8bits,LSB 表示汉字内码GBCode的低8bits。
Address 表示汉字或ASCII字符点阵在芯片中的字节地址。
BaseAdd:说明点阵数据在字库中的起始地址。
11*12点阵计算方法:BaseAdd=0x0;if(MSB >=0xA1 && MSB <= 0Xa9 && LSB >=0xA1)Address =( (MSB – 0xA1) * 94 + (LSB – 0xA1))*24+ BaseAdd;else if(MSB >=0xB0 && MSB <= 0xF7 && LSB >=0xA1)Address = ((MSB – 0xB0) * 94 + (LSB – 0xA1)+ 846)*24+ BaseAdd;15*16点阵计算方法:BaseAdd=0x2C9D0;if(MSB >=0xA1 && MSB <= 0Xa9 && LSB >=0xA1)Address =( (MSB - 0xA1) * 94 + (LSB - 0xA1))*32+ BaseAdd;else if(MSB >=0xB0 && MSB <= 0xF7 && LSB >=0xA1)Address = ((MSB - 0xB0) * 94 + (LSB - 0xA1)+ 846)*32+ BaseAdd;24*24点阵计算方法:BaseAdd=0x68190;if(MSB >=0xA1 && MSB <= 0Xa9 && LSB >=0xA1)Address =( (MSB - 0xA1) * 94 + (LSB - 0xA1))*72+ BaseAdd;else if(MSB >=0xB0 && MSB <= 0xF7 && LSB >=0xA1)Address = ((MSB - 0xB0) * 94 + (LSB - 0xA1)+ 846)*72+ BaseAdd;32*32点阵计算方法:BaseAdd=0XEDF00;if(MSB >=0xA1 && MSB <= 0Xa9 && LSB >=0xA1)Address =( (MSB - 0xA1) * 94 + (LSB - 0xA1))*128+ BaseAdd;else if(MSB >=0xB0 && MSB <= 0xF7 && LSB >=0xA1)Address = ((MSB - 0xB0) * 94 + (LSB - 0xA1)+ 846)*128+ BaseAdd;这四种点阵字体除了每个点阵字符的字节数和起始地址不一样,其余都是一样的。
其中第一个if条件语句是判断区号在0xA1到0xA8里面的全角字符区,共846个字符。
第二个else if条件语句是判断区号在0xB0到0xF7里面的汉字区,共6763个汉字。
ASCII字符地址计算ASCIICode:表示 ASCII 码( 8bits)BaseAdd:说明该套字库在芯片中的起始地址。
Address: ASCII 字符点阵在芯片中的字节地址。
6x12点阵ASCII计算方法:BaseAdd=0x1DBE00if (ASCIICode >= 0x20) and (ASCIICode <= 0x7E)Address = (ASCIICode –0x20 ) * 12+BaseAdd8x16点阵ASCII计算方法:BaseAdd=0x1DD780if (ASCIICode >= 0x20) and (ASCIICode <= 0x7E)Address = (ASCIICode –0x20 ) * 16+BaseAdd12x24点阵ASCII计算方法:BaseAdd=0x1DFF00if (ASCIICode >= 0x20) and (ASCIICode <= 0x7E)Address = (ASCIICode –0x20 ) * 48+BaseAdd16x32点阵ASCII计算方法:BaseAdd=0x1E5A50if (ASCIICode >= 0x20) and (ASCIICode <= 0x7E)Address = (ASCIICode –0x20 ) * 64+BaseAdd这四种点阵字体除了每个点阵字符的字节数和起始地址不一样,其余都是一样的。
每个点阵都是只用 到了0x20到0x7E,共96个字符。
---------------------------------------------------------------讲解完编码地址的计算后,再说一个比较重要的知识点,初学者容易在这个问题上面犯迷糊。
汉字内码在文件里面存储的时候就是按照高低字节依次存储的,比如汉字“我”的GB2312编码是0xced2,汉字“们”的编码是0xc3c7,现在我们在电脑端新建一个记事本文件,然后将“我们”这两个字写到电脑端的记事本里面,然后保存,文本编码类型选择ANSI即可。
此时将这个文本文件用winhex打开,可以看到,编码数值如下:跟汉字的编码值对比后发现汉字的编码值存储就是高低字节依次存储的。
那么问题来了,一般情况下,使用MCU微控制器的时候都是用的小端模式,即低地址存储低位数据,高地址存储高位数据。
现在我们采用如下的程序做简单的测试:char *ptr = {"我们"};U16 c1, c2;c1 = *(U16 *)ptr;c2 = *(U16 *)(ptr + 2);printf("c1 = %x, c2 = %x\r\n", c1, c2);串口打印的输出结果就是 c1 = 0xd2ce , c2 = 0xc7c3。
正好与汉字内码的高低字节反过来了,初学者在学习的时候务必要注意这个问题。
25.3G B2312全字库的移植方法这里用到的几个移植文件是早期UCGUI3.XX版本时代遗留下来的,但都进行了修改,更加适合STemWin5.xx版本使用(由于早期UCGUI3.XX版本是有源码的,这种方式是在源码的基础上新创建的一种字体方式,适合国内用的GB编码)。
图25-1GUI_Font12.c,GUI_Font16.c,GUI_Font24.c和GUI_Font32.c都是相同的代码结构,仅仅是定义的点阵大小不同,用户要实现其它点阵大小的字体,只需根据这几个文件照葫芦画瓢即可。
剩下的两个文件GUI_UC_EncondeNone.c和GUICharPEx.c是必须要包含的,用户需要根据字库的起始位置做修改(如何修改,看本章节的25.4小节,本章节配套的例子不用改,因为已经根据25.2小节的起始地址设置好了)。
接下来要做的移植工作比较简单,仅需两步即可完成:第1步:将图25-1中的6个文件全部添加到工程中,IAR和MDK是一样的,下面以MDK为例进行说明。