在运行时str被初始化为2个字节长度,FrameBuffer这

作者: 操作系统  发布:2019-09-23

2、(94*(区号-1)+位号-1)是一个汉字字模占用的字节数

 

内码 ch1 ch2
   不 不
1字节 1字节

fphzk = fopen("hzk16", "rb");

我们知道一个GB2312汉字是由两个字节编码的,范围为A1A1~FEFE。A1-A9为符号区,B0到F7为汉字区。每一个区有94个字符(注意:这只是编码的许可范围,不一定都有字型对应,比如符号区就有很多编码空白区域)。下面以汉字“我”为例,介绍如何在HZK16文件中找到它对应的32个字节的字模数据。

     2、(94*(区号-1)+位号-1)是一个汉字字模占用的字节数

#define int32 unsigned long

FILE* fphzk = NULL;

要求:原操作系统代码里只是支持了日语显示,需要做的是实现对这个系统的汉字全角支持。

   3、最后乘以32是因为汉字库文应从该位置起的32字节信息记录该字的字模信息(前面提到一个汉字要有32个字节显示)

位码:位号(汉字的第二个字节)-0xa0

int i, j, k, offset;

位码:位号(汉字的第二个字节)-0xa0

    lcd_put_ascii(var.xres / 2, var.yres / 2, 'a');
    printf("中: chinese code: %02x %02xn", str[0], str[1]);
    lcd_put_chinese(var.xres / 2 + 32, var.yres / 2, str);

select_chip(chip);   //选择第chip片27512芯片

以下是我自己写的示例程序, 可以自己修改成其它的数据格式.(很简单, 所以没写注释)。

前面说到一个汉字占两个字节,这两个中前一个字节为该汉字的区号,后一个字节为该字的位号。其中,每个区记录94个汉字,位号为该字在该区中的位置。所以要找到“我”在hzk16库中的位置就必须得到它的区码和位码。(为了区别使用了区码和区号,其实是一个东西,别被我误导了)

 

    fclose(HZK);
     fclose(fp);

offset = (94*(unsigned int)(word[0]-0xa0-1)+(word[1]-0xa0-1))*32;

这里其他的地方比较弄,第5步将大小修改一下,我的是nihongo = (unsigned char *) memman_alloc_4k(memman, 55*94*32);

前面说到一个汉字占两个字节,这两个中前一个字节为该汉字的区号,后一个字节为该字的 位号。其中,每个区记录94个汉字,位号为该字在该区中的位置。所以要找到“我”在hzk16库中的位置就必须得到它的区码和位码。(为了区别使用了区码 和区号,其实是一个东西,别被我误导了)

  在汉字信息处理系统中存在着多种汉字编码。一般来说,在系统的不同部位,可根据其环境给汉字定以相应的编码,因为在汉字信息处理系统中存在着数种汉字编码。这些编码构成了一个汉字的代码体系。

}

hzk16的介绍以及简单的使用方法

我们知道一个GB2312汉字是由两个字节编码的,范围为A1A1~FEFE。A1-A9为符号区,B0到F7为汉字区。每一个区有94个字符(注意:这只是编码的许可范围,不一定都有字型对应,比如符号区就有很多编码空白区域)。下面以汉字“我”为例,介绍如何在HZK16文件中找到它对应的32个字节的字模数据。

int8   chip;  //字模所在的芯片,可用74HC138之类的芯片译码。

