STM32 - 外部flash - unicode转gbk

前言

之前在百度语音系列文章中,我们使用RT-Thread的SUFD和fal软件包读取存储在外部flash的字库,实现了将语音识别结果显示到LCD上。在这过程中我们知道,百度语音识别的结果是utf-8的编码,而LCD显示需要的是gbk编码,需要经过utf-8 -> unicode -> gbk得到gbk编码,所以我们又实现了两个函数:

/* utf-8转unicode */
utf8_to_unicode()

/* unicode转gbk */
unicode_to_gbk()

有了这两个函数,我们就可以将语音识别结果(utf-8)转成LCD显示所需要的gbk编码。

这里简单说明一下:utf-8和unicode之间有直接的关系,只需根据它们之间的关系,编写转换函数即可(即utf8_to_unicode( )),但unicode和gbk两者却没有直接的关系了,想要实现它们的转换,就必须进行查表,unicode和gbk各自对应一个数组,这两个数组组成一个对应表,前面文章实现时在头文件中包含了这个表,unicode_to_gbk( )的功能也就是查表。

但是因为这个表对单片机来说太大了,直接写在程序里太占用flash,所以我们可以把它和字库一样放进外部flash里,其实我们之前用的正点原子的字库它就包含了这个表,那么。。。别问我那时候为什么不直接用外部flash的表,因为我那时候尝试了很久都没有成功。。。但是经过我后面的不断尝试,终于搞定了,下面就分享一下:如何使用RT-Thread的fal软件包,读取外部flash的转换表,实现unicode转gbk。

myff_convert和unicode2gbk

学习过FATFS文件系统和汉字显示的同学应该对cc936.c这个文件很熟悉,cc936.c是文件系统里用来支持长文件名的,该文件里包含了两个数组 oem2uni 和 uni2oem ,其实存放的就是unicode和gbk的互相转换对照表,同时cc936.c还提供了ff_convert函数实现unicode和gbk的互换。

那我们要做的就是修改ff_convert函数,实现从外部flash读取转换表,因为RT-Thread的文件系统也有ff_convert函数,所以我将这里的改为myff_convert:

unsigned short myff_convert (	/* Converted code, 0 means conversion error */
	unsigned short	src,	/* Character code to be converted */
	unsigned int	dir		/* 0: Unicode to OEMCP, 1: OEMCP to Unicode */
)
{
	ftinfo.ugbkaddr = 0x0000000+sizeof(ftinfo);     //fal分区中转换表的地址
	ftinfo.ugbksize = 174344;                       //转换表的大小

	const struct fal_partition *partition = fal_partition_find("font"); //转换表所在分区为font

	unsigned short t[2];
	unsigned short c;
	uint32_t i, li, hi;
	uint16_t n;			 
	uint32_t 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;	
		}    
		/* Unicode to OEMCP */
		hi=ftinfo.ugbksize/2;//对半开.
		hi =hi / 4 - 1;
		li = 0;
		for (n = 16; n; n--)
		{
			i = li + (hi - li) / 2;	
			fal_partition_read(partition, ftinfo.ugbkaddr+i*4+gbk2uni_offset, (uint8_t*)&t, 4);
			//W25QXX_Read((u8*)&t,ftinfo.ugbkaddr+i*4+gbk2uni_offset,4);//读出4个字节  
			if (src == t[0]) break;
			if (src > t[0])li = i;  
			else hi = i;    
		}
		c = n ? t[1] : 0;  	    
	}
	return c;
}		   

myff_convert实现了单个字符的转换,紧接着:

void unicode2gbk(uint8_t *src,uint8_t *dst)
{
	uint16_t temp; 
	uint8_t buf[2];
	while(*src)
	{
			buf[0]=*src++;
			buf[1]=*src++;
 			temp=(uint16_t)myff_convert((unsigned short)*(uint16_t*)buf,0);
			if(temp<0X80)
            {
                *dst=temp;
                dst++;
            }
			else 
            {
                *(uint16_t*)dst=swap16(temp);
                dst+=2;
            }
		} 
	*dst=0;//添加结束符
}

unicode2gbk便是最后供我们使用的转换函数了。

测试验证(用法)

这次我用一个天气预报程序来简单验证,同样是解析json数据后:

/* 调用utf8_to_unicode将解析的天气数据(utf-8)转成unicode */
utf8_to_unicode(hh->valuestring, (char*)buf);

/* 使用上面实现的unicode2gbk将unicode转成gbk */
unicode2gbk((uint8_t*)buf,(uint8_t*)buffer);

/* 显示 */
show_str(100, 80, 200, 32, (uint8_t*)buffer, 32);

12ee0c7da07a0480cc6ac781c55b734.jpg

图中的"广州"和"多云"便是解析转码后的网络数据,测试无误。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值