U8glib如何显示中文

来源:互联网 发布:赛捷软件 编辑:程序博客网 时间:2024/06/14 16:29

U8glib之前并没有用过。最近为了让Marlin固件支持中文显示(需要支持图形显示的LCD,如常见的12864液晶),花时间研究了一下这个库。很强大、很好的一个库。在这里简单介绍一下如何使用U8glib显示中文或其它字体的字(包括英文或其它语言)。希望对有同样或类似需求的朋友能够提供帮助和参考。

强大的库

U8glib是非常一个非常强大的库,我体验到的强大之处有:
1、不同驱动芯片及不同分辨率的支持,这就让用户几乎不必关系底层驱动的部分,只需要写自己的程序就可以了,要知道底层驱动的调试比较费时间的;
2、不同连接方式支持,可以支持硬件SPI、软件SPI及8位并行控制方式;
3、支持Arduino、AVR及ARM等不同芯片,CPU升级时,移植代价比较小;
4、多种字体(几十种)可选,从4像素到42像素都有,不过都是最常见的ASCII码,中文等其它特殊字符需要自己定制(即使用自己的字体文件);
5、更换或定制字体还算容易,对于我来说,的确是研究了一段时间才搞明白如何添加新字体,不过一旦掌握,就很简单了;
6、支持横屏或竖屏显示;

局限性

虽然U8glib有很多优点,但也有它的局限性,至少我发现是这样的。尤其是对中文这样的无法用ASCII码覆盖的复杂字符(需要用Unicode标识)。
U8glib的局限性主要体现者对字体的处理方式上,虽然支持几十种字体,但每种字体最多只支持255个字符(0x01~0xFF),而对于中文、韩文及日文等的字符数量成千上万个,要想实现中文语句:创客实验室,可能需要切换不同的字体来实现对各个字的显示,总是切换字体确实比较麻烦,并且切换字体后,还需要重新确定显示坐标。
另一个局限也是提现在字体方面,就是U8glib字体都是0x00~0xFF的ASCII码,而中文则是Unicode,当用ASCII表示中文时,意味着不是完整的Unicode,而是发送\xab\x03\xef等之类的不易读的ASCII码(不是标准的)。所以要想实现显示一句中文,需要自己对应好正确的字体和ASCII码两个才可以正确显示一个汉字,并且每一个汉字都可能需要不同的字体和ASCII。说的有点模糊,看看下面这个例子吧。

如果你不想学这些东西,可以直接下载我整合的bdf文件:http://www.makerlab.me/guides/9/articles/82

举例

如何显示创客实验室这5个汉字呢?
要想显示这几个汉字,还真是不简单,让我们按照步骤一步步的走。注意,U8glib没有所谓的带或不带中文字库,所以带不带中文字库的显示屏都需要以下步骤(这是我的理解,如果我有错误,欢迎指正)。

第一步,确定<code>创客实验室</code>这几个汉字的Unicode码

这一部不难,有很多工具可以使用,我用的上这样网站: 转码工具 输入这5个汉字后,点击向下的箭头,就可以看到这几个字分别对应的Unicode了:

  521B  [CJK Unified Ideographs]
5BA2 [CJK Unified Ideographs]
5B9E [CJK Unified Ideographs]
9A8C [CJK Unified Ideographs]
5BA4 [CJK Unified Ideographs]

第二步,使用U8glib提供的工具,生产字体文件

