使用Tslib在触摸屏上显示汉字

终于到了在触摸屏上显示汉字了,真正写代码、测试的时间是1天,在此之前的一切准备、学习花费约2周到3周时间。而为了获取触摸屏上显示的图像,花费约2天。由于网络驱动已经接近于放弃状态,NFS用不了,只好用U盘来回复制(即使没有耐心也必须有耐心了)。明明在内核中选择了支持NTFS格式的读写,但却不能将开发板上的文件复制到U盘,而用另一个FAT32格式的另一牌子的U盘,开发板死活认不出来,网上的资料说要修改代码,我又懒得去改。无奈之下,只好格式化那个NTFS的U盘,结果,这篇文章拖到现在才发表。

郑重说明:
本文作者在本文及前面的文章中没有提及作者的工作内容、工作时间、业余时间及业余生活,因为在这些文章中涉及那些工作、生活内容是不明智的。这些文章并没有任何迹象表明作者没有工作、没有业余生活,也并没有表明作者只生活在写代码中。
免责声明:
本文是作者在研究过程中的一篇文章,本着互联网共享、自由(free,应该不是“免费”)之精神发布于此。本文使用的是Tslib中的代码,并在此基础上添加自己的代码,关于Tslib,作者已经写过很多篇相关的文章了,这里公布的仅仅是自己添加的代码。作者对文中代码没有任何义务,仅因为Tslib使用GPL协议,本文作者必须使用这个协议。作者才疏学浅,孤陋寡闻,能力有限,文中错误的地方,欢迎在文后留言,趁作者还有激情研究之时,大家一直探讨,共同学习,天天向上。
再声明一点,本文作者在S3C2440芯片的开发板上,使用最新下载的tslib,使用汉字字库HZK16、HZK24*,通过自己写的代码,在开发板自带的触摸屏上显示汉字。但是,并没有在其它的测试环境、平台下进行测试。
关于汉字显示的算法(其实没啥算法)、步骤已经在前面的文章说了很多了,此处不再提及。
由于还没有对autotool进行研究,而Tslib又使用这个工具管理代码,因此不懂如何添加新文件,如果让新文件也能编译。只好在原来的原来的文件中添加代码了。添加的代码的函数声明在fbutils.h中,函数定义在fbutils.c文件中,测试代码在ts_test.c中。
代码修改了约三次,基本上都是一些结构上的调整,就不说那些体面的话了。至于真正改动之处,只在最底层的显示字符的代码修改了几个地方,就是将原来的乘法改为移位,而对其它一些地方的乘法及移位测试时,发现没什么区别,因此保留乘法。举一例,如

1
offset = (*ascii - 0x20 ) * 16; 

就没有改为

1
offset = (*ascii - 0x20 ) << 4; 

前者更能让人明白这里的ASCII字符在字库数组中占用16字节,而左移4位,的确让人不知道有什么含义。
已知bug:
1、不在GB2312范围之内的汉字不能正常显示——这是废话,正如在en_US字符集下显示中文一样。
2、UCDOS的HZK24*系列字库文件没有中文字符,像“◆ □ ■ △ ▲”等在16点阵下显示正常,而在24点阵中显示失败(乱码或其它汉字),网上找不到包括完整的中文字符的字库,另外,不知道使用UCDOS的字库算不算侵权(这些东西都可以在网络下载)。

函数声明:

1
2
3
4
5
6
7
8
9
10
11
/* new add by Late Lee */
/* ascii code */
void put_string_ascii(int x, int y, char *s, unsigned colidx);
void put_string_center_ascii(int x, int y, char *s, unsigned colidx);
/* cineses character */
void put_string_hz(FILE *fp, int x, int y, unsigned char *s, unsigned colidx);
void put_string_center_hz(FILE *fp, int x, int y, unsigned char *s, unsigned colidx);
/* chineses character & ascii */
void put_font(FILE *fp, int x, int y, unsigned char *s, unsigned colidx);
void put_font_center(FILE *fp, int x, int y, unsigned char *s, unsigned colidx);
/* end of new add */

测试代码(ts_test.c):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
static FILE *fp;  /* HZK file pointer by Late Lee */
#define HZK "HZK/HZK16" /* HZK16 or HZK24K/HZK24S */

