[牛人杂谈]

单片机字库存储

[复制链接]
2202|27
手机看帖
扫描二维码
随时随地手机跟帖
yiyigirl2014|  楼主 | 2016-10-31 22:58 | 显示全部楼层 |阅读模式

1.导言

和单片机搭配的显示器,有12864、TFT、OLED等。在有些系统中,我们需要显示汉字,可以购买汉字芯片,或者购买带汉字显示的显示器,当然,也可以自己做字库。

这里我们介绍一种自己做字库的方法,成本2元*币左右。

2.汉字显示原理

看原理需要知道什么是像素:像素是液晶屏的最小单位,看你的手机屏幕或者电脑屏幕,他们实际上是由一个一个的正方形组成的,如果你的电脑或手机屏幕分辨率太高,不容易看到,需要借助放大镜,分辨率低的话,仔细一看就看见了,都是由一个一个的正方形组成的,这里面的一个正方形,就是1个像素。例如,12864屏幕就是128像素*64像素的屏幕,即横着有12864个正方形,竖着有64个正方形。

12864%E6%94%BE%E5%A4%A7.jpg

上图是12864屏幕的一角,请你仔细看看,是不是一个一个的正方形组成?

比128*64大的分辨率是320*240,还有800*600,1024*768,1280*720等,总之,分辨率越大,人的肉眼就越但不见它是由一个一个小正方形组成的。所以现在的手机屏幕是越来越高,当你用惯一个分辨率极高的手机,再去用你原来分辨率极低的手机,你就会发现原来的那个手机真是很模糊!

讲完了像素的概念,下面开始讲汉字显示的原理:

现在流行的汉字字库有两种,一种是GB2312、一种是GBK。这是两种不同的编码约定。

  • GB2312有六千多个汉字,是一些常用的汉字
  • GBK有2万多个汉字,包含所有的GB2312汉字,包含整个中国的汉字

假如我们想在液晶显示器上显示一个16*16像素大小的汉字“瑞”,怎么办呢?先看一下“瑞”字在液晶显示器上被放大的效果:

rui.jpg

上面的这个瑞即是16*16像素大小的字体,你可以数一下上面的像素点。你可以看一下,在上面“亮”的地方用“写点函数”写成和其它点不同的颜色,不就可以了吗!按照这个思想,我们就需要采用一种有效的办法了。从上面图像的右上角开始扫描,每行有16个点,即可以用两个字节来表示,“暗”的地方用0表示,亮的地方用1表示,那么第一行就可以写成十六进制的00 20,以此类推,可以得出第二行,第三行的字节码,如此一来,一个汉字就需要32个字节来表示。搞好了汉字的这些码,在程序中给TFT开个16*16大小的区域,然后开始扫描这些字节,遇到0,写背景色,遇到1,写定义的颜色。汉字显示就是如此了。

3.为什么显示英文一般不用字库芯片?

英文的单词都是由26个字母构成了,加上大小写的区别和一些字符,也不过才95个。假如要显示8*16像素大小的字符,每一个字符需要16个字节的字库空间,95个字符即是95*16=570个字节。即占用570个字节的RAM。对于LPC1114的8K字节RAM来说,搓搓有余了。

4.为什么显示中文需要字库芯片?

显示中文的话,必须需要每一个字的字模,16*16像素大小的中文,每一个中文都要32个字节。GBK收录了中文两万多个,如果要都能显示,需要700多K字节的空间。

所以,我们选择了把这些字库放在外部存储器当中,我们选择了2M的FLASH存储芯片W25Q16做为存储媒介。放个700多K的字库足够了,如果你愿意,同时放两种字体的字库都没问题。


yiyigirl2014|  楼主 | 2016-10-31 22:59 | 显示全部楼层

5.如何把GBK字库做成字模?(此部分做字模参考**论坛一帖子,非瑞生原创,特此感谢分享者)

5.1需要准备的文件和软件

  • 取模软件
  • GBK字库
  • 二进制文件生成工具

点此下载:GBK字库制作软件和文件

5.2开始制作

%E5%8F%96%E6%A8%A1%E8%BD%AF%E4%BB%B6.jpg