{

offset=(94*(区码-1)+(位码-1))*32

 

int8   *int8_p;//定义一个unsigned char 指针

fphzk = fopen("hzk16", "rb");

 

    但Framebuffer本身不具备任何运算数据的能力,就只好比是一个暂时存放水的水池.CPU将运算后的结果放到这个水池,水池再将结果流到显示器. 中间不会对数据做处理. 应用程序也可以直接读写这个水池的内容.在这种机制下,尽管Framebuffer需要真正的显卡驱动的支持,但所有显示任务都有CPU完成,因此CPU 负担很重

在PC机的文本文件中,汉字是以机内码的形式存储的,每个汉字占用两个字节:第一个字节为区码,为了与ASCII码区别,范围从十六进制的0A1H开始(小于80H的为ASCII码字符),对应区位码中区码的第一区;第二个字节为位码,范围也是从0A1H开始,对应某区中的第一个位码。这样,将汉字机内码减去0A0AH就得该汉字的区位码。

int i, j, k, offset;

HZK16字库里的16×16汉字一共需要256个点来显示,也就是说需要32个字节才能达到显示一个普通汉字的目的。

刷写8*16字符点阵

int16 area_l,area_h;//定义两个整型变量,用于存储区码和位码

printf("%s", flag?"●":"○");

9159金沙官网 1

用命令:$ dd if=/dev/zero of=/dev/fb0 bs=1024 count=768 清空屏幕;

                         }else{   printf("%s",'-');

break;

  1. 了解HZK编码,理解一下符合GB2312标准的中文点阵字库文件HZK16;
  2. 下载中文GB2312的二进制点阵文件;
  3. 将HZK16.fnt文件放入nihongo文件夹中;
  4. 修改主makefile文件和app_make.txt文件,将原来装载nihongo.fnt的语句替换成装载HZK16.fnt即可;
  5. 修改bootpack.c文件,将之前分配的装载日语字体的内存扩大,载入字库的文件名;
  6. 在haribote/graphic.c中添加支持汉字的代码,增加一个函数用于显示汉字;
  7. 修改putfonts8_asc函数里if (task->langmode == 3)语句块;
  8. 测试程序。
  9. 注意:日文的编码是分为左半部分和右半部分,而我们使用的HZK16是分为上半部分和下半部分的。

并通过 mmap 系统调用进行地址映射,随后用 memset 将屏幕清空(这里假设显示模式是 1024x768-8 位色模式,线性内存模式):

某些高端单片机,如Motorola的M68300系列32位单片机,寻址范围可达8M,液晶显示常用的16×16汉字库二进制数据文件为两百多k,将汉字字库存入大容量的E2PROM,通过地址线可寻址到汉字库中的每一个汉字。

unsigned char key[8] = {

这样我们就可以得到汉字在HZK16中的绝对偏移位置:

 

void   read_hz(int16 hz){

flag = buffer[k*2+j]&key[i];

实现思路:

framebuffer的设备文件一般是 /dev/fb0、/dev/fb1 等等。

       addr=(int16)pos;         

};

HZK16字库是符合GB2312标准的16×16点阵字库,HZK16的GB2312-80支持的汉字有6763个,符号682个。其中一级汉字有3755个,按声序排列,二级汉字有3008个,按偏旁部首排列。我们在一些应用场合根本用不到这么多汉字字模,所以在应用时就可以只提取部分字体作为己用。

 

                            printf("%s",'#');

(94*(区号-1)+位号-1)是一个汉字字模占用的字节数

3、最后乘以32是因为汉字库文应从该位置起的32字节信息记录该字的字模信息(前面提到一个汉字要有32个字节显示)

对像素进行瞄颜色

       addr=(int16)pos;  

fgets((char*)word, 3, stdin);

第6步,要注意,HZK16是上下两部分,不同于日文的左右两部分的结构。

1     fd_fb = open("/dev/fb0",O_RDWR);
 2     if(fd_fb < 0)
 3     {
 4         printf("can't open /dev/fb0 n");
 5         return -1;
 6     }
 7     if(ioctl(fd_fb, FBIOGET_VSCREENINFO, &var))            //取出可变信息
 8     {
 9         printf("can't get var n");
10         return -1;    
11     }
12     if(ioctl(fd_fb, FBIOGET_FSCREENINFO, &fix))            //取出固定信息
13     {
14         printf("can't get fix n");
15         return -1;    
16     }
17     screen_size = var.xres * var.yres * var.bits_per_pixel / 8;    //占内存大小 单位字节
18     line_width = var.xres *  var.bits_per_pixel / 8;         //一行像素大小
19     pixel_width =  var.bits_per_pixel / 8;               //一点像素大小
20     
21     fb_mem = (unsigned char *)mmap(NULL, screen_size,        //mmap 系统调用进行地址映射
22         PROT_READ | PROT_WRITE, MAP_SHARED, fd_fb, 0);
23     if(fb_mem == (unsigned char *) -1)
24     {                                      
25         printf("can't mmap n");
26         return -1;
27     }
28     memset(fb_mem, 0, screen_size);                   //清屏,黑色

限于篇幅,这里仅仅给出流程图(假定事先将所需汉字写到了一个文本文件),如图1所示。

printf("%s", flag?"●":"○");

区码:区号(汉字的第一个字节)-0xa0 (因为汉字编码是从0xa0区开始的,所以文件最前面就是从0xa0区开始,要算出相对区码)

1 static const unsigned char fontdata_8x16[FONTDATAMAX] = {
 2 
 3     /* 0 0x00 '^@' */
 4     0x00, /* 00000000 */
 5     0x00, /* 00000000 */
 6     0x00, /* 00000000 */
 7     0x00, /* 00000000 */
 8     0x00, /* 00000000 */
 9     0x00, /* 00000000 */
10     0x00, /* 00000000 */
11     0x00, /* 00000000 */
12     0x00, /* 00000000 */
13     0x00, /* 00000000 */
14     0x00, /* 00000000 */
15     0x00, /* 00000000 */
16     0x00, /* 00000000 */
17     0x00, /* 00000000 */
18     0x00, /* 00000000 */
19     0x00, /* 00000000 */
20 
21     /* 1 0x01 '^A' */
22     0x00, /* 00000000 */
23     0x00, /* 00000000 */
24     0x7e, /* 01111110 */
25     0x81, /* 10000001 */
26     0xa5, /* 10100101 */
27     0x81, /* 10000001 */
28     0x81, /* 10000001 */
29     0xbd, /* 10111101 */
30     0x99, /* 10011001 */
31     0x81, /* 10000001 */
32     0x81, /* 10000001 */
33     0x7e, /* 01111110 */
34     0x00, /* 00000000 */
35     0x00, /* 00000000 */
36     0x00, /* 00000000 */
37     0x00, /* 00000000 */
38 
39         /*****
40     ****
41     ****
42     ****
43     ****
44     ****
45     ****
46     ****
47     *****/
48 
49     /* 255 0xff '' */
50     0x00, /* 00000000 */
51     0x00, /* 00000000 */
52     0x00, /* 00000000 */
53     0x00, /* 00000000 */
54     0x00, /* 00000000 */
55     0x00, /* 00000000 */
56     0x00, /* 00000000 */
57     0x00, /* 00000000 */
58     0x00, /* 00000000 */
59     0x00, /* 00000000 */
60     0x00, /* 00000000 */
61     0x00, /* 00000000 */
62     0x00, /* 00000000 */
63     0x00, /* 00000000 */
64     0x00, /* 00000000 */
65     0x00, /* 00000000 */
66 
67 };

下面给出一个根据汉字机内码(两字节)在汉字库中查找汉字的字模的程序。字库文件分成四部分,分别存在四片27512(并行EPROM)中。读出的字模存入hz_buffer[32]数组中。

fclose(fphzk);

void putfont32(char *vram, int xsize, int x, int y, char c, char *font1, char *font2)
{
    int i,k,j,f;
    char *p, d ;
    j=0;
    p=vram+(y+j)*xsize+x;
    j++;
    //上半部分
    for(i=0;i<16;i++)
    {
        for(k=0;k<8;k++)
        {
            if(font1[i]&(0x80>>k))
            {
                p[k+(i%2)*8]=c;
            }
        }
        if(i%2==0){
            for(k=0;k<4;k++){
                f=p[k];
                p[k]=p[7-k];
                p[7-k]=f;
            }
        }else{
            for(k=0;k<4;k++){
                f=p[k+8];
                p[k+8]=p[15-k];
                p[15-k]=f;
            }
        }
       /* for(k=0;k<8/2;k++)
        {
            f=p[k+(i%2)*8];
            p[k+(i%2)*8]=p[8-1-k+(i%2)*8];
            p[8-1-k+(i%2)*8]=f;
        }*/
        if(i%2)
        {
            p=vram+(y+j)*xsize+x;
            j++;
        }
    }
    //下半部分
    for(i=0;i<16;i++)
    {
        for(k=0;k<8;k++)
        {
            if(font2[i]&(0x80>>k))
            {
                p[k+(i%2)*8]=c;
            }
        }
        if(i%2==0){
            for(k=0;k<4;k++){
                f=p[k];
                p[k]=p[7-k];
                p[7-k]=f;
            }
        }else{
            for(k=0;k<4;k++){
                f=p[k+8];
                p[k+8]=p[15-k];
                p[15-k]=f;
            }
        }
        /*for(k=0;k<8/2;k++)
        {
            f=p[k+(i%2)*8];
            p[k+(i%2)*8]=p[8-1-k+(i%2)*8];
            p[8-1-k+(i%2)*8]=f;
        }*/
        if(i%2)
        {
            p=vram+(y+j)*xsize+x;
            j++;
        }
    }
    return;
}

 

     在实际中,由于现很少采用EPROM芯片,可以用并口、SPI,I2C接口的大容量Flash、EEPROM芯片。但I2C接口速度较慢,显示汉字的速度将会很慢,可以在一些比较少字场合使用;而SPI接口的存储芯片速度较快,接口简单,对于一般的应用场合还是可以满足的;对于大量使用的场合,可以使用并行接口,它具储存空间大,读取速度快的特点,如使用AT29系列的Flash存储器,单片容量可以达到256K以上,就不需要分开存储,但其需要较多的IO口,接口复杂。所以应根据实际来选择存储器。

【转自 自己学习用 侵删】

代码如下:

 

       chip=3;

}

运行结果,我们在euc.txt中加入一些汉字。

每个字符由16个字节表示

2基于单片机的汉字显示原理

printf("%02X ", buffer[k]);

 有了偏移地址就可以从HZK16中读取汉字编码了

 

for(j=0;j<16;j++)
        for(i=0;i<2;i++)
            for(k=0;k<8;k++)
                if(mat[j][i]&(0x80>>k)) /*测试为1的位则显示*/
                    {

FILE* fphzk = NULL;

参考资料:

 

汉字一般是以点阵式存储的,如16×16,24×24点阵(即汉字的字模),每个汉字由32字节(16点阵)或72字节(24点阵)描述。根据汉字的不同字体,也可分为宋体字模、楷体字模、黑体字模等等。

return 1;

1. 30天操作系统支持中文。

8*16像素的字符点阵

由于E2PROM中存储了整个汉字库,只须在硬件上设定存放汉字库的存储器片选地址,直接将汉字作为字符数组付给汉字显示函数,通过机内码计算出区号和位号,即可方便地对汉字字模进行调用了。与前两种方法相比,无须事先提取字模和设定其地址用于程序调用,因此在进行程序升级,涉及到汉字显示时,不用更改汉字字模数据。

int main(void)

注解:1、区码减1是因为数组是以0为开始而区号位号是以1为开始的

HZK16 字库是符合GB2312标准的16×16点阵字库,HZK16的GB2312-80支持的汉字有6763个,符号682个。其中一级汉字有3755个,按 声序排列,二级汉字有3008个,按偏旁部首排列。我们在一些应用场合根本用不到这么多汉字字模,所以在应用时就可以只提取部分字体作为己用。

area_h=*(int8_p+1)-0xa0; //机内码高字节减去0xa0得到位码

}

fb_mem = mmap (NULL, 1024*768, PROT_READ|PROT_WRITE,MAP_SHARED,fb,0);

int8_p=void_p;    //char类型指针指向空指针,即机内码的低字节

HZK16字库里的16×16汉字一共需要256个点来显示,也就是说需要32个字节才能达到显示一个普通汉字的目的。

仅需要用asii码值乘以16就可以定位到当前字符的点阵位置

int8 hz_buffer[32];//定义32字节数组,用于存储点阵字模,该字模为横排字模。

}

 

            2、(94*(区号-1)+位号-1)是一个汉字字模占用的字节数

