在嵌入式产品中,难免会遇到由服务器或者APP端推送的消息内容,而大多数推送消息内容的字符编码都为UTF-8,底层硬件需要将推送的消息送到LCD或者OLED等屏幕上进行显示,此时就涉及到一个编码转换的内容,因为硬件不能直接将UTF-8编码的字符进行显示,必须经过算法将UTF-8编码对照Unicode编码转换为GBK汉字编码之后才能显示,而本文介绍从外部FLASH中读取Unicode编码和GBK字符编码,将UTF-8字符转换为GBK字符。
1.UTF-8转换为Unicode编码
UTF-8编码不能直接转换为GBK汉字编码,中间需要先转换为Unicode编码,在由Unicode编码转换为GBK汉字编码
2.Unicode编码转换为GBK汉字编码
Unicode汉字编码与GBK汉字编码的对照关系为,两个Unicode编码对应一个汉字,并且在Unicode编码中,汉字编码的起始位置是0x4e00,也就是说将UTF-8汉字编码转换为Unicode编码时需要偏移0x4e00去读取数据。
1.从flash读取Unicode编码
unsigned short mb_uni2gb_table[]={0};
uint16_t Read_flash_unicode(uint16_t* unicode,uint32_t ReadAddr,uint16_t num_len)
{
uint8_t buff[10];//缓冲区
ReadAddr=ReadAddr+Offset_addr;//为存储在flash 中的偏移地址
SPI_Flash_Read_2(buff,ReadAddr,num_len);
unicode[0]=(buff[1]<<8)|buff[0];
return 1;
}
2.UTF-8转换为Unicode编码
int SwitchToGbk(const unsigned char* pszBufIn, int nBufInLen, unsigned char* pszBufOut, int* pnBufOutLen)
{
int i = 0;
int j = 0;
int nLen;
unsigned short unicode;
unsigned short gbk;
for(; i < nBufInLen; i++, j++)
{
if((pszBufIn[i] & 0x80) == 0x00) // 1位
{
nLen = 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);
//从flash读取Unicode编码
Read_flash_unicode(mb_uni2gb_table,(unicode-0x4e00)*2,2);
gbk = *mb_uni2gb_table;
pszBufOut[j]= gbk/256;
pszBufOut[j+1] = gbk%256;
j++;
i+=2;
}
else
{
return -1;
}
}
*pnBufOutLen = j;
return 0;
}
3.Unicode编码转换为GBK汉字编码
void Get_HzMat(unsigned char *code,unsigned char *mat)
{
unsigned char qh,ql;
unsigned char i;
unsigned long foffset;
uint8_t size = 16;
uint8_t csize=(size/8+((size%8)?1:0))*(size);//得到字体一个字符对应点阵集所占的字节数
qh=*code;
ql=*(++code);
if(qh<0x81||ql<0x40||ql==0xff||qh==0xff)//非 常用汉字
{
for(i=0;i
1.lcd显示单个汉字的应用案例
/***************************************************************************************
** 函数名称 **:void Show_Font(uint16_t x,uint16_t y,uint8_t *font,uint16_t fc)
** 函数功能 **:lcd显示单个汉字
** 输入参数 **:uint16_t x,uint16_t y,uint8_t *font(汉字内容),uint16_t fc(汉字颜色)
** 输出参数 **:无
** 返 回 值 **:无
****************************************************************************************/
void Show_Font(uint16_t x,uint16_t y,uint8_t *font,uint16_t fc)
{
uint8_t size = 16;//固定显示16号字体
uint8_t temp,t,t1;
uint16_t y0=y;
uint8_t dzk[72];
uint8_t csize=(size/8+((size%8)?1:0))*(size);//得到字体一个字符对应点阵集所占的字节数
if(size!=12&&size!=16&&size!=24)return; //不支持的size
Get_HzMat(font,dzk); //得到相应大小的点阵数据
for(t=0;t
2.在指定区域内自动换行显示多个汉字
void Show_Str(uint16_t x,uint16_t y,uint16_t width,uint16_t height,uint8_t*str,uint16_t fc)
{
uint8_t size = 16;
uint16_t x0=x;
uint16_t y0=y;
uint8_t bHz=0; //字符或者中文
GPIO_Pin_Clear(U32BIT(LCD_CS));
while(*str!=0)//数据未结束
{
if(!bHz)
{
if(*str>0x80)bHz=1;//中文
else //字符
{
if(x>(x0+width-size/2))//换行
{
y+=size;
x=x0;
}
if(y>(y0+height-size))break;//越界返回
if(*str==13)//换行符号
{
y+=size;
x=x0;
str++;
}
else
LCD_ShowChar(x,y,*str,fc);//有效部分写入
str++;
x+=size/2; //字符,为全字的一半
}
}
else//中文
{
bHz=0;//有汉字库
if(x>(x0+width-size))//换行
{
y+=size;
x=x0;
}
if(y>(y0+height-size))break;//越界返回
Show_Font(x,y,str,fc); //显示这个汉字,空心显示
str+=2;
x+=size;//下一个汉字偏移
}
}
GPIO_Pin_Set(U32BIT(LCD_CS));
}