在工具栏处点“打开”按钮,打开gbk_ziku.txt文件,然后根据自己的需要,设置想要的取模方式,然后点工具栏上的“输出”按钮 并等待其完成,完成后会在取模软件所在路径生成了一个temp.txt文件,修改这个文件名,比如现在我是按照“宋体、点阵数为16、字重为4、取模为为16*16、对齐设置为左上、方向设置为横向取模,高位在左”的方式来取的字模,也就是我平时TFT常用的一种字模,改文件名为st16x16.txt 。

为了生成的方便,我们在D盘根目录下新建一个文件夹,名称就叫ziku吧,然后,把ziku.exe 和 st16x16.txt复制一份到这个文件夹里。

打开自己计算机的命令窗口:“开始”->“运行”->“cmd”,如下图所示:

%E5%91%BD%E4%BB%A41.jpg

然后用cd命令进入到我们刚刚建的ziku文件夹下,输入命令如下图所示:

%E5%91%BD%E4%BB%A42.jpg

输入命令,生成字库文件,如下图所示:

%E5%91%BD%E4%BB%A43.jpg

回车,然后程序会在ziku文件夹下生成一个名称固定为ziku.bin的字库文件

%E5%91%BD%E4%BB%A44.jpg

为了区分,把这个字库文件修改名称为st16x16.bin 。

到此,字库已经制作完成。

6.如何把做好的GBK字库字模存储到W25Q16中?

硬件:电脑串口—单片机—W25Q16

程序:单片机与电脑采用串口连接,单片机与W25Q16采用SPI方式连接。所以,我们只需要给单片机写一个接收串口数据再把数据通过SPI口传输到W25Q16中的程序即可。


使用特权

评论回复
yiyigirl2014|  楼主 | 2016-10-31 23:00 | 显示全部楼层

7.单片机如何读取W25Q16中的字模并显示在液晶屏上?

假设我们的GBK字模是从W25Q16地址中的0x100开始存储的,那么,从0x100地址开始,单片机读取32个字节,就是GBK字库的第一个字“丂”的字模,再读32个字节,就是GBK字库第二个字“丄”的字模。(有人会问,你是怎么知道GBK字库第几个字是什么的?答:你把上文中5.1节提到的文件下载后,打开GBK字库,就看见了。)根据上文中第2步讲的原理,字模中,遇到0就给LCD的1个像素画一个颜色,遇到1就给LCD的下一个像素画不同的颜色,把32个字节都捋一遍,一个汉字就显示在LCD上了。

如果我们想要显示汉字“瑞”,我们该从W25Q16中的哪个字节开始提取它的字模呢?这时候,就需要知道字符存储编码的原理了。

字符编码原理:英文字母带各种符号等共有95个,都有自己的ascii码,一个字母或者符号就是一个ascii码。汉字以及汉字的符号是需要2个字节来存储,在keil等主流编译器中,一般都是以GBK编码方式存储。

GBK编码:每个GBK码由2个字节组成,第一个字节为0X81~0XFE,第二个字节分为两部分,一是0X40~0X7E,二是0X80~0XFE。例如汉字“瑞”的GBK编码为C8 F0,第一字节C8,位于0X81~0XFE之间,第二字节F0,位于0X40~0XFE之间。第一个字节代表的意义称为区,那么GBK里面总共有126个区(0XFE-0X81+1=126);第二个字节代表的意义就是每个区内有多少个汉字,算了一下,一共有190个(0XFE-0X80+0X7E-0X40+2=190)。那么,GBK一共存储了126X190=23940个汉字。

我们仔细看GBK编码第二个字节两部分,0X40~0X7E 0X80~0XFE,也就是说它是从0X40~到0XFF,中间的0x7F和最后的0xFF没有用到。但是为了能够线性查找,我们暂且认为这两个字节也存在,就是我们强制把每个区190个汉字当做每个区192个汉字,不过0X7F和0XFF上没有汉字。

定义GBKH代表第一个字节,GBKL代表第二个字节,字库的偏移量offset,放入W25Q16的字库从0x100地址开始存储,那么获取某个汉字的字模的函数就可以写成:

