文章节选自:《ARM Cortex-M0从这里开始》 作者:zhaojun_xf https://bbs.eeworld.com.cn/thread-324656-1-1.html
字库设计与应用
一般情况下TFT彩屏或部分LCD图型液晶模块中都没有字库。所以,要能够在这些液晶模块中显示字符或汉字等,就必须设计字库。下面将介绍如何制作满足自己需要的字库文件。
1 字库制作
在电脑中,所有的数据都是以0和1保持的,按不同的数据操作,可以得到不同的结果。由于英文字母种类很少,只需要8位二进制(一字节)即可表示。而对于中文,常用的字符就有6000多个。于是,将ASCII表中的高于128的很少使用的数字两个一组来表示一个汉字,即形成了汉字内码;而低于128的ASCII则留给英文字符使用,即英文的内码。
1. 点阵字符显示原理
在打印机上打印或在显示器上显示字符,并不是得到内码就可以的。内码只是一个字符的代替符,每一个字符都有自己的字模数据,虽然也是一组数据,但意义却截然不同。这一组数据记录了各个字符的形状。
如图8-14为英文字符“A”的8×16的字模记录数据。此字符宽度为8个像素,高度为16个像素。所以,存储这样一个字符的字模数据需要(8×16)/8 = 16字节的存储空间。
如图8-15为汉字字符“你”的16×16的字模记录数据。此字符宽度为16个像素,高度也为16个像素。所以,存储这样一个字符的字模数据需要(16×16)/8 32字节的存储空间。
由上面的字模数据可以看出,如果要显示一个字符,只要获取其相应的字模数据,并把字模数据发送给显示屏就能过显示相应的字符了。
2. 字库的制作
对于英语字符,一般只需要5×7点阵字模就可以完整的显示;而对于中文,至少需要16×16的点阵才能完整的显示。为了能够在打印机上打印出适当的字符,这里将介绍制作12×24的英文字符字库和24×24的汉字字库,为第10章的使用打下基础。 至于其他大小的字库,制作原理一样的,读者可以根据自己的需要制作相应点阵的字库数据。
(1)英文字库制作
字模软件有很多,在搜索引擎上输入“字模软件”,就能搜到很多字模生成软件。下面以FontLibrary软件,来讲解英文字符字库的制作方法。
1)此软件是绿色软件,不需要安装,下载到本地磁盘后就可以直接打开了。打开FontLibrary,界面如8-16所示。
2)此软件自带了一些常用的字符集,如果有需要的可以直接选择导入。如图8-17就是导入GB2312简体中文字符集后的界面。
3)由于软件没有自带英文字符集,直接在右边的输入框中输入英文字符集。之后根据需要选择字体,设置参数,如图8-18所示。不过需要注意以下几点:
点阵大小选择自定义,然后在框中输入12×24;
扫描方式中选择的是水平扫描,这个非常重要,如果扫描方式不对,显示或打印的字符就不正确;
数据长度也非常重要,这里选择每组8个Bit。
以就是说,字模是按照横向扫描的,每8个像素点组成一个字节。那么对于12×24来说,由于横向只有12个像素点,比一个字节要多4位,而比两个字节要少4位。12位需要补4位零,补齐2字节来存储,但是显示或打印时必须去掉这补齐的4位。所以,12×24实际存储需要48字节。
4)输入字符集,按照要求设置好参数。选择要生产的字符数据格式。这里选择创建二进制文件,如图8-19所示。
5)点击生成字库后,会弹出如图8-20所示的索引生成对话框,一般情况下是不需要索引的。如果需要,在对话框中填写索引的起始地址,软件会自动在每一个字库数据之前填写按照顺序添加的多个字节的索引。这一点读者一点要注意,如果有索引,那么在读取字库数据时需要把多余的字节加上去,这里选择“取消”即可。
6)在存储对话框中输入字库文件的名称,如图8-21所示。点击保存后,英文字库就生成了。
(2)汉字字库制作
FontLibrary虽然能直接生成中文字库,而且还自带多种中文字符集。但是它最大的缺点就是速度太慢,如果生成几十个字符的字库只需要几秒,但是如果要生成几千个字符集的字库,那就需要几个小时了。对于这样的速度确实没法接受,下面选择另一款字库软件mold(牧马字模测试版ver 0.88)。
这款软件支持中文和英文字模,不过英文字模需要付费。所以,生成英文字库就使用免费的FontLibrary软件。这款软件也支持生成二进制和文本格式的字库。
1)mold也是绿色软件,从网上下载后,解压就可以直接打开了,界面如图8-22所示。
2)此软件不支持字符输入,所以,需要先新建一个文本文件,在文本文件中输入需要生成字库的字符集。由于FontLibrary自带字库集,在这里也可以拷贝这些字符集。
点击软件快捷方式“打开”,在弹出的对话框中找到字符集,并打开这个文本字符集。设置好字体参数,如图8-23所示。需要注意几个地方的参数:
点阵数设置为24;
取模设置为24×24;
输出格式选择为BIN(二进制);
方向设置为横向取模,高位在左。
3)设置好参数后,点击“输出”图标,过几秒钟后,就生成了字库文件,并且在软件的下面提示输出文件大小信息,如图8-24所示。
4)生成字库文件后,可以在存放字符集的地方找到生成的字库文件,也可以软件“保存”图标,重新保存到其他地方,并输入文件的名称。
2 TFT上显示字符
通过上面的方法可以生存文本文件的字库、BIN文件或其他文件格式。由于本设计中并没有外部Nor Flash芯片,而LPC1114 内部的Flash只有32KB,根本不够存放全部字库。所以,这里通过两种方式来存放字库。
把常用英文字符集的8×16点阵字库、16×32数字字库和32×64数字字库放在程序代码的数组中;把16x32的英语字符集字库和16×16的汉字字库放在SD卡中。
这里并没有使用到汉字字库,但是其显示方式和数字或英文字符的显示原理是一模一样的。而且不同点阵的字库显示也是一样的,这里就只介绍典型的字符和汉字的显示。
1. 字符显示
本函数是字符显示函数,字符集的字库数据是存放在数组AsciiLib中的。通过需要显示的字符的ASCII码计算其字符字库的存放地址,之后按照地址顺序取出字库数据,并逐点显示到TFT彩屏模块中的。由于0x20以前的都是些控制类字符,这里没有使用,提取字符字库是从0x20开始的,而且8×16的点阵占用16字节的容量,所以计算字符字库的地址公式为:
addr = AsciiLib[((*asciiCode-0x20)*16) + i]
/****************************** 程序清单8-13 **********************************/
/********************************************************************************
* FunctionName : TFTPutChar()
* Description : 在指定坐标显示一个8x16点阵的ascii字符
* EntryParameter : x-行坐标;y-列坐标;charColor-字符颜色;bkColor-背景颜色
* ReturnValue : None
********************************************************************************/
void TFTPutChar(uint16 x,uint16 y,uint8 *asciiCode,uint16 charColor,uint16 bkColor)
{
uint8 i,j;
uint8 addr = 0;
for (i=0; i<16; i++)
{
addr = AsciiLib[((*asciiCode-0x20)*16) + i]; // 获取字符数据
for (j=0; j<8; j++)
{
if ((addr >> (7-j)) & 0x01) // 显示字体
{
TFTSetPoint(x+j, y-i, charColor);
}
else
{
if (bkColor != TFT_NOCOLOR) // 显示背景
{
TFTSetPoint(x+j, y-i, bkColor);
}
}
}
}
}
2. 汉字显示
汉字的显示和英文字符的显示是一样的,只是汉字占用的存储空间比字符多一倍。计算汉字字库地址的方法比字符要复杂一些。那是因为汉字的数量比英语字符要多很多,所以存放方式就比英文字符复杂一些。
首先需要注意,汉字的字码是从0xA1A0开始的,如图8-25所示是中文字码表的前面部分字符。从表不难看出,一个汉字对应两个字节的ASCII码,并且ASCII均是大于0x80的。
其次,汉字的存放中,根据汉字的应用频繁度不同,分为多个等级和多个区域。在GB2312中把全部字符集组成了94×94的方阵,每一行称为一个“区”,编号为01~94;每一列称为一个“位”,编号为01~94,这样就得到了GB2312的区位图,用区位图的位置来表示的汉字编码,称为区位码。所以要能够正确的显示汉字就必须通过这样的原理计算出汉字的具体位置,计算出汉字字库的存放地址。由于一个16×16的汉字需要32字节的存储空间,下面就不难计算出汉字的字库的地址了,公式如:
index = (((*ptr - 0xA1)*94 + (*(ptr+1) - 0xA1))*32)
最后需要注意的是,由于本字库存放在SD卡中,所以在调用此函数之前必须先调用打开字库文件的函数。再利用ReadFont()函数读取一个汉字的字库数据到数组中,按照逐点显示的原理把汉字显示出来。
/****************************** 程序清单8-14 **********************************/
/********************************************************************************
* FunctionName : TFTPutChinese()
* Description : 在指定坐标显示一个16x16点阵的中文汉字
* EntryParameter : x - 行坐标;y - 列坐标;charColor - 字符的颜色;bkColor - 字符背景颜色
* ReturnValue : None
********************************************************************************/
void TFTPutChinese(uint16 x,uint16 y,uint8* ptr,uint16 charColor,uint16 bkColor)
{
uint8 i,k;
uint32 index;
uint8 font[32];
// 汉字的地址是从0xA1A1开始
index = (((*ptr - 0xA1)*94 + (*(ptr+1) - 0xA1))*32); // 字库
ReadFont(font, index, 32); // 读取数据
for (i=0; i<32; i++) // 一个汉字32字节
{
for (k=0; k<8; k++) // 一个字节8位
{
if ((font >> (7-k)) & 0x01)
{
TFTSetPoint(x+k,y,charColor); // 字符颜色
}
else
{
if (bkColor != TFT_NOCOLOR)
{
TFTSetPoint(x+k,y,bkColor); // 背景颜色
}
}
}
if (((i!=0)&&((i%2)) != 0)) // 奇数
{
x -= 8; // 写左半
y--;
}
else
{
x += 8; // 写右半
}
}
}
通过上面两函数的学习,读者应该不难理解点阵字符的显示原理了。只是需要注意这里的TFT的起始地址是从左下角开始,也就是说,坐标0点在左下角。当然,读者也可以更改TFT的起始坐标在其他地方,不过更改后,以上函数的x,y的计算方式约有不同。