在线时间665 小时
UID3038360
注册时间2015-4-12
NXP金币0
TA的每日心情 | 擦汗 2021-9-9 22:51 |
---|
签到天数: 415 天 连续签到: 1 天 [LV.9]以坛为家II
金牌会员
 
- 积分
- 5181
- 最后登录
- 2022-5-23
|
本帖最后由 ALTIUM2 于 2015-8-26 21:07 编辑
每天解决一个问题2 :MCU显示中文字库的方法
------------------------------------------------------------------------------------------------------------- 电子工程师在做电子产品的时候,经常会用到人机界面,而人机界面中我们常常需要显示中文汉字,以下我就为大伙整理一下常用的三种方法。
==预备知识
汉字机内码,又称“汉字ASCII码”,简称“内码”,指计算机内部存储,处理加工和传输汉字时所用的由0和1符号组成的代码。输入码被接受后就由汉字操作系统的“输入码转换模块”转换为机内码,与所采用的键盘输入法无关。机内码是汉字最基本的编码,不管是什么汉字系统和汉字输入方法,输入的汉字外码到机器内部都要转换成机内码,才能被存储和进行各种处理。
因为汉字处理系统要保证中西文的兼容,当系统中同时存在ASCII码和汉字国标码时,将会产生二义性。例如:有两个字节的内容为30H和21H,它既可表示汉字“啊”的国标码,又可表示西文“0”和“!”的ASCII码。为此,汉字机内码应对国标码加以适当处理和变换。
国标码的机内码为二字节长的代码,它是在相应国标码的每个字节最高位上加“1”,即
汉字机内码=汉字国标码+8080H
例如,上述“啊”字的国标码是3021H,其汉字机内码则是B0A1H。
汉字机内码的基础是汉字国标码。
机内码:为了避免ASCII码和国标码同时使用时产生二义性问题,大部分汉字系统都采用将国标码每个字节高位置1作为汉字机内码。这样既解决了汉字机内码与西文机内码之间的二义性,又使汉字机内码与国标码具有极简单的对应关系。
汉字机内码、国标码和区位码三者之间的关系为:区位码(十进制)的两个字节分别转换为十六进制后加2020H得到对应的国标码;机内码是汉字交换码(国标码)两个字节的最高位分别加1,即汉字交换码(国标码)的两个字节分别加80H得到对应的机内码;区位码(十进制)的两个字节分别转换为十六进制后加A0H得到对应的机内码。
总的就是一个汉字对应一个机内码,在 IDE 中,汉字将会被“翻译”成唯一的机内码。
-------------------------------------------------------------------------------------------------------------
(一)按地址内部或者外扩FLASH存储标准字库中所取字模
该方法的原理就是将一个标准的汉字库装入ROM存储器,再根据汉字的机内码在字库中寻址,找到对应的字模,提取后送到显示器显示。因为采用了和PC机相同的编码(机内码),软件的开发和维护非常简单,基本上与写PC机软件差不多。而对单片机系统自身的要求则相对高多了,16×16点阵的字库需要256K字节,但是一般8位单片机的寻址能力只有64K字节,要进行存储器扩充,除增加很大一部分硬件成本外,还因为要进行存储器分页管理、地址切换,显示速度明显受影响,而且只能显示一种点阵字体。
实际举例1:
void GUI_HZDispChar(U16 c)
{
…………
if(c >= 0xa1a1)
{
temp = c;
qh = (temp>>8)&0xff;
wh = temp&0xff;
c0 = 94*(qh-0xB0)+wh-0xA1 + 95;
}
else
{
c0 = c - 0x20;
XDist = XDist/2;
}
…………
}
核心:首先判断是否是汉字通,然后根据机内码找到你存在FLASH中字库位置的字模数据,最后提取显示出来
-------------------------------------------------------------------------------------------------------------
(二)直接固化显示字模,按地址选取
该方法的将要显示的语句中全部汉字的字模数据依次提取出来,顺序存放在存储器中,当显示时,直接取出字模数据送至显示器即可。这种方法占用空间少,程序实现简单,显示速度快;但是字模数据的提取和存储安排是一件委有繁琐的事件,要想大量显示汉字或进行程序修改几乎是不可能的,软件的可维护性很差。
实际举例2://先定义所用字模库
code uint8 shi[9][28] =
{
/* 业 */
0x08,0x80,0x08,0x80,0x08,0x80,0x88,0x88,0x48,0x88,0x48,0x90,0x28,0x90,0x28,0xA0,
0x28,0xA0,0x08,0x80,0x08,0x80,0x08,0x80,0xFF,0xF8,0x00,0x00,
/* 务 */
0x10,0x00,0x1F,0xE0,0x30,0x40,0x4D,0x80,0x82,0x00,0x0D,0x80,0x70,0x78,0x84,0x10,
0x3F,0xC0,0x04,0x40,0x08,0x40,0x10,0x40,0x61,0x80,0x00,0x00,
……
};
//再取所用字模
memcpy(g_uca_HZFont14,shi[0],28);
//最后调用显示函数即可
-------------------------------------------------------------------------------------------------------------(三)建立带索引的小字库[3]
将全部要显示的汉字统一建成一个小字库,字库分为2部分:索引素和字模表。索引表由若干定长记录组成,记录的内容为:汉字机内码、地址码、识别码。其中地址码是该汉字字模在字模表中的位置,识别码标志该汉字的点阵形式或字体等。字模表中按素引存放汉字字模。显示汉字时先根据待显汉字的机内码在索引表中寻找,找到对应索引记录后,读出地址码和识别码,再根据此从字模表中读出字模,送显即可。这种方法可根据实际使用对字库进行裁剪,硬件开销较小,但是要进行复杂的查询运算,字多了平均寻找时间就会变长,效率降低。
实际举例3:
// ------------------ 汉字字模的数据结构定义 ------------------------ //
struct typFNT_GB16 // 汉字字模数据结构
{
unsigned char Index[3]; // 汉字内码索引
unsigned char Msk[32]; // 点阵码数据
};
/////////////////////////////////////////////////////////////////////////
// 汉字字模表 //
// 汉字库: 宋体16.dot,横向取模左高位,数据排列:从左到右从上到下 //
/////////////////////////////////////////////////////////////////////////
code struct typFNT_GB16 codeGB_16[] = // 数据表
{
/*-- 文字: 上 --*/
/*-- 宋体12; 此字体下对应的点阵为:宽x高=16x16 --*/
"上",0x00,0x00,0x01,0x00,0x01,0x00,0x01,0x00,0x01,0x00,0x01,0x00,0x01,0xF8,0x01,0x00,
0x01,0x00,0x01,0x00,0x01,0x00,0x01,0x00,0x01,0x00,0x01,0x04,0x7F,0xFE,0x00,0x00,
/*-- 文字: 海 --*/
/*-- 宋体12; 此字体下对应的点阵为:宽x高=16x16 --*/
"海",0x21,0x00,0x11,0x00,0x11,0xFE,0x02,0x00,0x97,0xF8,0x52,0x88,0x52,0x48,0x12,0x08,
0x2F,0xFE,0x22,0x88,0xE2,0x48,0x22,0x08,0x23,0xFE,0x20,0x08,0x20,0x28,0x20,0x10,
…………
};
//调用函数+索引
void PutGB1616(unsigned short x, unsigned short y, unsigned char c[2], unsigned int fColor,unsigned int bColor)
{
unsigned int i,j,k;
LCD_SetPos(x, x+16-1,y, y+16-1);
for (k=0;k<64;k++)
{ //64标示自建汉字库中的个数,循环查询内码
if ((codeGB_16[k].Index[0]==c[0])&&(codeGB_16[k].Index[1]==c[1]))
{
for(i=0;i<32;i++)
{
unsigned short m=codeGB_16[k].Msk;
for(j=0;j<8;j++)
{
if((m&0x80)==0x80)
{
Write_Data_U16(fColor);
}
else
{
Write_Data_U16(bColor);
}
m<<=1;
}
}
}
}
}
-------------------------------------------------------------------------------------------------------------
(四)个人总结:
方法一:
标准字库使用确实非常方便快捷,维护简单,但是对MCU资源有要求或者需要外扩FLASH,成本提高了,而且最重要的如果外扩时,烧录字库很不方便。
方法二:
固定的字库数组虽然可以减少MCU 的flash需求,但是编写程序寻找字模非常不便,维护困难,可以说是一个吃力不讨好的辛苦活。
方法三:
索引的方法寻找字模,结合一二两种方法的优点,即降低才成本而且维护也较方便,但是在大量字模时,会影响MCU速度。
通过这三种方法的对比,找到你最需的方法了吗?

|
评分
-
查看全部评分
|