跟着原子学习stm32之汉字显示

       学习stm32有2年的时间了,但是也只是有些基础的了解。为了深入的学习stm32应用,从新拿起原子写的《stm32开发指南》来深入的学习,所以这里太基本的东西不讲。文中有可能会搬一些原子大神的东西。


       字库显示的整个过程可以概括为:

       根据汉字的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的转换就必不可少了!


以上为看原子讲义的小总结,比较笼统,欢迎批评指正









你可能感兴趣的:(c,汉字编码,汉字显示)