static void refresh_screen ()
{
……
 /* just a test */
 unsigned char incode[] = "▲!ADC■测镕试◎示例"; // 注:“镕”字不在GB2312范围之内,不能正常显示。
 int y = yres/4+50;
 put_string_ascii(0, y, "Powered by Late Lee", 9);
 put_string_hz(fp, 0, y+30, "波神留我看斜阳听取蛙声一片", 2);
 put_font(fp, 0, y+56, incode, 5);
 /* end of the test */

……
}

关键的代码(fbutils.c):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
/* new add by Late Lee 2011-05-30*/
//#define HZK24
#ifdef HZK24  /* 24 */
#include "ascii24.h"
#define   ASCII_CODE   ascii24
#define   FONT_SIZE    24                         /* size: 24 */
#else         /* 16 */
#include "ascii16.h"
#define  ASCII_CODE  ascii16
#define  FONT_SIZE    16                         /* size: 16 */
#endif


#define BYTES                (FONT_SIZE/8)                   /* for HZ: 3 bytes  2 bytes*/
#define BUF_SIZE          (BYTES * FONT_SIZE)        /* HZ buff 3*24 = 72 bytes 2*16 = 32 bytes */

#define ASCII_BYTES     (BYTES-1)                    /* 2 1*/
#define ASCII_SIZE       (FONT_SIZE * ASCII_BYTES)      /* ASCII buffer: 24*2 = 48 bytes 16 * 1 = 16 bytes */
#define ASCII_WIDTH    (FONT_SIZE/2)                         /* ASCII: 16*8 24*12 */

/* end here Late Lee*/

/*****************************************************************************
*           new add by Late Lee 2011-05-30
*****************************************************************************/

/**
 * __display_ascii - Display an ASCII code on touch screen
 * @x: Column
 * @y: Row
 * @ascii: Which ASCII code to display 
 * @colidx: Color index(?)
 * This routine display an ASCII code that stored in an array(eg, ASCII_CODE).
 * 16x8 ASCII code takes 1 byte, 24*12 ASCII code takes 2 bytes, so we need 
 * -ASCII_BYTES-.
 */
static void __display_ascii(int x, int y, char *ascii, unsigned colidx)
{
        int i, j, k;
        unsigned char *p_ascii;
        int offset;        
        
        offset = (*ascii - 0x20 ) * ASCII_SIZE;  /* find the code in the array */
        p_ascii = ASCII_CODE + offset;

        for(i=0;i<FONT_SIZE;i++)
                for(j=0;j<ASCII_BYTES;j++)
                        for(k=0;k<8;k++)
                                if( p_ascii[i*ASCII_BYTES+j] & (0x80>>k) )
                                //if(*( p_ascii + i*ASCII_BYTES+j) & (0x80>>k))
                                        pixel (x + j*8 + k, y + i, colidx);
}

/**
 * put_string_ascii - Display an ASCII string on touch screen
 * @x: Column
 * @y: Row
 * @s: Which string to display
 * @colidx: Color index
 */
void put_string_ascii(int x, int y, char *s, unsigned colidx)
{
        while (*s != 0) {
                __display_ascii(x, y, s, colidx);
                x += ASCII_WIDTH;
                s++;
        }
}

/* not test */
void put_string_center_ascii(int x, int y, char *s, unsigned colidx)
{
        size_t sl = strlen (s);
        put_string_ascii (x - (sl / 2) * ASCII_WIDTH,
                    y - FONT_SIZE / 2, s, colidx);
}

/**
 * __display_font_16 - Display a 16x16 (chinese) character on touch screen
 * @fp: File pointer points to HZK(ie, HZK16)
 * @x: Column
 * @y: Row
 * @font: Which (chinese) character to display
 * @colidx: Color index
 * This routine ONLY display 16*16 character.
 * Every character takes two bytes, we show the first 8 bits, then the second 8 bits,
 * then the whole world will be shown before us.
 */
static void __display_font_16 (FILE *fp, int x, int y, unsigned char *font, unsigned colidx)
{
        int i, j, k;
        unsigned char mat[BUF_SIZE]={0};
        int qh,wh;
        unsigned long offset;
        qh = *font   - 0xa0;
        wh = *(font+1) - 0xa0;
        offset = ( 94*(qh-1) + (wh-1) ) * BUF_SIZE;  /* offset of the character in HZK */

         /* read it */
        fseek(fp,offset,SEEK_SET);
        fread(mat,BUF_SIZE,1,fp);

         /* show it */
        for(i=0;i<FONT_SIZE;i++)
                for(j=0;j<BYTES;j++)
                        for(k=0;k<8;k++)
                                if(mat [i*BYTES+j] & (0x80>>k))
                                        pixel (x + j*8 + k, y + i, colidx);
}