注解:

可以重新写回屏幕: #dd if=fbfile of=/dev/fb;

                                                      汉字库的使用 

{

这样我们就可以得到汉字在HZK16中的绝对偏移位置:

    {

printf("n");

 

1.1、汉字机内码
  汉字机内码(亦称汉字内码)是系统内部处理和存储汉字而使用的代码。众所周知,西文字符的机内码多采用一个字节来表示的ASCII码,有的系统则采用EBCDIC码。一般只使用7位来表示128个字符,而把高位用作奇偶校验(或者不用)。我国的国标GB2312-80规定,一个汉字用两个字节表示,目前规定每个字节也只用七位,其高位未作定义。
  为了保证系统的中西文兼容,意味着系统的机内码中必须保持ASCII(IBM-PC采用该码作为西文字符的机内码)的使用,同时又要允许汉字机内码的使用,并且使两者之间没有冲突。如果用GB2312-80中的国标码作为机内码,则在系统中同时存在ASCII码和国标码时,将会产生二义性。例如,机内有两个字节的内容分别为30H和21H,它们既可以表示汉字“啊”的国标码,又可以表示字符“0”和“!”的ASCII码。所以,原原本本地采用国标码作为汉字机内码是不行的,必须要加以适当的变换。
  一般情况下是将国标码的每个字节的高位置成1,作为汉字机内码,这种编码称作为变形国标码。这样作既解决了西文机内码与汉字机内码的二义性,又保证汉字机内码与国标码之间有极简单的对应关系。其组织如下:

区码减1是因为数组是以0为开始而区号位号是以1为开始的

offset=(94*(区码-1)+(位码-1))*32

                              }

}

