LCD显示GBK字库里面的汉字
前言
本文介绍如何把字库文件写入单片机的flash后,在单片机程序中添加代码直接显示汉字;或者显示接收上位机发送过来的UTF_8编码规则的信息。
提示:以下是本篇文章正文内容,下面案例可供参考
一、编码规则
从网上引来一段从UNICODE到UTF8的转换规则:
UTF-8: 1~3字节可变
UNICODE: 2字节一个字符
GB2312: 2字节一个字符
例子: “你”字的UTF-8编码: E4 BD A0 11100100 10111101 10100000
“你 ”的 Unicode 编码 : 4F 60 01001111 01100000
按照UTF-8的编码规则,分解如下:xxxx0100 xx111101 xx100000
把除了x之外的数字拼接在一起,就变成“你”的Unicode编码了。
注意UTF-8的最前面3个1,表示整个UTF-8串是由3个字节构成的。
经过UTF-8编码之后,再也不会出现敏感字符了,因为最高位始终为1。
GBK与Unicode之间并没有很明确的对应关系,因此就实用性而言还是查表法为主,另外表格平时可保存在Flash中。
二、使用步骤
1.需烧录的字库
这里不讨论怎样把字库烧录到单片机外部Flash
需要烧录单片机外部Flash的文件有GBK.FON,Unicode.bin
2.转码
把UTF_8编码转换成Unicode编码,之后根据转换成的Unicode编码查找Flash中Unicode编码与GBK编码对应表格获得GBK编码。得到显示字库中的字节偏移量即可实现单片机显示中文字符的功能。
/*
*pszBufIn:需要转换的UTF_8内码
*nBufInLen:转换长度
*pszBufOut:转换后的Unicode内码
*pnBufOutLen:转换后的Unicode内码长度
*/
int UTF_8ToUnicode(const unsigned char* pszBufIn, int nBufInLen, unsigned char* pszBufOut, int* pnBufOutLen)
{
int i = 0;
int j = 0;
unsigned short unicode;
unsigned short gbk;
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);
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.函数体
//在指定位置开始显示一个字符串
//支持自动换行
//(x,y):起始坐标
//width,height:区域
//str :字符串
//size :字体大小
//mode:0,非叠加方式;1,叠加方式
void Show_Str_font(uint16_t x,uint16_t y,uint16_t width,uint16_t height,uint8_t*str,uint16_t fc)
{
uint16_t x0=x;
uint16_t y0=y;
uint8_t bHz=0; //字符或者中文
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;//下一个汉字偏移
}
}
if(*str>0x80)
lcd_full_black(0,0,240,8);
}
//显示一个指定大小的汉字
//x,y :汉字的坐标
//font:汉字GBK码
//size:字体大小
//mode:0,正常显示,1,叠加显示
void Show_Font(uint16_t x,uint16_t y,uint8_t *font,uint16_t fc)
{
// uint8_t size = 24;
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); //得到相应大小的点阵数据
//输出
GPIO_Pin_Clear(U32BIT(LCD_CS));
for(t=0;t<csize;t++)
{
temp=dzk[t]; //得到点阵数据
for(t1=0;t1<8;t1++)
{
if(temp&0x80)
Gui_DrawPoint(x,y,fc);
temp<<=1;
y++;
if((y-y0)==size)
{
y=y0;
x++;
break;
}
}
}
GPIO_Pin_Set(U32BIT(LCD_CS));
}
3.显示汉字
...........
#define Color_White 0xFFFF //白
#define Color_Red 0xF800 //红
............
int main()
{
Show_St_font(0,0,240,240,“你好”,Color_White);
Show_St_font(0,40,240,240,“你好”,Color_red);
while(1)
}
!