学习笔记 :2019-07-13 XZJ
在使用stm32获取服务器下发的json数据时,解析出来的数据编码是utf8格式的,在串口或者LCD上显示都是乱码,为了解决这个问题,百度了一下,发现在stm32上转码的几乎没有,最后有一个用stm32+esp8266获取知心天气的例程中发现了这个转码,这是原文地址http://www.openedv.com/forum.php?mod=viewthread&tid=229818&highlight=%CD%F8%C2%E7%CC%EC%C6%F8感谢开源精神。可惜的是我使用的单片机没那么大的容量,里面转码的编码表是一个特别大的数组,单片机的flash根本存不下,还好我的板子上有外部flash,25Q64,参考了下原子的例程,移植了文件系统,吧数组保存到25q64中。
第一步、将数组转换为bin文件,使用原子提供的c2B软件。
第二步、将bin文件放到SD卡上,
第三步、使用文件系将SD卡上的bin文件存入外部flash。
下面是存储和转码的源代码,其他的文件系统等源码就不贴出来了,基本使用的都是正点原子的例程。
将结构体utf8info中的编码表信息也存入外部flash中,上电的时候可以检测信息头来判断编码表有没有被更改,一旦被更改就可以及时发现并且更新。
#include "sys.h"
#include <stdio.h>
#include "string.h"
#include "fontupd.h"
#include "LCD.h"
#include "flash.h"
#include "ff.h"
#include "malloc.h"
#include "utf8togbk.h"
#define FONTUTFTUBGK (4916)*1024//bin编码表文件存放起始地址
const u8 *UTF8TOGBK="0:/SYSTEM/FONT/utf8togbk.BIN";//bin文件在SD卡的储存路径
//编码表信息结构体.
//用来保存信息基本信息,地址,大小等
utf8info utf8_info;
//==================================================================
//函数名:fupd_prog1
//作者: 徐参考正点原子例程
//日期: 2019-7-12
//功能: 显示当前文件更新进度
//输入参数:x,y:坐标,size:字体大小,fsize:整个文件大小,pos:当前文件指针位置
//返回值: 0
//修改记录:2019-7-13
//==================================================================
u32 fupd_prog1(u16 x,u16 y,u8 size,u32 fsize,u32 pos)
{
float prog;
u8 t=0XFF;
prog=(float)pos/fsize;
prog*=100;
if(t!=prog)
{
LCD_ShowString(x+3*size/2,y,240,320,size,"%");
t=prog;
if(t>100)t=100;
LCD_ShowNum(x,y,t,3,size);//显示数值
}
return 0;
}
//==================================================================
//函数名: updata_fontx1
//作者: 徐
//日期: 2019-7-12
//功能: 更新某一个bin文件
//输入参数:x,y:LCD显示坐标,size:LCD显示字体大小,fxpath:路径
//返回值: 0,成功;其他,失败.
//修改记录:2019-7-13
//==================================================================
u8 updata_fontx1(u16 x,u16 y,u8 size,u8 *fxpath)
{
u32 flashaddr=0;
FIL * fftemp;
u8 *tempbuf;
u8 res;
u16 bread;
u32 offx=0;
u8 rval=0;
fftemp=(FIL*)mymalloc(sizeof(FIL)); //分配内存
if(fftemp==NULL)rval=1;
tempbuf=mymalloc(4096); //分配4096个字节空间
if(tempbuf==NULL)rval=1;
res=f_open(fftemp,(const TCHAR*)fxpath,FA_READ);
if(res)rval=2;//打开文件失败
if(rval==0)
{
utf8_info.utf8togbkddr=FONTUTFTUBGK+sizeof(utf8_info); //信息头之后,紧utf8togbk转换码表
utf8_info.utf8togbksize=fftemp->fsize; //UNIGBK大小
flashaddr=utf8_info.utf8togbkddr;
while(res==FR_OK)//死循环执行
{
res=f_read(fftemp,tempbuf,4096,(UINT *)&bread); //读取数据
if(res!=FR_OK)break; //执行错误
SPI_Flash_Write(tempbuf,offx+flashaddr,4096); //从0开始写入4096个数据
offx+=bread;
fupd_prog1(x,y,size,fftemp->fsize,offx); //进度显示
if(bread!=4096)break; //读完了.
}
f_close(fftemp);
}
myfree(fftemp); //释放内存
myfree(tempbuf); //释放内存
return res;
}
//==================================================================
//函数名: update_font1
//作者: 徐
//日期: 2019-7-12
//功能: 更新bin数组文件和结构体信息头
//输入参数:x,y:提示信息的显示地址,size:字体大小
//返回值: 0,更新成功; 其他,错误.
//修改记录:2019-7-13
//==================================================================
u8 update_font1(u16 x,u16 y,u8 size)
{
u8 *utf8togbk_path=(u8*)UTF8TOGBK;
u8 res;
res=updata_fontx1(x+20*size/2,y,size,utf8togbk_path); //更新UNIGBK.BIN
if(res)return 1;
//全部更新好了
utf8_info.utf8_gbk=0XBB;//信息头用来检测编码表是否被修改
SPI_Flash_Write((u8*)&utf8_info,FONTUTFTUBGK,sizeof(utf8_info)); //保存字库信息
return 0;//无错误.
}
//==================================================================
//函数名: utf8_gbk_init
//作者: 徐
//日期: 2019-7-12
//功能: 初始化编码表,检测表是否被修改
//输入参数:无
//返回值: 0完好,其他,损坏
//修改记录:2019-7-13
//==================================================================
u8 utf8_gbk_init(void)
{
SPI_Flash_Init();
SPI_Flash_Read((u8*)&utf8_info,FONTUTFTUBGK,sizeof(utf8_info));//读出ftinfo结构体数据
// printf("转码表:%x\r\n",utf8_info.utf8_gbk);
if(utf8_info.utf8_gbk!=0XBB)return 1; //字库错误.
return 0;
}
//==================================================================
//函数名: SwitchToGbk
//作者: 徐
//日期: 2019-7-12
//功能: utf8转gbk
//输入参数:pszBufI:需要转换的nutf8,nBufInLen:需要转换的nutf8的长度,
// pszBufOut:转换后的gbk,pnBufOutLen:转换后的gbk地址
//返回值:
//修改记录:2019-7-12将大数组存放在外部flash中,
// 2019-7-13获取unicode的地址偏移量,查表
//==================================================================
int SwitchToGbk(const unsigned char* pszBufIn, int nBufInLen, unsigned char* pszBufOut, int* pnBufOutLen)
{
int i = 0;
int j = 0;
unsigned short unicode;
u8 gbk[50];
for(; i < nBufInLen; i++, j++)
{
if((pszBufIn[i] & 0x80) == 0x00) // 1?
{
pszBufOut[j]= pszBufIn[i];
}
/*
else if((pszBufIn[i] & 0xE0) == 0xC0)// 2?
{
nLen = 2;
unicode = (pszBufIn[i] & 0x1F << 6) | (pszBufIn[i+1]& 0x3F);
}*/
else if ((pszBufIn[i] & 0xF0) == 0xE0) // 3?
{
if (i+ 2 >= nBufInLen) return -1;
unicode = (((int)(pszBufIn[i] & 0x0F)) << 12) | (((int)(pszBufIn[i+1] & 0x3F)) << 6) | (pszBufIn[i+2] & 0x3F);
SPI_Flash_Read(gbk,utf8_info.utf8togbkddr+(2*(unicode-0x4e00)),2);
pszBufOut[j]= gbk[1];//gbk%256;
pszBufOut[j+1] = gbk[0];//gbk/256;
j++;
i+=2;
}
else
{
return -1;
}
}
*pnBufOutLen = j;
return 0;
}
.h文件中就是函数的声明和结构体的定义,源码如下
#ifndef __utf8togbk_h
#define __utf8togbk_h
#include "sys.h"
__packed typedef struct
{
u8 utf8_gbk; //字库存在标志,0XBB,字库正常;其他,字库不存在
u32 utf8togbkddr; //utf8togbk的地址
u32 utf8togbksize; //utf8togbk的大小
}utf8info;
extern utf8info utf8_info;
u8 utf8_gbk_init(void);
u8 update_font1(u16 x,u16 y,u8 size);
u8 updata_fontx1(u16 x,u16 y,u8 size,u8 *fxpath);
int SwitchToGbk( const unsigned char* pszBufIn, int nBufInLen, unsigned char* pszBufOut, int* pnBufOutLen);
#endif