Chinaunix首页 | 论坛 | 博客
  • 博客访问: 133479
  • 博文数量: 55
  • 博客积分: 1870
  • 博客等级: 上尉
  • 技术积分: 540
  • 用 户 组: 普通用户
  • 注册时间: 2008-03-21 20:51
文章分类

全部博文(55)

文章存档

2011年(27)

2009年(3)

2008年(25)

我的朋友

分类: C/C++

2011-05-04 14:07:19

【FPGA黑金开发板】NIOSII那些事儿--LCD中英文字符显示(二十三)

声明:本文转载于http://www.cnblogs.com/kingst,版权归黑金动力社区(http://www.heijin.org)所有。

3

      这一节,我们在上一节的基础上,来研究英文变宽字体以及中文的字体显示的解决方案。

      在LCD上显示字符,不管是英文还是中文,都需要有字库支持。在有些LCD模块中,已经将字库文件烧写到了芯片当中,这样的字库有优点也有缺点。优点是操作简单,而缺点就是不灵活,显示的效果不够好,而且性价比也不高。FPGA黑金开发板选用的COG液晶是本身不带字库文件的液晶,我们在这里将研究一种通用的中英文字符显示方法,让大家充分了解如何利用外部字库文件实现字符显示,让我们的液晶显示更漂亮的字体。

      英文字库

      我们首先来研究英文字库的结构。英文字库使用的是ASCII码,起码值是0到127,其寻址公式为:

英文点阵数据在英文点阵字库中的偏移 = 英文的ASCII码 * 一个英文字模占用的字节数

我们使用的字库是tahoma字体,高度为16位,而字体的宽度是变宽的。在下表的tahoma_font_offset[]中,注释部分与偏移量是一一对应的,比如!,它的地址偏移量为7,它的宽度为11-7=4个,也就是说

字符宽度 = 它的下一个字符的偏移量 - 它本身的偏移量