void Get_GBK_DZK(uint8_t *code, uint8_t *dz_data)
{
    uint8_t GBKH,GBKL;                 
    uint32_t offset;        

    GBKH=*code;
    GBKL=*(code+1);     
    if(GBKH>0XFE||GBKH<0X81)return;
    GBKH-=0x81;
    GBKL-=0x40;
    offset=((uint32_t)192*GBKH+GBKL)*32;
    W25Q16_Read(dz_data,offset+0x100,32);           
    return;
}

函数中,参数*code带入汉字的两字节编码,*dz_data是一个32个字节的数据,带入函数中,就可以得到任何一个汉字的字模了。例如:

 uint8_t buf[32];
    Get_GBK_DZK("瑞", buf);


使用特权

评论回复
gejigeji521| | 2016-10-31 23:56 | 显示全部楼层
GB2312有六千多个汉字,是一些常用的汉字GBK有2万多个汉字,包含所有的GB2312汉字,包含整个中国的汉字

使用特权

评论回复
yiyigirl2014|  楼主 | 2016-11-9 23:06 | 显示全部楼层
高级的系统级都是用字库文件来存蚊子的。

使用特权

评论回复
dongnanxibei| | 2016-11-9 23:38 | 显示全部楼层
在好多库函数里都会提供一些字库文件的,包括不同分辨率的。

使用特权

评论回复
稳稳の幸福| | 2016-11-9 23:42 | 显示全部楼层
分辨率越大,字库文件越大,加载时候就会慢一点。

使用特权

评论回复
mintspring| | 2016-11-10 19:05 | 显示全部楼层
如果纯粹空间够,来个解码电脑上哪字体文件的程序就更OK了。

使用特权

评论回复
slotg| | 2016-11-10 23:49 | 显示全部楼层
感谢分享

使用特权

评论回复
zhuotuzi| | 2016-11-11 19:58 | 显示全部楼层
字库文件就是把点阵字存储到一个文件里,用时候调用就行了。

使用特权

评论回复
598330983| | 2017-2-24 19:04 | 显示全部楼层
yiyigirl2014 发表于 2016-10-31 23:00
7.单片机如何读取W25Q16中的字模并显示在液晶屏上?假设我们的GBK字模是从W25Q16地址中的0x100开始存储的, ...

代码中最后的那个return;返回了什么呢?

使用特权

评论回复
734774645| | 2017-2-24 19:23 | 显示全部楼层
现在看懂了,原来是通过指针来读取出来到buf的,然后推送buf到显示器。

使用特权

评论回复
yiyigirl2014|  楼主 | 2017-2-24 20:23 | 显示全部楼层
显示中文的话,必须需要每一个字的字模,16*16像素大小的中文,每一个中文都要32个字节。GBK收录了中文两万多个,如果要都能显示,需要700多K字节的空间。
32个字节=(每行16BIT,就是2个8BIT,就是2个字节)*16行=32个字节


使用特权

评论回复
yiyigirl2014|  楼主 | 2017-2-24 20:23 | 显示全部楼层
也就是如果底层函数取字形的时候要执行32次基础指令才能取出来一个字。

使用特权

评论回复
huangcunxiake| | 2017-2-24 22:26 | 显示全部楼层
现在流行的汉字字库有两种,一种是GB2312、一种是GBK。这是两种不同的编码约定。

使用特权

评论回复
zhuotuzi| | 2017-2-25 00:04 | 显示全部楼层
以前仅仅是照搬,没想过这么深入的问题,原来是这么个实现过程。

使用特权

评论回复
zhuomuniao110| | 2017-2-25 13:02 | 显示全部楼层
存储英文的其实也就1K的空间就够了,因此好多单片机应用时候直接定义成code类型就可以了,自动放到flash

使用特权

评论回复
zhuomuniao110| | 2017-2-25 13:10 | 显示全部楼层
主要知道存储在外置SPI芯片里的字库文件在什么位置存放。而且这个存放的编码顺序是跟标准字库一致的。

使用特权

评论回复
稳稳の幸福| | 2017-2-25 13:50 | 显示全部楼层
通过指针读取非常好理解。

使用特权

评论回复
玛尼玛尼哄| | 2017-2-25 16:20 | 显示全部楼层
所有的操作都隐藏在基础函数之下

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

199

主题

3442

帖子

10

粉丝