位码:位号(汉字的第二个字节)-0xa0

注解:1、区码减1是因为数组是以0为开始而区号位号是以1为开始的

for(j=0; j<2; j++){

 

       chip=0;addr=(int16)pos;

printf("n");

HZK16字库里的16×16汉字一共需要256个点来显示,也就是说需要32个字节才能达到显示一个普通汉字的目的。

}

printf("n");

字符点阵显示

/*

fprintf(stderr, "error hzk16n");

注解:1、区码减1是因为数组是以0为开始而区号位号是以1为开始的

3自定义小字库的制作

04 80 0E A0 78 90 08 90 08 84 FF FE 08 80 08 90

0A 90 0C 60 18 40 68 A0 09 20 0A 14 28 14 10 0C

 

       addr=(int16)pos;

}

 

有了偏移地址就可以从HZK16中读取汉字编码了,剩下的就是文件操作了,就不说了,要看代码(汉字)就是下面的:“hzk16汉字库的简单读写程序 ”,是一个最简单的c语言程序。

HZK16字库是符合GB2312标准的16×16点阵字库,HZK16的GB2312-80支持的汉字有6763个,符号682个。其中一级汉字有 3755个,按声序排列,二级汉字有3008个,按偏旁部首排列。

仿照写一个

    }

for(j=0; j<2; j++){

 

*/

printf("0x%02X};n", buffer[31]);

可以用命令: #dd if=/dev/zero of=/dev/fb 清空屏幕. 如果显示模式是 1024x768-8 位色,

这样我们就可以得到汉字在HZK16中的绝对偏移位置:

fphzk = NULL;

屏幕输出‘a’,“中”

区码=内码第一字节-160

printf("uchar code key[32] = {");

 

值得注意的是,基于单片机的汉字显示不能在字符LCD上实现。使用图形LCD有很多优点,不仅能显示汉字,而且可以实现汉字动态移动和上下滚屏,实现汉字与图形的混合显示,同时功耗低。