01#ifndef TAHOMA_H_
02#define TAHOMA_H_
03//字符的相对偏移量
04unsigned int  tahoma_font_offset[]={
05          //    !   "   #   $   %   &  '    (
06        0  ,3  ,7  ,11 ,19 ,25 ,36 ,43 ,45 ,49 ,
07     // )   *   +   ,   -   .   /   0   1   2
08        53 ,59 ,67 ,71 ,75 ,79 ,83 ,89 ,95 ,101,
09     // 3   4   5   6   7   8   9   :   ;   <
10        107,113,119,125,131,137,143,147,152,159,
11     // =   >   ?   @   A   B   C   D   E   F
12        168,175,180,190,197,203,210,217,223,229,
13     // G   H   I   J   K   L   M   N   O   P
14        236,243,247,252,258,263,271,278,286,292,
15     // Q   R   S   T   U   V   W   X   Y   Z
16        300,307,313,319,326,332,342,348,354,360,
17     // [   \   ]   ^   _   `   a   b   c   d
18        364,368,372,380,387,392,398,404,409,415,
19     // e   f   g   h   i   j   k   l   m   n
20        421,425,431,437,439,442,447,449,457,463,
21     // o   p   q   r   s   t   u   v   w   x
22        469,475,481,485,490,494,500,506,514,520,
23     // y   z   {   |   }   ~
24        526,531,536,540,545,553
25};
26 
27const char  font_tahoma_8[]={
280x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0B,0xF0,0x00,0x00,0x00,0x00,0x00,0x38,
290x00,0x00,0x00,0x38,0x00,0x00,0x02,0x00,0x0E,0x40,0x03,0xC0,0x0E,0x70,0x03,0xC0,
300x02,0x70,0x00,0x40,0x00,0x00,0x08,0xC0,0x09,0x20,0x3F,0xF8,0x09,0x20,0x06,0x20,
310x00,0x00,0x00,0x60,0x00,0x90,0x00,0x90,0x0C,0x60,0x03,0x00,0x00,0xC0,0x06,0x30,
320x09,0x00,0x09,0x00,0x06,0x00,0x00,0x00,0x07,0x60,0x08,0x90,0x08,0x90,0x09,0x60,
330x06,0x00,0x05,0x80,0x08,0x00,0x00,0x38,0x00,0x00,0x07,0xC0,0x18,0x30,0x20,0x08,
340x00,0x00,0x20,0x08,0x18,0x30,0x07,0xC0,0x00,0x00,0x02,0x80,0x01,0x00,0x07,0xC0,
350x01,0x00,0x02,0x80,0x00,0x00,0x01,0x00,0x01,0x00,0x01,0x00,0x0F,0xE0,0x01,0x00,
360x01,0x00,0x01,0x00,0x00,0x00,0x20,0x00,0x1C,0x00,0x00,0x00,0x00,0x00,0x01,0x00,
370x01,0x00,0x01,0x00,0x00,0x00,0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x38,0x00,
380x07,0xC0,0x00,0x38,0x00,0x00,0x07,0xE0,0x08,0x10,0x08,0x10,0x08,0x10,0x07,0xE0,
390x00,0x00,0x00,0x00,0x08,0x20,0x0F,0xF0,0x08,0x00,0x00,0x00,0x00,0x00,0x0C,0x20,
400x0A,0x10,0x09,0x10,0x08,0x90,0x08,0x60,0x00,0x00,0x04,0x20,0x08,0x10,0x08,0x90,
410x08,0x90,0x07,0x60,0x00,0x00,0x01,0x80,0x01,0x40,0x01,0x20,0x0F,0xF0,0x01,0x00,
420x00,0x00,0x04,0xF0,0x08,0x90,0x08,0x90,0x08,0x90,0x07,0x10,0x00,0x00,0x07,0xC0,
430x08,0xA0,0x08,0x90,0x08,0x90,0x07,0x00,0x00,0x00,0x00,0x10,0x0C,0x10,0x03,0x10,
440x00,0xD0,0x00,0x30,0x00,0x00,0x07,0x60,0x08,0x90,0x08,0x90,0x08,0x90,0x07,0x60,
450x00,0x00,0x00,0xE0,0x09,0x10,0x09,0x10,0x05,0x10,0x03,0xE0,0x00,0x00,0x00,0x00,
460x0C,0xC0,0x00,0x00,0x00,0x00,0x20,0x00,0x1C,0xC0,0x00,0x00,0x00,0x00,0x00,0x00,
470x01,0x00,0x02,0x80,0x02,0x80,0x04,0x40,0x04,0x40,0x08,0x20,0x00,0x00,0x02,0x80,
480x02,0x80,0x02,0x80,0x02,0x80,0x02,0x80,0x02,0x80,0x02,0x80,0x00,0x00,0x00,0x00,
490x08,0x20,0x04,0x40,0x04,0x40,0x02,0x80,0x02,0x80,0x01,0x00,0x00,0x00,0x00,0x10,
500x0B,0x10,0x00,0x90,0x00,0x60,0x00,0x00,0x07,0xC0,0x08,0x20,0x13,0x90,0x14,0x50,
510x14,0x50,0x17,0xD0,0x04,0x10,0x04,0x20,0x03,0xC0,0x00,0x00,0x0E,0x00,0x03,0xC0,
520x02,0x30,0x02,0x30,0x03,0xC0,0x0E,0x00,0x00,0x00,0x0F,0xF0,0x08,0x90,0x08,0x90,
530x08,0x90,0x07,0x60,0x00,0x00,0x03,0xC0,0x04,0x20,0x08,0x10,0x08,0x10,0x08,0x10,
540x08,0x10,0x00,0x00,0x0F,0xF0,0x08,0x10,0x08,0x10,0x08,0x10,0x04,0x20,0x03,0xC0,
550x00,0x00,0x0F,0xF0,0x08,0x90,0x08,0x90,0x08,0x90,0x08,0x10,0x00,0x00,0x0F,0xF0,
560x00,0x90,0x00,0x90,0x00,0x90,0x00,0x90,0x00,0x00,0x03,0xC0,0x04,0x20,0x08,0x10,
570x09,0x10,0x09,0x10,0x0F,0x10,0x00,0x00,0x0F,0xF0,0x00,0x80,0x00,0x80,0x00,0x80,
580x00,0x80,0x0F,0xF0,0x00,0x00,0x08,0x10,0x0F,0xF0,0x08,0x10,0x00,0x00,0x08,0x00,
590x08,0x10,0x08,0x10,0x07,0xF0,0x00,0x00,0x0F,0xF0,0x01,0x80,0x02,0x40,0x04,0x20,
600x08,0x10,0x00,0x00,0x0F,0xF0,0x08,0x00,0x08,0x00,0x08,0x00,0x00,0x00,0x0F,0xF0,
610x00,0x30,0x00,0xC0,0x03,0x00,0x00,0xC0,0x00,0x30,0x0F,0xF0,0x00,0x00,0x0F,0xF0,
620x00,0x30,0x00,0xC0,0x03,0x00,0x0C,0x00,0x0F,0xF0,0x00,0x00,0x03,0xC0,0x04,0x20,
630x08,0x10,0x08,0x10,0x08,0x10,0x04,0x20,0x03,0xC0,0x00,0x00,0x0F,0xF0,0x01,0x10,
640x01,0x10,0x01,0x10,0x00,0xE0,0x00,0x00,0x03,0xC0,0x04,0x20,0x08,0x10,0x08,0x10,
650x18,0x10,0x24,0x20,0x23,0xC0,0x00,0x00,0x0F,0xF0,0x01,0x10,0x01,0x10,0x03,0x10,
660x04,0xE0,0x08,0x00,0x00,0x00,0x08,0x60,0x08,0x90,0x08,0x90,0x08,0x90,0x07,0x10,
670x00,0x00,0x00,0x10,0x00,0x10,0x0F,0xF0,0x00,0x10,0x00,0x10,0x00,0x00,0x07,0xF0,
680x08,0x00,0x08,0x00,0x08,0x00,0x08,0x00,0x07,0xF0,0x00,0x00,0x00,0x70,0x03,0x80,
690x0C,0x00,0x03,0x80,0x00,0x70,0x00,0x00,0x00,0x70,0x03,0x80,0x0C,0x00,0x03,0x80,
700x00,0x70,0x03,0x80,0x0C,0x00,0x03,0x80,0x00,0x70,0x00,0x00,0x0C,0x30,0x02,0x40,
710x01,0x80,0x02,0x40,0x0C,0x30,0x00,0x00,0x00,0x30,0x00,0xC0,0x0F,0x00,0x00,0xC0,
720x00,0x30,0x00,0x00,0x0C,0x10,0x0A,0x10,0x09,0x90,0x08,0x50,0x08,0x30,0x00,0x00,
730x3F,0xF8,0x20,0x08,0x20,0x08,0x00,0x00,0x00,0x38,0x07,0xC0,0x38,0x00,0x00,0x00,
740x20,0x08,0x20,0x08,0x3F,0xF8,0x00,0x00,0x00,0x80,0x00,0x40,0x00,0x20,0x00,0x10,
750x00,0x20,0x00,0x40,0x00,0x80,0x00,0x00,0x20,0x00,0x20,0x00,0x20,0x00,0x20,0x00,
760x20,0x00,0x20,0x00,0x00,0x00,0x00,0x08,0x00,0x10,0x00,0x00,0x00,0x00,0x00,0x00,
770x06,0x00,0x09,0x40,0x09,0x40,0x09,0x40,0x0F,0x80,0x00,0x00,0x0F,0xF8,0x08,0x40,
780x08,0x40,0x08,0x40,0x07,0x80,0x00,0x00,0x07,0x80,0x08,0x40,0x08,0x40,0x08,0x40,
790x00,0x00,0x07,0x80,0x08,0x40,0x08,0x40,0x08,0x40,0x0F,0xF8,0x00,0x00,0x07,0x80,
800x09,0x40,0x09,0x40,0x09,0x40,0x05,0x80,0x00,0x00,0x0F,0xF0,0x00,0x48,0x00,0x48,
810x00,0x00,0x07,0x80,0x28,0x40,0x28,0x40,0x28,0x40,0x1F,0xC0,0x00,0x00,0x0F,0xF8,
820x00,0x40,0x00,0x40,0x00,0x40,0x0F,0x80,0x00,0x00,0x0F,0xD0,0x00,0x00,0x20,0x40,
830x1F,0xD0,0x00,0x00,0x0F,0xF8,0x01,0x00,0x02,0x80,0x04,0x40,0x08,0x00,0x0F,0xF8,
840x00,0x00,0x0F,0xC0,0x00,0x40,0x00,0x40,0x0F,0x80,0x00,0x40,0x00,0x40,0x0F,0x80,
850x00,0x00,0x0F,0xC0,0x00,0x40,0x00,0x40,0x00,0x40,0x0F,0x80,0x00,0x00,0x07,0x80,
860x08,0x40,0x08,0x40,0x08,0x40,0x07,0x80,0x00,0x00,0x3F,0xC0,0x08,0x40,0x08,0x40,
870x08,0x40,0x07,0x80,0x00,0x00,0x07,0x80,0x08,0x40,0x08,0x40,0x08,0x40,0x3F,0xC0,
880x00,0x00,0x0F,0xC0,0x00,0x80,0x00,0x40,0x00,0x00,0x09,0x80,0x09,0x40,0x0A,0x40,
890x06,0x40,0x00,0x00,0x07,0xF0,0x08,0x40,0x08,0x40,0x00,0x00,0x07,0xC0,0x08,0x00,
900x08,0x00,0x08,0x00,0x0F,0xC0,0x00,0x00,0x00,0xC0,0x03,0x00,0x0C,0x00,0x03,0x00,
910x00,0xC0,0x00,0x00,0x03,0xC0,0x0C,0x00,0x03,0x00,0x00,0xC0,0x03,0x00,0x0C,0x00,
920x03,0xC0,0x00,0x00,0x08,0x40,0x04,0x80,0x03,0x00,0x04,0x80,0x08,0x40,0x00,0x00,
930x00,0xC0,0x33,0x00,0x0C,0x00,0x03,0x00,0x00,0xC0,0x00,0x00,0x0C,0x40,0x0A,0x40,
940x09,0x40,0x08,0xC0,0x00,0x00,0x01,0x00,0x01,0x00,0x1E,0xF0,0x20,0x08,0x00,0x00,
950x00,0x00,0x3F,0xF8,0x00,0x00,0x00,0x00,0x20,0x08,0x1E,0xF0,0x01,0x00,0x01,0x00,
960x00,0x00,0x03,0x00,0x00,0x80,0x00,0x80,0x01,0x00,0x02,0x00,0x02,0x00,0x01,0x80,
970x00,0x00};
98 
99#endif /*TAHOMA_H_*/
      中文字库

      相对于英文字库,中文字库就要复杂一些,为了让大家更明白,我们先了解一下汉字点阵字库的原理。

  • 汉字编码

      区位码在孤寂GD2312-80中规定,所有的国际汉字及符号分配在一个94行、94列的方阵中,方阵的每一行称为一个“区”,编号为01区到94区,每一列为一个“位”,比那好为01位到94位,方阵中的每一个汉字和符号所在的区号和位号组成在一起形成的四个阿拉伯数字就是他们的“区位码”。区位码的前两位是他的区号,后两位是它的位号。用区位码就可以唯一的确定一个汉字或字符,反过来说,任何一个汉字或字符也都对应着一个唯一的区位码。例如,汉字“母”字的区位码是3624,表明它在方阵的36区24位,问好“?”的区位码为0331,则它在03区31位。

  • 机内码

      汉字的机内码是指在计算机中表示一个汉字的编码。机内码与区位码稍有区别。如上所述,汉字区位码的区码和位码的取值均在1-94之间,如直接用区位码作为机内码,就会与基本的ASCII码混淆。为了避免机内码与基本ASCII码的冲突,需要避开基本ASCII码中的控制码(00H-1FH),还需要与基本ASCII码中的字符相区别。为了实现这两点,可以先在区码和位码分别加上20H,在此基础上再加80H(此处“H”表示前两位数字为十六进制)。经过这些处理,用机内码表示一个汉字需要占两个字节,分别称为高位字节和地位字节,这两位字节的机内码按如下规则表示:高位字节 = 区码 + 20H +80H(或区码+A0H)低位码=位码+20H+80H(或位码+A0H)由于汉字的区码与位码的取值范围的十六进制数均为01H-5EH(即十进制的01-94),所以汉字的高位字节与低位字节的取值范围则为A1H-FEH(即十进制的161-254)。例如,汉字“啊”的区位码为1601,区码和位码分别用十六进制表示即为1001H,它的机内码的高位字节为B0H,低位字节为A1H,机内码就是B0A1H。

      有了上面的基础后,我们来看看我们点阵字库的结构。

      点阵字库存储在汉字的点阵字库中,每个字节的每个位代表一个汉字的一个点,每个汉字都是由一个矩形的点阵组成,0代表没有,1代表有点,将0和1用不同的颜色画出,就形成了汉字,常用的点阵矩阵有12*12,14*14,16*16三种字库。我们常用的字库文件来自UCDOC中,DOC前辈们经过将制作好的字模放到一个个标准的苦衷,这就是点阵字库文件。一般我们使用的是16*16的点阵宋体字库,所谓16*16,是每一个汉字在纵、横各16点的区域内显示的。现在又有了HZK12,HZK24,HZK32和HZK48字库及黑体、楷体和隶书字库。虽然汉字库种类繁多,但都是按照区位的顺序排列的。前一个字节为该汉字的区号,后一个字节为该字的位号。每一个区记录94个汉字,位号则为该字在该区中的位置。因此,汉字在汉字库中的具体位置采用机内码的计算公式为:

94*(区号-0XA0-1)+(位号-0XA0-1)

      减1是因为数组是以0开始而区号位号是以1开始的。这仅为汉字为单位该汉字在汉字库中的位置,如果想得到以字节为单位,该汉字所在汉字库中的位置,那么只需要乘以一个汉字字模占用的字节数即可,即:

(94*(区号-0XA1)+(位号-0XA1))* 一个汉字字模占用字节数

      正常来说,一个汉字字模占用的字节数为横纵点数/8,以16*16点阵为例,它的一个汉字字模占用的字节数就为16*16/8=32。不过也有例外,在下面将会有所提及。

我们所使用的字库是HZK12,它是12*12的点阵字库,字库设计者为了使用方便,字模每一行的位数均补齐为8的整数倍,有的设计者也将列补齐为8的整数倍。我们使用的HZK12即为这种,于是实际该字库的为长度是16*16,多余的4为都是0(不显示),在显示效果上不受影响。

      下面,我们就来研究一下程序是如何实现的。

      首先,我们在工程目录中inc下建立gui.h文件,内容如下表所示

01/*
02 * =================================================================
03 *       Filename:  gui.h
04 *   Description: 
05 *        Version:  1.0.0
06 *        Created:  2010.4.16
07 *       Revision:  none
08 *       Compiler:  Nios II 9.0 IDE
09 *         Author:   (AVIC)
10 *          Email:  avic633@gmail.com 
11 * =================================================================
12 */
13#ifndef GUI_H_
14#define GUI_H_
15 
16typedef struct{
17        unsigned char x;
18        unsigned char y;
19        unsigned char * matrix;    
20        unsigned char wide;
21        unsigned char reverse;
22}X_16_T;
23 
24typedef struct{
25    unsigned char x;
26    unsigned char y;
27    unsigned char * str;
28    unsigned char reverse;
29}CHARACTER_STRING;
30 
31typedef struct{
32    unsigned char x;
33    unsigned char y;
34    unsigned char reverse;
35}STRING_T;
36 
37extern unsigned char printf_string(STRING_T * p, char * fmt, ...);
38 
39#define BUFFER_SIZE 200
40 
41#endif /*GUI_H_*/

