字库显示的整个过程可以概括为:
根据汉字的GBK码找字库码。根据字库码以bit的形式在显示屏上显示出来。
整个过程主要包括两个难点:
1、GBK码和字库码的存储。
2、如何根据汉字查找码值,然后显示出来
解决第一个问题。
本节的应用是将UNIGBK文件、GBK12文件、GBK16文件从SD卡中移植到W25Q64中,首先关于各个文件的生成请看原子写的《stm32开发指南》中46章介绍。然后程序的开始首先要检测SD卡中各个文件是否存在,如果存在的话,则根据要求做移植,那么问题是移植到哪里呢。对于W25Q64,我的观点是它是一个死的存储机构。你可以随心所遇的选择移植的位置。但有个问题,如果你使用了某个区域做其它用途,如实验数据的记录等,千万不要覆盖了它们的位置。另外要计算下你选取的首地址到W25Q64的最后地址能否足够大盛的下这几个文件。考虑了这两点,你就可以做接下的操作了,那就是判断移植!这里有个小问题,就是在第一次完成移植后,W25Q64中有了字库文件。可以设置一个地址为标志为地址,用来表明当前W25Q64中是否存在字库,这样每次初始化判断一下可以避免字库的重复写入。
解决第二个问题。
GBK码是汉字内码扩展规范,字库码(需要自己制作,详细制作方法见原子stm32开发指南)对应GBK码的编码形式的存在。即GBK码中一个汉字占两个字节,第一个字节为 0X81~0XFE,第二个字节分为两部分,一是 0X40~0X7E,二是 0X80~0XFE。
共有23940个汉字。而字库码中一个汉字所占字节数是不固定的,他根据汉字的大小来确定(即使用软件生成字库文件时设置的宽和高决定的)。它是以bit的形式将汉字拼出来,如果要显示的汉字大,则该汉字占用的字节数就多。由于字库码是根据GBK码来制作的,所与两个文件中的汉字顺序是相同的。当我们使用GBK码去查找他对应的要显示的汉字时,需要先通过GBK码计算他在字库中是第几个汉字,然后根据单个字的大小计算字的编码偏移首地址。
这是汉字显示部分我读原子《stm32开发指南》的一些整理。没涉及到具体。
在使用汉字显示时,原子在文中还提到了CC936的改编,其中的两个UNI2GBK和GBK2UNI数组单独放在一个文件中生成了一个UNI2GBK.BIN文件。这两个数据有个特点:即4个字节表示一个汉字(uni20em数组是前两个字节为unicode码,后两个字节为其对应的GBK码;oem2uni数组是前两个字节为GBK码,后两个字节为其对应的unicode码),所以除以4,代表一共有多少汉字,然后在srcsrc == p[i * 2]中乘以2 是因为两个字节为一个数组元素,即一个汉字占数组的两个元素。所以对应第N个汉字,它在数组中位置为N*2。最后的输出为c = n ? p[i * 2 + 1] : 0;表明输出查找到的GBK码(unicode码)后面对应的unicode码(GBK码)。
它的代码是
<span style="font-size:14px;">WCHAR ff_convert ( /* Converted code, 0 means conversion error */
WCHAR src, /* Character code to be converted */
UINT dir /* 0: Unicode to OEMCP, 1: OEMCP to Unicode */
)
{
WCHAR t[2];
WCHAR c;
u32 i, li, hi;
u16 n;
u32 gbk2uni_offset=0;
if (src < 0x80)c = src;//ASCII,直接不用转换.
else
{
if(dir) //GBK 2 UNICODE
{
gbk2uni_offset=ftinfo.ugbksize/2;
}else //UNICODE 2 GBK
{
gbk2uni_offset=0;
}
//if(UK_FLAG)//存在
{
/* Unicode to OEMCP */
hi=ftinfo.ugbksize/2;//对半开.
hi =hi / 4 - 1;
li = 0;
for (n = 16; n; n--)
{
i = li + (hi - li) / 2;
SPI_Flash_Read((u8*)&t,ftinfo.ugbkaddr+i*4+gbk2uni_offset,4);//读出8个字节
if (src == t[0]) break;
if (src > t[0])li = i;
else hi = i;
}
c = n ? t[1] : 0;
}
//else c=0;
}
return c;
} </span>
我查看了程序的代码,在原子的例程中,除了改编后的mycc936调用了UNI2GBK文件其它地方没有调用他,程序中也没有间接调用。那么UNI2GBK文件存在的意义是什么?
在FATFS中存在这样的定义:
<span style="font-size:14px;">#define _USE_LFN 2 /* 0 to 3 */
#define _MAX_LFN 255 /* Maximum LFN length to handle (12 to 255) */
/* The _USE_LFN option switches the LFN support.
/
/ 0: Disable LFN feature. _MAX_LFN and _LFN_UNICODE have no effect.
/ 1: Enable LFN with static working buffer on the BSS. Always NOT reentrant.
/ 2: Enable LFN with dynamic working buffer on the STACK.
/ 3: Enable LFN with dynamic working buffer on the HEAP.
/
/ The LFN working buffer occupies (_MAX_LFN + 1) * 2 bytes. To enable LFN,
/ Unicode handling functions ff_convert() and ff_wtoupper() must be added
/ to the project. When enable to use heap, memory control functions
/ ff_memalloc() and ff_memfree() must be added to the project. */
#define _LFN_UNICODE 0 /* 0:ANSI/OEM or 1:Unicode */
/* To switch the character code set on FatFs API to Unicode,
/ enable LFN feature and set _LFN_UNICODE to 1. */</span>
其中的_USE_LFN表示是否支持长文件名,在支持长文件名的情况下,可选择是否把长文件名的的字符数据在FATFS接口上转为UNICODE码。可以看到这是在FATFS中用到了UNI2GBK文件的地方,实际上如果我们仅仅测试将中文名打印到显示屏上的话,是用不到UNI2GBK文件文件的。
在ARM中文字是以GBK编码存在,但是在WINDOWS系统值,文字的存在形式是UNICODE编码,这样,当应用到FATFS时,UNICODE与GBK的转换就必不可少了!
以上为看原子讲义的小总结,比较笼统,欢迎批评指正
|