U8glib为我们提供了必要的工具和文档,下载U8glib后(https://code.google.com/p/u8glib/ ,由于这个地址需要翻墙,所以没办法翻墙的朋友可以到网盘下载:http://pan.baidu.com/s/1dDfApod ,提供了多个不同版本,我使用的是Arduino版本,并且我把所有的源文件都下载了下来,因为有几个工具及文件在Arduino版本代码里面并没有,需要单独下载),可能需要另外下载的工具上 bdf2u8g(.exe)【用来把字体文档bdf转化为字体数据的】,Unicode.bdf(则是完整的Unicode字体文件,比较大,在U8glib源码中可以下载到Unicode.bdf 9.8M大小),都下载完成后,放入同一个文件夹,来转换字体,命令如下(主要windows版本需要加.exe,linux系统不需要):
linux系统命令是:./bdf2u8g -b 0 -e 255 -l 156 -u 157 unifont.bdf chinese_test chinese_test.c
windows系统命令是:bdf2u8g.exe -b 0 -e 255 -l 156 -u 157 unifont.bdf chinese_test chinese_test.c
等等,这都是什么意思?
bdf2u8g命令的参数说明:
必须的参数:
bdf文件,这是你需要转换的字体文件,bdf格式;
字体名称,用于生产代码数据的标识;
.c文件,c语言文件;
可选参数:
[-b 数字] ASCII码的起始位,范围是0~255;
[-e 数字] ASCII码的结束位,范围是0~255;
[-l page] 用于定位超出0~255范围的Unicode的页数,如果ASCII码范围是0~127,则使用这个参数,如果范围在128~255,则使用下面的-u参数;
[-u page] 用于定位超出0~255范围的Unicode的页数,如果ASCII码范围是128~255,则使用这个参数,如果范围在0~127,则使用上面的-l参数;
创 521B计算页地址为:0x521B/0x80 = 0xA4 = 164,由于1B=27 < 7F,所以使用-l参数即可,命令为:./bdf2u8g -b 27 -e 27 -l 164 unifont.bdf chinese_test chinese_test.c执行命令后,会输出:

encoding range 27..27
bbx 14 16 0 -2 encoding 27
input file '../bdf/unifont.bdf'
u8g font name 'chinese_test'
output file 'chinese_test.c'

这时打开生产的c代码文件内容如下:

#include "u8g.h"
const u8g_fntpgm_uint8_t chinese_test[55] U8G_FONT_SECTION("chinese_test") = {
0,16,16,0,254,0,0,0,0,0,27,27,0,14,254,0,
0,14,16,32,16,0,254,8,4,8,4,20,4,18,36,33,
36,64,164,190,36,34,36,34,36,34,36,42,36,36,36,32,
132,32,132,31,148,0,8};

需要注意的是,如果在Arduino IDE下使用,需要调整为:

#include "utility/u8g.h"
const u8g_fntpgm_uint8_t chinese_test[55] U8G_SECTION(".progmem.chinese_test") = {
0,16,16,0,254,0,0,0,0,0,27,27,0,14,254,0,
0,14,16,32,16,0,254,8,4,8,4,20,4,18,36,33,
36,64,164,190,36,34,36,34,36,34,36,42,36,36,36,32,
132,32,132,31,148,0,8};

前面的include部分是必须改的,U8G_SECTION(".progmem.chinese_test")这个部分可能不同版本需要不同的写法,我用的版本必须改为下面的,否则会有错误。
完整的Arduino代码(显示一个字):

#include "U8glib.h"
#include "utility/u8g.h"
const u8g_fntpgm_uint8_t chinese_test[55] U8G_SECTION(".progmem.chinese_test") = {
0,16,16,0,254,0,0,0,0,0,27,27,0,14,254,0,
0,14,16,32,16,0,254,8,4,8,4,20,4,18,36,33,
36,64,164,190,36,34,36,34,36,34,36,42,36,36,36,32,
132,32,132,31,148,0,8};

U8GLIB_MINI12864 u8g(45,47);

void draw(void) {
// graphic commands to redraw the complete screen should be placed here
u8g.setFont(chinese_test);
//u8g.setFont(u8g_font_osb21);
u8g.drawStr( 0, 22, "\x1b");
}

void setup(void) {

// flip screen, if required
// u8g.setRot180();

// set SPI backup if required
//u8g.setHardwareBackup(u8g_backup_avr_spi);

// assign default color value
if ( u8g.getMode() == U8G_MODE_R3G3B2 )
u8g.setColorIndex(255); // white
else if ( u8g.getMode() == U8G_MODE_GRAY2BIT )
u8g.setColorIndex(3); // max intensity
else if ( u8g.getMode() == U8G_MODE_BW )
u8g.setColorIndex(1); // pixel on
}

void loop(void) {
// picture loop
u8g.firstPage();
do {
draw();
} while( u8g.nextPage() );

// rebuild the picture after some delay
delay(500);
}

那么如何显示创客实验室5个汉字呢?你可能注意到了。这5个汉字并没有在unicode的同一页,也就是如果你想节省flash空间,降低字体数据大小的话,需要每个字生产一个字体,并且每个字切换一下字体(严格来说不是字体了,而是字数据),其它几个字的生产代码分别是:
客 5BA2生产代码:./bdf2u8g -b 162 -e 162 -u 183 unifont.bdf chinese_ke chinese_ke.c
实 ‎5B9E生产代码:./bdf2u8g -b 158 -e 158 -u 183 unifont.bdf chinese_shi chinese_shi.c
验 ‎9A8C生产代码:./bdf2u8g -b 140 -e 140 -u 132 unifont.bdf chinese_yan chinese_yan.c
室 ‎5BA4生产代码:./bdf2u8g -b 164 -e 164 -l 183 unifont.bdf chinese_shi2 chinese_shi2.c

其中有几个字,都在5B00~5BFF范围内,可以生产在一个文档中,不过夹杂的一些不相关字会占用flash空间。
数据都生产完成了,但每个字都需要切换一次字体,真的让人受不了,有没有解决办法呢?答案是有的,我经过很多测试和对比,发现如果直接将字体数据进行合并,会导致显示不正常,为了克服这个问题,需要对单独生产的数据进行调整,调整后的创客实验室5个字的数据为:

const u8g_fntpgm_uint8_t chinese_test[] U8G_SECTION(".progmem.chinese_test") = {
0,16,16,0,254,0,0,0,0,0,161,165,0,14,254,0,/\*<b>161,165</b>161165A1A5 \*/
//Chinese "创"
0,14,16,32,16,0,254,8,4,8,4,20,4,18,36,33,
36,64,164,190,36,34,36,34,36,34,36,42,36,36,36,32,
132,32,132,31,148,0,/\*8, \*/
//Chinese "客"
0,15,16,32,16,0,254,2,0,1,0,127,254,64,2,136,
4,15,240,16,32,44,64,3,128,28,112,224,14,31,240,16,
16,16,16,31,240,16,/\*16\*/
//Chinese "实"
0,15,16,32,16,0,254,2,0,1,0,127,254,64,2,136,
132,4,128,4,128,16,128,8,128,8,128,255,254,1,64,2,
32,4,16,24,8,96,/\*4\*/
//Chinese "验"
0,15,16,32,16,0,254,0,32,248,32,8,80,72,80,72,
136,73,4,74,250,124,0,4,68,4,36,29,36,228,168,68,
136,4,16,43,254,16,/\*0\*/
//Chinese "室"
0,15,15,30,16,0,255,2,0,1,0,127,254,64,2,128,
4,63,248,4,0,8,32,31,240,1,16,1,0,63,248,1,
0,1,0,255,254
};

要想显示这5个字,只需要将之前提到的arduino代码中的显示代码改为u8g.drawStr( 0, 28, "\xa1\xa2\xa3\xa4\xa5");就可以显示了,如图:

可以看到,中文可以显示了,但字体是Unicode.bdf文件中标准的字体,16X16像素,如果想显示个性字体,请参考下一部分

转自:http://www.makerlab.me/guides/9/articles/51

0 0
原创粉丝点击