fclose(fphzk);

memset (fb_mem, 0, 1024*768); //这个命令应该只有在root可以执行

在C51中,HZK16汉字库的使用(mydows's Blog转载)

for(k=0; k<31; k++){

 

再由区位码可以得到它在汉字库中字模第一个字节的位置:

版本1

int fb;

区位码(10进制) 内码(16进制)
区号 位号 高字节 低字节
1—9 1—94 A1—A9 A1—FE
10—12 1—94 AA—AC A1—FE
13—15 1—94 AD—AF A1—FE
16—87 1—94 B0—F7 A1—FE

我们知道一个GB2312汉字是由两个字节编码的,范围为0xA1A1~0xFEFE。A1-A9为符号区,B0-F7为汉字区。每一个区有94个字符(注意:这只是编码的许可范围,不一定都有字型对应,比如符号区就有很多编码空白区域)。

一个字节8位来表示一行的8个像素是否被选中点亮

else if((pos>=128*1024)&&(pos<192*1024)) //在第三片27512芯片

就像下面这样:

用命令: #dd if=/dev/fb of=fbfile  可以将fb中的内容保存下来;

汉字的字模其实是汉字字形的图形化。对于16点阵字模,就是把汉字写在一个16×16的网格内,汉字的笔画能过某网格时该网格就对应1,否则该网格对应0,这样每一网格均对应1或0,把对应1的网格连起来看,就是这个汉字。汉字就是这样通过字节表示点阵存储在字库中的。

9159金沙官网,return 1;

    Linux是工作在保护模式下,所以用户态进程是无法象DOS那样使用显卡BIOS里提供的中断调用来实现直接写屏,Linux抽象出 FrameBuffer这个设备来供用户态进程实现直接写屏。Framebuffer机制模仿显卡的功能,将显卡硬件结构抽象掉,可以通过 Framebuffer的读写直接对显存进行操作。用户可以将Framebuffer看成是显示内存的一个映像,将其映射到进程地址空间之后,就可以直接进行读写操作,而写操作可以立即反应在屏幕上。这种操作是抽象的,统一的。用户不必关心物理显存的位置、换页机制等等具体细节。这些都是由 Framebuffer设备驱动来完成的。

int32 pos;  //定义一个long型变量,用于存储计算所得字模在字库的位置,

fseek(fphzk, offset, SEEK_SET);

 

#define int16 unsigned int

unsigned char key[8] = {

 

pos=32*((int32)((area_h-1)*94)+area_l-1); //计算在一个完整的字库中的位置(256K)

}

区码:区号(汉字的第一个字节)-0xa0    (因为汉字编码是从0xa0区开始的,所以文件最前面就是从0xa0区开始,要算出相对区码)

典型的汉字库可选用UCDOS下的字库,如16点阵字库HZK16。需要256K空间,用了较大的EEPROM,又不方便读取,而实际应用中需要的汉字又非常少,因而我们可以自己制作小的汉字库,在这个小字库里只包含系统需要的汉字。这样,一方面节省读取时间,另一方面大大地节省了资源。

下面以汉字"我"为例,介绍如何在HZK16文件中找到它对应的32个字节的字模数据。前面说到一个汉字占两个字节,这两个中前一个字节为该汉字的区号,后一个字节为该字的位号。其中,每个区记录94个汉字,位号为该字在该区中的位置。所以要找到"我"在hzk16库中的位置就必须得到它的区码和位码。

 

将整个汉字字库存放在EPROM或E2PROM内,程序根据要显示汉字的机内码来调用汉字字模。

我画的图示:

    fd_hzk16 =  open("HZK16",O_RDWR);
    if(fd_hzk16 < 0)
    {
        printf("can't open HZK16 n");
        return -1;
    }

    if(fstat(fd_hzk16, &hzk_stat))    //得到文件统计信息
    {
        printf("can't get fstatn");
        return -1;

    }
    hzk_mem = (unsigned char *)mmap(NULL, hzk_stat.st_size, 
        PROT_READ, MAP_SHARED, fd_hzk16, 0);
    if(hzk_mem == (unsigned char *) -1)
    {
        printf("can't mmap hzk_memn");
        return -1;
    }

    {

for(i=0; i<8; i++){

unsigned char* fb_mem;

2.1汉字字模

位码:汉字的第二个字节-0xA0

在使用Framebuffer时,Linux是将显卡置于图形模式下的.

       chip=2;

fseek(fphzk, offset, SEEK_SET);

 使用#include <sys/stat.h>中的fstat()函数来统计HZK16文件信息

本文使用另一种显示方法,即事先将程序用到的汉字、符号和数码(为了节省显示空间,可以将数码压成8×16点阵),编成一个文本文件,用一段小程序做出相应小的汉字库,这个小字库的汉字点阵数据取自于一般汉字库。再经过转换和调整,得到新的汉字库,最后把新字库固化在EEPROM中。单片机只需按序号读出点阵字节,送往LCD即可显示所需汉字。减轻了单片机的负担,去除了繁琐的查找内码、求起始位置、转换、调整等工作,提高了系统可靠性。

2017/07/02 更新,之前随手复制的别人的,只打算自己存档,所以格式没怎么管,但是看到500+阅读量觉得挺对不起之前点开的朋友的,而且终于打算好好经营这个号了,所以好好整理了一下。

fb = open ("/dev/fb0", O_RDWR);

                                                 hzk16汉字库的简单读写程序

示例源代码

使用HZK16 字库,将它拷贝到内存中,使用时直接用数组指向某个汉字所在地址

offset=(94*(区码-1)+(位码-1))*32

int main(void)

1 lcd_put_ascii(int x, int y, unsigned char c )
 2 {
 3     unsigned char *dots = (unsigned char *)&fontdata_8x16[c*16];
 4     int i, b;
 5     unsigned char byte;
 6     
 7     for(i = 0; i < 16; i++)
 8     {
 9         byte = dots[i];
10         
11         for(b = 7; b >= 0; b --)
12         {
13             if(byte & (1<<b))
14             {
15                 /* 显示 */
16                 lcd_put_pixel(x + 7 - b, y + i, 0xffffff);//白
17             }
18             else
19             {
20                         /* 不显示 */
21                 lcd_put_pixel(x + 7 - b, y + i, 0);//黑
22             
23             }
24         }
25     }
26     

1引言

for(;;){

    在应用程序中,一般通过将 FrameBuffer 设备映射到进程地址空间的方式使用,比如下面的程序就打开 /dev/fb0 设备,

先由内码计算出它在汉字库中的区位码,计算公式为:

for(k=0; k<32; k++){

 1 void lcd_put_pixel(int x, int y, unsigned int color)
 2 {
 3     unsigned char *pen_8 = fb_mem + y * line_width + x * pixel_width;     //当前像素对应内存位置
 4     unsigned short *pen_16;
 5     unsigned int *pen_32;
 6 
 7     unsigned int red, blue, green;
 8     
 9     pen_16 = (unsigned short *)pen_8;
10     pen_32 = (unsigned int *)pen_8;
11     
12     switch(var.bits_per_pixel)
13     {
14         case 8:
15         {
16             *pen_8 = color;            //对应调色板颜色
17             
18             break;
19         }
20         case 16:
21         {
22             /* 5*6*5 */
23             red   = (color >> 16) & 0xff;
24             green = (color >> 8) & 0xff;
25             blue  = (color >> 0) & 0xff;
26 
27             color = ((red >> 3 ) << 11) | ((green >> 2) << 5) | ( blue >> 3);
28             
29             /* 颜色数据为高位 */
30             *pen_16 = color;
31             
32             break;
33         }
34         case 32:
35         {
36             *pen_32 = color;
37             break;
38         }
39         
40     }
41 
42 }

area_l=*int8_p-0xa0; //机内码低字节减去0xa0得到区码

这样我们就可以得到汉字在HZK16中的绝对偏移位置:

 

void   *void_p;//定义一个空类型指针

版本2

 1 void lcd_put_chinese(int x, int y, unsigned char *str)
 2 {
 3     unsigned int area = str[0] - 0xa1;
 4     unsigned int where = str[1] - 0xa1;
 5     unsigned char *dots = hzk_mem + (area * 94 + where) * 32;
 6     unsigned char byte;
 7     int i,j,b;
 8 
 9     for(i=0; i < 16; i++)
10         for(j=0; j < 2; j++)
11         {
12             byte = dots[i*2 + j];
13             for(b=7; b >=0; b--)
14             {
15                 if(byte & (1<<b))
16                 {
17                     /* 显示 */
18                     lcd_put_pixel(x + j * 8 + 7 - b, y + i, 0xffffff);//白
19                 }
20                 else
21                 {
22                             /* 不显示 */
23                     lcd_put_pixel(x + j * 8 + 7 - b, y + i, 0);//黑
24                 
25                 }
26             }
27         }
28 
29 }

    }   

fprintf(stderr, "error hzk16n");

 

      hz_buffer[i]=read_data(addr+i); //读取一字节的数据

0x80,0x40,0x20,0x10,0x08,0x04,0x02,0x01

FrameBuffer的原理     FrameBuffer 是出现在 2.2.xx 内核当中的一种驱动程序接口。

1.3、汉字交换码
  汉字交换码是一种用于汉字信息处理系统之间,或者与通讯系统之间进行信息交换的汉字代码。汉字交换码位于一台机器的出口和另一台机器(包括输出设备与记录设备)的入口之间。为了要达到系统设备之间或记录介质之间信息交换的目的,汉字交换码必须采取统一的形式。目前国内计算机系统所采用的标准信息处理交换码,是根据国家标准制定的,即GB1988 — 《信息处理交换使用的七位编码字符集》;还制定了相应的代码扩充标准,即GB2311 — 《信息处理交换使用的七位编码字符集的扩充方法》。因为汉字交换码应与GB1988兼容,并根据GB2311所规定的方法进行编制。由于汉字数量远远大于七位编码所能表示的六千多个常用汉字制定了交换码的国家标准,即GB2312 — 《信息交换用汉字编码字符基本集》,其中每个汉字用对应于GB1988的两个七位码来表示。

区码:汉字的第一个字节-0xA0(因为汉字编码是从0xA0区开始的, 所以文件最前面就是从0xA0区开始, 要算出相对区码)

fread(buffer, 1, 32, fphzk);

    }

offset = (94*(unsigned int)(word[0]-0xa0-1)+(word[1]-0xa0-1))*32;

例如汉字“房”的机内码为十六进制的“B7BF”,其中“B7”表示区码,“BF”表示位码。所以“房”的区位码为0B7BFH-0A0A0H=171FH。将区码和位码分别转换为十进制得汉字“房”的区位码为“2331”,即“房”的点阵位于第23区的第31个字的位置,相当于在文件HZK16中的位置为第32×[(23-1) ×94+(31-1)]=67136B以后的32个字节为“房”的显示点阵。

unsigned char word[5];

UCDOS软件中的文件HZK16为16×16的国标汉字点阵文件,以二进制格式存储。在文件HZK16中,按汉字区位码从小到大依次存有国标区位码表中的所有汉字,每个汉字占用32个字节,每个区为94个汉字。

int flag;

           3、最后乘以32是因为汉字库文应从该位置起的32字节信息记录该字的字模信息(前面提到一个汉字要有32个字节显示)

printf("0x%02X,", buffer[k]);

在基于单片机的智能系统中,汉字显示模块是很重要的一个组成部分,它应用广泛、操作容易、调试简便。

};

 

我们在一些应用场合根本用不到这么多汉字字模,所以在应用时就可以只提取部分字体作为己用。

else if((pos>=64*1024)&&(pos<128*1024)) //在第二片27512芯片

if(fphzk == NULL){

//pos=116672;         //这是“请”字在HZK16文件中的位置,单位为字节。用于测试

}

                                  汉字的字模与显示--汉字的代码体系
目 录
  1.1 汉字机内码
  1.2 汉字地址码
  1.3 汉字交换码
  1.4 汉字字型码

}

    {

0x80,0x40,0x20,0x10,0x08,0x04,0x02,0x01

我们知道一个GB2312汉字是由两个字节编码的,范围为A1A1~FEFE。A1-A9为符号区,B0到F7为汉字区。每一个区有94个字符(注意:这只是编码的许可范围,不一定都有字型对应,比如符号区就有很多编码空白区域)。下面以汉字“我”为例,介绍如何在HZK16文件中找到它对应的32个字节的字模数据。

if(fphzk == NULL){

在计算机中对汉字的识别是通过机内码来实现的,汉字标准机内码为两字节代码。汉字在汉字库中是按照区位来排列的,每一区中有94个汉字,每个汉字都对应唯一的区号和在本区的位号,汉字输入法中就有区位码方法,实际上,汉字机内码和区位码有标准的对应关系,某个汉字在字库中的区号加上0xa0等于其机内码的高字节,位号加上0xa0等于其机内码的低字节,因此很容易通过程序计算出要显示的汉字在汉字库中的区位号,即得到了其在汉字库中的偏移地址。

unsigned char buffer[32];

位码=内码第二字节-160

}

hzk汉字点阵   
    
   int    i,j,k;   
   unsigned    char    incode[3]="我";    //    要读出的汉字   
   unsigned    char    qh,wh;   
   unsigned    long    offset;   
   //    占两个字节,    取其区位号   
   qh    =    incode[0]    -    0xa0;/ /获得区码            
   wh    =    incode[1]    -    0xa0;   / /获得位码               
   offset    =    (94*(qh-1)+(wh-1))*32;          /    *得到偏移位置*    /   
      
   FILE    *HZK;   
   char    mat[32];   
   if((HZK=fopen("hzk16",    "rb"))    ==    NULL)   
   {   
   printf("Can't    Open    hzk16n");   
   exit(0);   
   }   
   fseek(HZK,    offset,    SEEK_SET);   
   fread(mat,    32,    1,    HZK);

}

//显示

for(k=0; k<16; k++){

然而,在单片机上显示汉字也存在几个问题。首先,单片机资源有限,我们不能为了显示汉字占用太多的资源;其次,汉字存储读取比较繁琐,使用不方便;第三,汉字是通过点阵显示出来的,往往与LCD写入方式不一样,这就得进行转换和调整。

unsigned char buffer[32];

区码:区号(汉字的第一个字节)-0xa0    (因为汉字编码是从0xa0区开始的,所以文件最前面就是从0xa0区开始,要算出相对区码)

最后乘以32是因为汉字库文应从该位置起的32字节信息记录该字的字模信息(前面提到一个汉字要有32个字节显示)

void_p=&hz;    //空指针指向机内码的低字节

}

#define int8 unsigned char

(一行一行地保存,共16行,每行2个字节, 共32个字节)

                               图形LCD模块ACM19264ASB的汉字显示

所以,'我'在HZK16 16*16点阵字库的存放的序列为:

1.2、汉字地址码
  汉字地址码是指汉字字模库(这里主要指整字形的点阵字模库)中存储各汉字字形信息的逻辑地址码。中文系统中的汉字字模库有两种,它们分别存放在RAM(或EPROM)中和磁盘上。故中文系统中的汉字地址码有两种,一种采用内存地址数来表示(对应RAM和EPROM中的字库),另外一种采用盘地址来表示(对应于磁盘中的字库)。由于中文系统的汉字字模库中汉字字形信息排列的规则,使得中文系统的汉字字模库中的汉字字形信息排列序列的规则,使得中文系统的汉字地址码与汉字机内码之间存在着一个简单的函数关系。

for(k=0; k<16; k++){

    }

}

         HZK16字库是符合GB2312标准的16×16点阵字库,HZK16的GB2312-80支持的汉字有6763个,符号682个。其中一级汉字有3755个,按声序排列,二级汉字有3008个,按偏旁部首排列。我们在一些应用场合根本用不到这么多汉字字模,所以在应用时就可以只提取部分字体作为己用。

return 0;

函数void read_hz(int16 hz)的参数hz为两字节的机内码,调用方法:read_hz(‘汉’);

offset=(94*(区码-1)+(位码-1))*32

2.2汉字显示

fread(buffer, 1, 32, fphzk);

前面说到一个汉字占两个字节,这两个中前一个字节为该汉字的区号,后一个字节为该字的位号。其中,每个区记录94个汉字,位号为该字在该区中的位置。所以要找到“我”在hzk16库中的位置就必须得到它的区码和位码。(为了区别使用了区码和区号,其实是一个东西,别被我误导了)

printf("输入要生成字模的汉字(多个):");

    }

unsigned char word[3] = "我";

  根据CGB2312-80中的汉字、图形符号,根据其位置分为94个“区”,每个区包含94个汉字,每个汉字字符又称作“位”。其中“区”的序号,由01到94,“位”的序号,也是从01到94。若以横向表示“位”号,纵向表示“区”号,则“区”和“位”构成一个二维坐标。给定一个“区”值和“位”值就可以确定一个唯一的汉字或图形符号。所以4位数字就可以唯一确定一个汉字或符号,下面给出汉字的区内和内码对应关系表。

while(1){

(区码×94+位码)×32 于是,可以向后连续读出由32个字节组成的该字的点阵数据。

int flag;

int8    i;   //定义一个循环变量

if(*word == 'n')

int16 addr;  //在某一芯片64K字节空间内的地址

for(i=0; i<8; i++){

定义如下:
unsigned char str[]="我"
在运行时str被初始化为2个字节长度,内容为“我”的GBK码,为:0xCE(区码),0xD2(位码)。
使用如下换算公式得到“我”在HZK16文件中的地址,从该位置开始的顺序32字节为“我”的字模。
    ADD=【(区码-0xa1)×0x5e + (位码-0xa1)】×0x20
按照上面的计算方法,“我”的字模地址:0x216E0 。他的C语言字模为:0x04,0x80,0x0E,0xA0,0x78,0x90,0x08,
0x90,0x08,0x84,0xFF,0xFE,0x08,0x80,
0x08,0x90,0x0A,0x90,0x0C,0x60,0x18,
0x40,0x68,0xA0,0x09,0x20,0x0A,0x14,
0x28,0x14,0x10,0x0C

fphzk = NULL;

HZK16字库里的16×16汉字一共需要256个点来显示,也就是说需要32个字节才能达到显示一个普通汉字的目的。

}

汉字占用资源太多(如16点阵,每个汉字就需32字节),因而通常把汉字库放在EEPROM里,需要显示某个汉字时,先算出它的区位码,再求出点阵起始位置,从EEPROM中顺序调出该字的点阵数据,存在缓冲区里,最后依次送往LCD显示,描出该字。需要说明的是汉字存储方式与LCD显示方式有一定差别。

flag = buffer[k*2+j]&key[i];

if(pos<64*1024)   //在第一片27512芯片

return 0;

   

为了方便查找所需汉字的点阵,每个汉字都与一个双字节的内码一一对应。通过汉字的内码可以计算出它的点阵起始字节。现以16点阵为例说明。


表116点阵汉字字库存储方式

1.4、汉字字型码
  由于目前汉字信息处理系统中产生汉字字形的方式大多是数字式的,即以点阵的方式形成汉字,过汉字字形码是指确定一个汉字字形码也就不同。

    {

for(i=0;i<32;i++)

else if((pos>=192*1024)&&(pos<256*1024)) //在第四片27512芯片

    {

对ASCII字符,则read_hz('A'+0xa380);读取

       chip=1;

本文由9159.com发布于操作系统,转载请注明出处:在运行时str被初始化为2个字节长度,FrameBuffer这

关键词: