要求:原操作系统代码里只是帮忙了马耳他语展现,须求做的是贯彻对那几个种类的方块字全角帮忙。

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

2017/07/02
更新,此前随手复制的旁人的,只打算自己存档,所以格式没怎么管,然而看看500+阅读量觉得挺对不起此前点开的朋友的,而且终于打算好好经营那么些号了,所以可以整理了眨眼之间间。

在C51中,HZK16汉字库的行使(mydows’s Blog转发)

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

   
Linux是工作在敬重形式下,所以用户态进程是力不从心象DOS那样采纳显卡BIOS里提供的刹车调用来贯彻直接写屏,Linux抽象出
FrameBuffer那几个装置来供用户态进度已毕直接写屏。Framebuffer机制模仿显卡的效率,将显卡硬件结构抽象掉,可以透过
Framebuffer的读写直接对显存举行操作。用户可以将Framebuffer看成是显示内存的一个影像,将其映射到进度地址空间之后,就足以一贯开展读写操作,而写操作可以马上反应在屏幕上。那种操作是空虚的,统一的。用户无需关注物理显存的职位、换页机制等等具体细节。那一个都是由
Framebuffer设备驱动来形成的。

【转自 自己读书用 侵删】

概念如下:
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

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

   
但Framebuffer本身不具有任何运算数据的能力,就不得不比是一个暂时寄放水的水池.CPU将运算后的结果放到这一个水池,水池再将结果流到屏幕.
中间不会对数据做处理.
应用程序也可以直接读写这一个水池的内容.在这种机制下,就算Framebuffer须求真正的显卡驱动的帮忙,但有所突显任务都有CPU完结,由此CPU
负担很重

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

        
HZK16字库是顺应GB2312标准的16×16点阵字库,HZK16的GB2312-80支撑的方块字有6763个,符号682个。其中一流汉字有3755个,按声序排列,二级汉字有3008个,按偏旁部首排列。大家在局地接纳场馆根本用不到那样多汉字字模,所以在行使时就足以只领到部分字体作为己用。

HZK16字库里的16×16中国字一共需求256个点来突显,也就是说必要32个字节才能达标显示一个司空眼惯汉字的目的。

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

我们在一些利用场馆根本用不到如此多汉字字模,所以在利用时就足以只领到部分字体作为己用。

HZK16字库里的16×16汉字一共须求256个点来体现,也就是说需求32个字节才能达到呈现一个家常汉字的目标。

咱俩知道一个GB2312汉字是由四个字节编码的,范围为A1A1~FEFE。A1-A9为符号区,B0到F7为汉字区。每一个区有94个字符(注意:那只是编码的特许限制,不自然都有字型对应,比如符号区就有好多编码空白区域)。上边以汉字“我”为例,介绍怎么着在HZK16文书中找到它对应的32个字节的字样数据。

能够用命令: #dd if=/dev/zero of=/dev/fb
清空显示屏. 假设突显方式是 1024×768-8 位色,

HZK16字库里的16×16汉字一共必要256个点来显示,也就是说要求32个字节才能达标突显一个一般性汉字的目标。

俺们知晓一个GB2312汉字是由三个字节编码的,范围为A1A1~FEFE。A1-A9为符号区,B0到F7为汉字区。每一个区有94个字符(注意:这只是编码的许可范围,不必然都有字型对应,比如符号区就有成百上千编码空白区域)。上边以汉字“我”为例,介绍怎么着在HZK16文件中找到它对应的32个字节的字样数据。

眼前说到一个中国字占三个字节,那四个中前一个字节为该汉字的区号,后一个字节为该字的位号。其中,每个区记录94个汉字,位号为该字在该区中的地方。所以要找到“我”在hzk16库中的地点就务须得到它的区码和位码。(为了分歧使用了区码和区号,其实是一个事物,别被自己误导了)

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

俺们明白一个GB2312汉字是由三个字节编码的,范围为0xA1A1~0xFEFE。A1-A9为符号区,B0-F7为汉字区。每一个区有94个字符(注意:那只是编码的特许限制,不必然都有字型对应,比如符号区就有为数不少编码空白区域)。

眼前说到一个中国字占多个字节,那七个中前一个字节为该汉字的区号,后一个字节为该字的位号。其中,每个区记录94个汉字,位号为该字在该区中的地方。所以要找到“我”在hzk16库中的地方就必须获得它的区码和位码。(为了差异使用了区码和区号,其实是一个东西,别被我误导了)

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

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

上边以汉字”我”为例,介绍怎样在HZK16文件中找到它对应的32个字节的字样数据。前边说到一个中国字占八个字节,那四个中前一个字节为该汉字的区号,后一个字节为该字的位号。其中,每个区记录94个汉字,位号为该字在该区中的地点。所以要找到”我”在hzk16库中的地方就非得取得它的区码和位码。

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

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

可以重复写回显示屏: #dd if=fbfile
of=/dev/fb;

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

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

那样大家就能够拿走汉字在HZK16中的相对偏移地方:

在接纳Framebuffer时,Linux是将显卡置于图形形式下的.

位码:汉字的其次个字节-0xA0

那样大家就足以博得汉字在HZK16中的相对偏移地点:

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

 

那般大家就能够取得汉字在HZK16中的绝对偏移地方:

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

声明:1、区码减1是因为数组是以0为始发而区号位号是以1为起初的

    在应用程序中,一般通过将 FrameBuffer
设备映射到进度地址空间的不二法门接纳,比如上面的顺序就打开 /dev/fb0
设备,

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

诠释:1、区码减1是因为数组是以0为始发而区号位号是以1为开始的

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

并由此 mmap 系统调用进行地址映射,随后用
memset 将屏幕清空(那里要是突显格局是 1024×768-8
位色方式,线性内存形式):

注解:

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

3、最终乘以32是因为汉字库文应从该岗位起的32字节音信记录该字的字样音讯(后边提到一个汉字要有32个字节显示)

int fb;

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

           3、最终乘以32是因为汉字库文应从该地方起的32字节音信记录该字的字样新闻(前边提到一个中国字要有32个字节显示)

 有了摇头地址就足以从HZK16中读取汉字编码了

unsigned char* fb_mem;

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

有了摇头地址就足以从HZK16中读取汉字编码了,剩下的就是文件操作了,就隐瞒了,要看代码(汉字)就是下面的:“hzk16汉字库的简单读写程序 ”,是一个最简便易行的c语言程序。

落到实处思路:

fb = open (“/dev/fb0”, O_RDWR);

末尾乘以32是因为汉字库文应从该职责起的32字节新闻记录该字的字样音信(前边提到一个汉字要有32个字节显示)

                                                 hzk16汉字库的简短读写程序

  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是分为上半部分和下半部分的。

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

自身画的图示:

hzk汉字点阵   
    
   int    i,j,k;   
   unsigned    char    incode[3]=”我”;    //    要读出的汉字   
   unsigned    char    qh,wh;   
   unsigned    long    offset;   
16点阵字库的使用及示范程序,添加中文字库。   //    占八个字节,    取其区位号   
   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    hzk16\n”);   
   exit(0);   
   }   
   fseek(HZK,    offset,    SEEK_SET);   
   fread(mat,    32,    1,    HZK);

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

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

所以,’我’在HZK16 16*16点阵字库的寄放的连串为:

//显示

第6步,要留心,HZK16是前后两片段,分裂于日文的左右两部分的结构。

 

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

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的位则体现*/
                    {

代码如下:

效仿写一个

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

                            printf(“%s”,’#’);

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;
}

 

就如上边那样:

                         }else{   printf(“%s”,’-‘);

 

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);                   //清屏,黑色

以下是我要好写的示范程序, 可以协调修改成别的的多少格式.(很简短,
所以没写注释)。

                              }

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

 

示例源代码

    fclose(HZK);
     fclose(fp);

澳门金沙国际 1

字符点阵突显

版本1

                               图形LCD模块ACM19264ASB的汉字呈现

参考资料:

8*16像素的字符点阵

int main(void)

1引言

1. 30天操作系统辅助中文。

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

{

在按照单片机的智能种类中,汉字突显模块是很首要的一个组成部分,它应用广泛、操作不难、调试简便。

每个字符由16个字节表示

FILE* fphzk = NULL;

可是,在单片机上突显汉字也存在多少个问题。首先,单片机资源有限,我们不能为了显得汉字占用太多的资源;其次,汉字存储读取比较繁琐,使用不便宜;第三,汉字是透过点阵突显出来的,往往与LCD写入措施不均等,这就得进行转移和调动。

仅须求用asii码值乘以16就足以稳定到目前字符的点阵地点

int i, j, k, offset;

值得注意的是,基于单片机的方块字呈现不可能在字符LCD上贯彻。使用图形LCD有很多亮点,不仅能显得汉字,而且能够达成汉字动态移动和左右滚屏,完毕汉字与图片的插花突显,同时功耗低。

 

int flag;

2基于单片机的汉字展现原理

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 };

unsigned char buffer[32];

2.1中国字字模

 

澳门金沙国际,unsigned char word[3] = “我”;

汉字相似是以点阵式存储的,如16×16,24×24点阵(即汉字的字样),每个汉字由32字节(16点阵)或72字节(24点阵)描述。根据汉字的两样字体,也可分为陶文字模、甲骨文字模、大篆字模等等。

刷写8*16字符点阵

unsigned char key[8] = {

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

 

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

为了有利于寻找所需汉字的点阵,每个汉字都与一个双字节的内码一一对应。通过汉字的内码可以统计出它的点阵开端字节。现以16点阵为例表明。

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     

};

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

 

fphzk = fopen(“hzk16”, “rb”);

区码=内码第一字节-160

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

if(fphzk == NULL){

位码=内码第二字节-160

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

fprintf(stderr, “error hzk16\n”);

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

 

return 1;

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

    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 fstat\n");
        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_mem\n");
        return -1;
    }

}

2.2中国字突显

 

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

汉字占用资源太多(如16点阵,每个汉字就需32字节),因此平常把汉字库放在EEPROM里,必要显示某个汉字时,先算出它的区位码,再求出点阵开首地方,从EEPROM中相继调出该字的点阵数据,存在缓冲区里,最后依次送往LCD展现,描出该字。须要证实的是汉字存储格局与LCD突显格局有一定差别。

 

fseek(fphzk, offset, SEEK_SET);

正文使用另一种展现情势,即事先将次第用到的方块字、符号和数码(为了节约突显空间,可以将数据压成8×16点阵),编成一个文件文件,用一段小程序做出相应小的汉字库,这些小字库的汉字点阵数据取自于一般汉字库。再经过转换和调动,得到新的汉字库,最后把新字库固化在EEPROM中。单片机只需按序号读出点阵字节,送往LCD即可展现所需汉字。减轻了单片机的承受,去除了繁琐的查找内码、求起初地点、转换、调整等工作,进步了系统可相信性。

HZK16
字库是吻合GB2312标准的16×16点阵字库,HZK16的GB2312-80扶助的汉字有6763个,符号682个。其中一流汉字有3755个,按
声序排列,二级汉字有3008个,按偏旁部首排列。我们在局地使用场所根本用不到这般多汉字字模,所以在使用时就可以只领到部分字体作为己用。

fread(buffer, 1, 32, fphzk);

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

 

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

3自定义小字库的造作

HZK16字库里的16×16中国字一共须求256个点来体现,也就是说要求32个字节才能达到显示一个常见汉字的目标。

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

一级的汉字库可拔取UCDOS下的字库,如16点阵字库HZK16。须要256K空中,用了较大的EEPROM,又不便于读取,而实在利用中须求的汉字又非常少,由此大家得以友善创造小的汉字库,在这一个小字库里只包蕴系统须要的汉字。这样,一方面节省读取时间,另一方面大大地节约了资源。

咱俩清楚一个GB2312汉字是由五个字节编码的,范围为A1A1~FEFE。A1-A9为符号区,B0到F7为汉字区。每一个区有94个字符(注意:那只是编码的认可限制,不肯定都有字型对应,比如符号区就有众多编码空白区域)。上边以汉字“我”为例,介绍如何在HZK16文书中找到它对应的32个字节的字样数据。

}

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

 

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

前面说到一个中国字占多个字节,那五个中前一个字节为该汉字的区号,后一个字节为该字的
位号。其中,每个区记录94个汉字,位号为该字在该区中的地点。所以要找到“我”在hzk16库中的地点就非得得到它的区码和位码。(为了不一样使用了区码
和区号,其实是一个东西,别被我误导了)

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

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

 

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

好几高端单片机,如红米的M68300连串32位单片机,寻址范围可达8M,液晶突显常用的16×16汉字库二进制数据文件为两百多k,将汉字字库存入大容量的E2PROM,通过地点线可寻址到汉字库中的每一个中国字。

区码:区号(汉字的率先个字节)-0xa0   
(因为汉字编码是从0xa0区初阶的,所以文件最终边就是从0xa0区开头,要算出相对区码)

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

在处理器中对汉字的鉴别是通过机内码来促成的,汉字标准机内码为两字节代码。汉字在汉字库中是依据区位来排列的,每一区中有94个汉字,每个汉字都对应唯一的区号和在本区的位号,汉字输入法中就有区位码方法,实际上,汉字机内码和区位码有规范的相应关系,某个汉字在字库中的区号加上0xa0等于其机内码的高字节,位号加上0xa0等于其机内码的低字节,因而很不难通进度序总结出要来得的汉字在汉字库中的区位号,即取得了其在汉字库中的偏移地址。

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

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

出于E2PROM中存储了一切汉字库,只须在硬件上设定存放汉字库的存储器片选地址,直接将汉字作为字符数组付给汉字显示函数,通过机内码总计出区号和位号,即可方便地对汉字字模举办调用了。与前三种艺术比较,无须事先提取字模和设定其地址用于程序调用,因而在展开程序升级,涉及到汉字展现时,不用更改汉字字模数据。

那样大家就足以得到汉字在HZK16中的绝对偏移地点:

}

                                  汉字的字样与浮现–汉字的代码连串
目 录
  1.1 汉字机内码
  1.2 汉字地址码
  1.3 汉字沟通码
  1.4 汉字字型码

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

}


 

printf(“\n”);

  在汉字新闻处理系统中留存着冒尖汉字编码。一般的话,在系统的两样地位,可根据其条件给汉字定以相应的编码,因为在汉字音讯处理系统中留存着数种汉字编码。那个编码构成了一个中国字的代码连串。

诠释:1、区码减1是因为数组是以0为起始而区号位号是以1为开始的

}

1.1、汉字机内码
  汉字机内码(亦称汉字内码)是系统里头处理和仓储汉字而利用的代码。众所周知,西文字符的机内码多应用一个字节来表示的ASCII码,有的系统则使用EBCDIC码。一般只利用7位来代表128个字符,而把高位用作奇偶校验(或者不用)。我国的国标GB2312-80确定,一个中国字用多少个字节表示,近期规定每个字节也只用七位,其高位未作定义。
  为了保险系统的中西文包容,意味着系统的机内码中务必维持ASCII(IBM-PC接纳该码作为西文字符的机内码)的施用,同时又要允许汉字机内码的运用,并且使两者之间没有争持。假诺用GB2312-80中的国标码作为机内码,则在系统中还要设有ASCII码和国标码时,将会时有暴发二义性。例如,机内有七个字节的内容分别为30H和21H,它们既可以象征汉字“啊”的国标码,又有什么不可代表字符“0”和“!”的ASCII码。所以,一五一十地利用国标码作为汉字机内码是格外的,必必要加以合适的变换。
  一般景况下是将国标码的每个字节的高职务成1,作为汉字机内码,这种编码称作为变形国标码。那样作既解决了西文机内码与汉字机内码的二义性,又确保汉字机内码与国标码之间有极不难的照应关系。其社团如下:

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

fclose(fphzk);

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

   3、最终乘以32是因为汉字库文应从该岗位起的32字节音讯记录该字的字样信息(前边提到一个中国字要有32个字节显示)

fphzk = NULL;

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

 

return 0;

区位码(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

 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 }

}

1.2、汉字地址码
  汉字地址码是指汉字字模库(那里关键指整字形的点阵字模库)中存储各汉字字形音讯的逻辑地址码。中文系统中的汉字字模库有三种,它们分别存放在RAM(或EPROM)中和磁盘上。故汉语系统中的汉字地址码有二种,一种选拔内存地址数来表示(对应RAM和EPROM中的字库),其它一种选择盘地址来代表(对应于磁盘中的字库)。由于中文系统的汉字字模库中汉字字形新闻排列的规则,使得中文系统的汉字字模库中的汉字字形音讯排列体系的平整,使得普通话系统的汉字地址码与汉字机内码之间存在着一个简单易行的函数关系。

 

版本2

1.3、汉字互换码
  汉字调换码是一种用于汉字音讯处理系统之间,或者与广播发表系统里头开展新闻沟通的汉字代码。汉字调换码位于一台机械的发话和另一台机械(包含输出设备与记录设备)的进口之间。为了要达成系统装备之间或记录介质之间音讯调换的目标,汉字调换码必须运用联合的款型。近期境内计算机系列所使用的正式音讯处理沟通码,是基于国家标准制定的,即GB1988

《音信处理交流使用的七位编码字符集》;还制定了相应的代码扩展标准,即GB2311

《音讯处理调换使用的七位编码字符集的伸张方法》。因为汉字调换码应与GB1988包容,并依照GB2311所确定的措施进行编辑。由于汉字数量远远超乎七位编码所能表示的六千八个常用汉字制定了调换码的国家标准,即GB2312

《消息调换用汉字编码字符基本集》,其中每个汉字用对应于GB1988的多少个七位码来表示。

 

int main(void)

1.4、汉字字型码
  由于近期汉字音信处理系统中暴发汉字字形的措施大多是数字式的,即以点阵的艺术形成汉字,过汉字字形码是指确定一个汉字字形码也就差距。

对像素进行瞄颜色

{

                                                      汉字库的行使 

 

FILE* fphzk = NULL;

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

 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 }

int i, j, k, offset;

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

 

int flag;

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

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

unsigned char buffer[32];

上面给出一个根据汉字机内码(两字节)在汉字库中寻觅汉字的字样的主次。字库文件分成四局地,分别设有四片27512(并行EPROM)中。读出的字样存入hz_buffer[32]数组中。

 

unsigned char word[5];

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

屏幕输出‘a’,“中”

unsigned char key[8] = {

#define int8 unsigned char

 

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

#define int16 unsigned int

};

#define int32 unsigned long

fphzk = fopen(“hzk16”, “rb”);

/*

if(fphzk == NULL){

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

fprintf(stderr, “error hzk16\n”);

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

return 1;

*/

}

void   read_hz(int16 hz){

while(1){

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

printf(“输入要生成字模的汉字(四个):”);

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

for(;;){

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

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

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

if(*word == ‘\n’)

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

break;

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

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

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

fseek(fphzk, offset, SEEK_SET);

   

fread(buffer, 1, 32, fphzk);

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

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

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

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

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

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

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

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

pos=32*((int32)((area_h-1)*94)+area_l-1);
//计算在一个完好无损的字库中的地点(256K)

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

//pos=116672;        
//那是“请”字在HZK16文本中的地点,单位为字节。用于测试

}

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

}

    {

printf(“\n”);

       chip=0;addr=(int16)pos;

}

    }

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

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

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

    {

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

       chip=1;

}

       addr=(int16)pos;  

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

    }

printf(“\n”);

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

}

    {

}

       chip=2;

fclose(fphzk);

       addr=(int16)pos;

fphzk = NULL;

    }   

return 0;

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

}

    {

       chip=3;

       addr=(int16)pos;         

    }

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

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

    {

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

    }

}

   
 在实际上中,由于现很少使用EPROM芯片,可以用并口、SPI,I2C接口的大容量Flash、EEPROM芯片。但I2C接口速度较慢,呈现汉字的进度将会很慢,可以在部分比较少字场面使用;而SPI接口的存储芯片速度较快,接口简单,对于一般的施用场地仍可以满意的;对于大气行使的场馆,可以动用并行接口,它具储存空间大,读取速度快的特性,如接纳AT29多重的Flash存储器,单片容量可以完成256K以上,就不要求分开储存,但其索要较多的IO口,接口复杂。所以应基于实际来抉择存储器。

 

相关文章