/**
 * __display_font_24 - Display a 24x24 (chinese) character on touch screen
 * @fp: File pointer points to HZK(ie, HZK24)
 * @x: Column
 * @y: Row
 * @font: Which (chinese) character to display
 * @colidx: Color index
 */
static void __display_font_24 (FILE *fp, int x, int y, unsigned char *font, unsigned colidx)
{
        unsigned int i, j;
        unsigned char mat[FONT_SIZE][BYTES]={{0}};
        int qh,wh;
        unsigned long offset;
        qh = *font   - 0xaf;
        wh = *(font+1) - 0xa0;
        offset = ( 94*(qh-1) + (wh-1) ) * BUF_SIZE;

        fseek(fp,offset,SEEK_SET);
        fread(mat,BUF_SIZE,1,fp);

        for(i=0;i<FONT_SIZE;i++)
                for(j=0;j<FONT_SIZE;j++)
                        if( mat[j][i>>3] & (0x80>>(i&7)) )
                        // if ( mat[j][i/8] & (0x80>>i%8) ) /* org */
                                pixel (x + j, y + i, colidx);
}

/**
 * put_string_hz - Display a (chinese) character string on touch screen
 * @fp: File pointer points to HZK(ie, HZK24 or HZK16)
 * @x: Column
 * @y: Row
 * @s: Which string to display(must be 'unsigned char*')
 * @colidx: Color index
 */
void put_string_hz (FILE *fp, int x, int y, unsigned char *s, unsigned colidx)
{        
        while (*s != 0) {
                #ifdef HZK24
                __display_font_24 (fp, x, y, s, colidx);  /* for HZK24 */
                #else
                __display_font_16 (fp, x, y, s, colidx);
                #endif
                x += FONT_SIZE;
                s += 2;         /* 2 bytes */
        }
}

/* not test */
void put_string_center_hz (FILE *fp, int x, int y, unsigned char *s, unsigned colidx)
{
        size_t sl = strlen ((char *)s);
        put_string_hz (fp, x - (sl/2) * FONT_SIZE, y - FONT_SIZE/2, s, colidx);
}

/**
 * put_font - Display an ASCII or/and (chinese) character string on touch screen
 * @fp: File pointer points to HZK(ie, HZK24 or HZK16)
 * @x: Column
 * @y: Row
 * @s: Which string to display
 * @colidx: Color index
 */
void put_font(FILE *fp, int x, int y, unsigned char *s, unsigned colidx)
{
        while (*s != 0) {
                if ( (*s>0xa0) && (*(s+1)>0xa0) ) {
                        #ifdef HZK24
                        __display_font_24 (fp, x, y, s, colidx);          /* for HZK24 */
                        #else
                        __display_font_16 (fp, x, y, s, colidx);         /* for HZK16 */
                        #endif
                        x += FONT_SIZE;
                        s += 2;         /* 2 bytes */
                } else {
                        __display_ascii (x, y, (char *)s, colidx);
                        x += ASCII_WIDTH;
                        s++;         /* 1 byte */
                }
        }
}
/* not test */
void put_font_center(FILE *fp, int x, int y, unsigned char *s, unsigned colidx)
{
        size_t sl = strlen ((char *)s);
        put_font (fp, x - (sl/2) * 16, y - 16/2, s, colidx);
}

关于截图:
使用fb2png(可通过google搜索“fb2png”,我是很辛苦才找到的),交叉编译,在开发板上执行如下命令:

1
fb2png /dev/fb0 filename.png 5 800 600 24

实际中使用的命令为:

1
fb2png /dev/fb0 filename.png 5 240 320 16

效果图如下(由于图片已经有了本人的大名,故不打水印了):
test_k_new test_s_new
效果图亦可以参见: http://www.latelee.org/yetanothertest/display-hz-on-touch-screen.html
临时整理的工程目录压缩包: 能显示汉字的tslib压缩包
下一计划是ADC和TS驱动。