然后,我们在工程目录的drvier下建立gui.c文件,内容如下表所示

001/*
002 * =================================================================
003 *       Filename:  gui.c
004 *    Description: 
005 *        Version:  1.0.0
006 *        Created:  2010.4.16
007 *       Revision:  none
008 *       Compiler:  Nios II 9.0 IDE
009 *         Author:   (AVIC)
010 *          Email:  avic633@gmail.com 
011 * ================================================================
012 */
013#include "../inc/gui.h"
014#include "../inc/lcd.h"
015#include "../inc/tahoma.h"
016#include "../inc/hzk12.h"
017#include
018#include
019 
020static int _gui_x_16(X_16_T *p);
021static int  _print_tahoma(CHARACTER_STRING *p);
022static int _tahoma_string_length(char * p);
023unsigned char printf_string(STRING_T * p, char * fmt, ...);
024static int h_to_v( unsigned char *dest, unsigned char *source);
025int _print_simsun(CHARACTER_STRING *p);
026 
027/*
028 * ===  FUNCTION  ===================================================
029 *         Name:  _gui_x_16
030 * Description: 这个函数是根据字库的结构,将字库中的点打印到LCD屏幕上,结构体
031*                 X_16_T在gui.h中定义,可以通过参数确定点的位置,字库的宽度,
032*                 是否反色,以及字库文件的指针。
033 * =================================================================
034 */
035int _gui_x_16(X_16_T *p)
036{
037    unsigned char i;
038 
039    if(p == NULL)return -1;
040    if(p->x > 128)return -1;
041    if(p->y > 8)return -1 ;
042    if(p->matrix == NULL)return -1;
043     
044    if(p->reverse > 1)return -1;
045 
046    lcd.set_x(p->x);
047    lcd.set_y(p->y);
048    for(i=0;iwide;i++){
049   lcd.write_data(p->reverse?p->matrix[2*i+1]^0xfe:p->matrix[2*i+1]);
050    }
051 
052    lcd.set_x(p->x);
053    lcd.set_y(p->y+1);
054    for(i=0;iwide;i++){
055            lcd.write_data(p->reverse?~p->matrix[2*i]:p->matrix[2*i]);
056    }
057 
058   return 0;
059 
060}
061/*
062 * ===  FUNCTION  ===================================================
063 *         Name:  _print_tahoma
064 * Description: 这个函数是英文字库的处理函数,使用的字库为定义在tomato.h中,
065*                 CHARACTER_STRING结构体在gui.h当中定义,可以通过参数确定点
066*                 的位置,是否反色,以及字库文件的指针。
067 * =================================================================
068 */
069int  _print_tahoma(CHARACTER_STRING *p)
070{
071    unsigned char l,i=0;
072    unsigned int wide;
073    X_16_T tmp;
074    
075    if(p == NULL)return 0;
076    if(p->x > 128)return 0;
077    if(p->y > 8)return 0;
078    if(p->str == NULL)return 0;
079    if(p->reverse > 1)return 0;
080    
081    l=strlen((const char *)p->str);
082 
083    for(i=0;i
084        wide=tahoma_font_offset[p->str[i]-' '+1];
085        wide-=tahoma_font_offset[p->str[i]-' '];       
086            tmp.x=p->x;
087            tmp.y=p->y;
088            tmp.matrix=(unsigned char *)font_tahoma_8+tahoma_font_offset[p->str[i]-' ']*2;//*2是因为字模高为16位,两个字节
089            tmp.reverse=p->reverse;
090            tmp.wide=wide;
091 
092            _gui_x_16(&tmp);
093 
094            p->x+=wide;
095    }
096     
097    return 0;
098}
099/*
100 * ===  FUNCTION  ===================================================
101 *         Name:  _tahoma_string_length
102 *  Description:  这个函数求英文字模的宽度
103 * =================================================================
104 */
105int _tahoma_string_length(char * p)
106{
107    int temp=0;
108 
109    while(*p !='\0'){
110        temp+=tahoma_font_offset[*p-' '+1];
111        temp-=tahoma_font_offset[*p-' '];
112        p++;
113    }
114    return temp;
115}
116/*
117 * ===  FUNCTION  ====================================================
118 *         Name:  printf_string
119 * Description: 这个函数是实现中英文字体自动切换显示的,利用它可以显示中英文混合
120*                 字体的字符串。里面还涉及到了变参的使用
121 * ==================================================================
122 */
123unsigned char printf_string(STRING_T * p, char * fmt, ...)
124{
125     unsigned char buf1[BUFFER_SIZE];
126     CHARACTER_STRING tmp;
127     unsigned int i=0,offset,c=0;
128     va_list arg_ptr;
129     unsigned char buf[BUFFER_SIZE];
130      
131    if(p == NULL)return 0;
132    if(p->x > 191)return 0;
133    if(p->y > 6)return 0 ;
134 
135    memset(buf,'\0',sizeof(buf));
136    //这部分就是C语言中变参的使用方法
137    va_start(arg_ptr,fmt);
138    vsprintf(buf,fmt,arg_ptr);
139    va_end(arg_ptr);
140 
141    offset=p->x;
142 
143    while(buf[c]!='\0'){
144        //通过判断来决定字符是英文还是中文
145        if(buf[c] < 0x7f && buf[c]!='\n'){
146            i=0;
147            memset(buf1,'\0',sizeof(buf1));
148 
149            while(buf[c]<0x7f && buf[c]!='\0' &&buf[c]!='\n'){
150                buf1[i++]=buf[c++];
151            }
152 
153            tmp.x=offset;
154            offset+=_tahoma_string_length(buf1);
155            tmp.y=p->y;
156            tmp.str=buf1;
157 
158            tmp.reverse=p->reverse;
159 
160            if(_print_tahoma(&tmp)==-1)return 0;
161 
162        }
163 
164        if(buf[c] > 0x7f){
165            i=0;
166            memset(buf1,'\0',sizeof(buf1));
167 
168            while(buf[c] >0x7f){
169                buf1[i++]=buf[c++];
170                buf1[i++]=buf[c++];
171            }
172             
173            tmp.x=offset;
174            offset+=i*6;
175 
176            tmp.y=p->y;
177            tmp.str=buf1;
178            tmp.reverse=p->reverse;
179 
180            if(_print_simsun(&tmp)==-1)return 0;
181        }
182        //new line symbol
183        if(buf[c] =='\n'){
184            p->y+=2;
185            offset=p->x;
186            c++;
187        }
188    }
189    p->x=tmp.x;
190 
191    return 0;
192}
193/*
194 * ===  FUNCTION  ===================================================
195 *         Name:  h_to_v
196 * Description:  将汉字字模有横向转换为纵向,字库中的字模是横着放的,如果不经过转
197*                 化,显示出来的就是倒着的字。
198 * =================================================================
199 */  
200static int h_to_v( unsigned char *dest, unsigned char *source)
201{
202    int i,j;
203 
204    for(j=0;j<8;j++){
205        for(i=0;i<8;i++)if(source[30-i*2]&(0x80>>j))dest[j*2]|=(0x80>>i);
206        for(i=0;i<8;i++)if(source[14-i*2]&(0x80>>j))dest[j*2+1]|=(0x80>>i); 
207    }
208 
209    for(j=0;j<4;j++){
210        for(i=0;i<8;i++)if(source[31-i*2]&(0x80>>j))dest[j*2+16]|=(0x80>>i);
211        for(i=0;i<8;i++)if(source[15-i*2]&(0x80>>j))dest[j*2+17]|=(0x80>>i);    
212    }
213 
214    return 1;
215}
216/*
217 * ===  FUNCTION  ===================================================
218 *         Name:  _print_simsun
219 * Description: 这个函数是打印中文宋体汉字,
220 * =================================================================
221 */
222int _print_simsun(CHARACTER_STRING *p)
223{
224    unsigned char l,i;
225    X_16_T tmp;
226    unsigned int offset=0;
227    unsigned char bua[32],bub[32]; 
228 
229    if(p == NULL)return 0;
230    if(p->x > 128)return 0;
231    if(p->y > 64)return 0 ;
232    if(p->str == NULL)return 0;
233    if(p->reverse > 1)return 0;
234 
235    l=strlen(p->str);
236    l/=2;
237 
238    for(i=0;i
239        //这部分是根据机内码,求字模所在的位置,在前面以后有所提及
240         offset=p->str[2*i];
241        offset-=0xa1;
242        offset*=94;
243        offset+=p->str[2*i+1];
244        offset-=0xa1;
245        offset*=32;
246           
247        memcpy(bua,achzk12+offset,32);//achzk12是存放汉字字库的数组
248 
249         memset(bub,0,32);
250        h_to_v(bub,bua);
251 
252        tmp.x=p->x;
253        tmp.y=p->y;
254        tmp.reverse=p->reverse;
255        tmp.matrix=bub;
256        tmp.wide=12;    
257 
258        _gui_x_16(&tmp);
259 
260        p->x+=12;
261    }
262    return 0;
263}

      在上面涉及到了achzk12,它是存放中文字库的数组。对于中文字库,有两种解决方案,一种是将字库文件(bin格式)烧写到flash中,每次用的时候先从flash读出来;另一种是将字库文件(将bin格式文件转化为c格式)数组的形式放到程序中。这两种方案根据硬件系统来选取。在这里,我们选用了第二种,因为我们的外部sdram很大,将字库文件放到程序中,每次上电都会将字库文件导入到sdram中,这样调用的时候速度就会很快,那么大的sdram不用也是浪费。而第一种方案一般是在ram比较小的情况下使用的,这样可以节省ram的空间。由于ackzk12文件比较大,在这里就不放出来了。

      最后,我们来测试一下,写个测试程序吧。

01/*
02 * ==================================================================
03 *       Filename:  main.c
04 *    Description: 
05 *        Version:  1.0.0
06 *        Created:  2010.4.16
07 *       Revision:  none
08 *       Compiler:  Nios II 9.0 IDE
09 *         Author:  马瑞 (AVIC)
10 *          Email:  avic633@gmail.com 
11 * ==================================================================
12 */
13#include
14#include
15#include
16#include
17#include "../inc/lcd.h"
18#include "../inc/gui.h"
19#include "../inc/ds1302.h"
20 
21#include "system.h"
22#include "altera_avalon_pio_regs.h"
23#include "altera_avalon_timer_regs.h"
24#include "alt_types.h"
25#include "sys/alt_irq.h"
26 
27unsigned char time[7] = {0x00,0x19,0x14,0x17,0x03,0x03,0x10};//格式为: 秒 分 时 日 月 星期 年
28alt_u8 segtab[10]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90};  //0~9
29unsigned char led_buffer[8]={0};
30unsigned char bittab[6]={0xfe,0xfd,0xfb,0xf7,0xef,0xdf};
31static unsigned char cnt=0;
32unsigned char ti[][7]={"一","二","三","四","五","六","日"}; 
33 
34/***********************************************/
35static void timer_init(void);    //初始化中断
36 
37/***********************************************/
38int main(void)
39{
40    unsigned char i=0;
41    unsigned char buf[20];
42     
43    unsigned char en_str[]="Hello! What's your name?";
44    unsigned char cn_str[] = "你好!你叫什么名字?";
45    unsigned char str[] = " O(∩_∩)O~";
46 
47    STRING_T *string_t;
48     
49    timer_init();     
50    ds1302.set_time(time);
51     
52    lcd.initialize();
53    lcd.clear();
54     
55    string_t->x = 0;
56    string_t->y = 0;
57    string_t->reverse = 0;
58     
59    printf_string(string_t,"%s",en_str);
60   
61    string_t->x = 0;
62    string_t->y = 2;
63    string_t->reverse = 0;
64     
65    printf_string(string_t,"%s",cn_str);
66         
67    string_t->x = 0;
68    string_t->y = 4;
69    string_t->reverse = 0;
70     
71    printf_string(string_t,"%s",str);
72while(1){
73    //我们将实时时钟加入进来,这样就可以在LCD上显示时间了
74        ds1302.get_time(time);          //采集时
75         
76        string_t->x = 0;
77        string_t->y = 6;
78        string_t->reverse = 1;
79         
80        printf_string(string_t,"%02d-%02d-%02d %02d:%02d:%02d 星期%s\n",time[6],time[4],time[3],time[2],time[1],time[0],ti[time[5]-1]);
81         
82    }
83 
84  return 0;
85}

      写好以后,我们就可以编译了。编译通过以后运行,我们来看看效果如何,上张效果图吧。

LSFJP6R9L{AWN`3PI)SU5FW

      还不错吧,中文是宋体,英文是变宽的,显示效果很不错,连笑脸都可以打印出来,看来这个字库还是很全的,在此谢谢前辈们为我们做出的努力和贡献,我们将没齿难忘。

     这一节内容就结束了,谢谢大家的支持!

阅读(1653) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~