液晶显示器汉字字模存储及显示

一、3 种汉字字模存储和提取的方法

1、字模存放在程序存储器中;

        这种方法较为常用,针对程序不大或单片机无外部扩展数据存储区功能的情况。

2、通过外扩的EEPROM 存储汉字字模数据,将其作为外部数据存储器进行寻址;

        采用哈佛结构的单片机,如8051 单片机及其派生产品,程序存储器(ROM)数据存储器(RAM)可分别寻址,51 单片机ROM 和RAM 最大的寻址空间均为64 K 。通常来说,对于中型的嵌入式系统,尤其是带液晶的单片机系统,64 K的程序空间并不富裕,而将汉字字模作为常量数组会大大占用ROM 的空间。而相对来说,数据存储器只需几k 就够用了, 剩下很多空间可用于功能芯片的扩展。

        将提取的汉字字模数据存放在EPROM 或EEPROM内,并设定该芯片的片选地址,则只要知道某个汉字字模数据在该芯片的存储位置,通过程序计算出偏移地址,即可实现显示功能。

3、使用外扩的EEPROM存储整个汉字库

        某些高端单片机,如Motorola 的M68300 系列32 位单片机,寻址范围可达8 M。液晶显示常用的16 ×16 汉字库二进制数据文件为两百多K ,将汉字字库存入大容量的EEPROM , 通过地址线可寻址到汉字库中的每一个汉字。在计算机中对汉字的识别通过机内码来实现的,汉标准机内码为两字节代码汉字在汉字库中是按照区位来排列的,每一区中有94 个汉字,每个汉字都对应惟一的区号和在本区的位号,汉字输入法中就有区位码方法。实际上,汉字机内码和区位码有标准的对应关系:某个汉字在字库中的区号加上0xA0等于机内码的高字节,位号加上0xA0 等于机内码的低字节

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

二、具体如何显示汉字

1、GB2312

         GB2312将所收录的字符分为94 个区,编号为01区至94区;每个区收录94 个字符(但不一定就是94个),编号01位至94 位。GB2312 的每一个字符都由与其唯一对应的区号和位号所确定。一个汉字(或GB2312中的字符)占用两个字节,由前一字节可得到“区号”(或者说前一字节为“区号”,取决于这两个字节是什么),由后一字节可得到“位号”(或者说后一字节为“位号”)。例如,GB2312中第一个汉字“啊”,编号为16 区01 位(1601),内码为0xB0A1。

GB2312 字符集的区位分布表:
区号            字数           字符类别
01               94               一般符号
02               72                顺序号码
03               94                拉丁字母
04               83               日文假名
05               86               Katakana
06                48               希腊字母
07               66               俄文字母
08                63                汉语拼音符号
09                76                图形符号
10               15                备用区
16-55          3755            一级汉字,以拼音为序
56-87          3008            二级汉字,以笔划为序
88-94          备用区

2、具体步骤如下:

1、打开字库文件

      字库文件为HZK16,当然使用fopen函数了。

2、搜索汉字(寻址)

根据汉字区位码、内码,就可以知道找到这个汉字了。在我们输入汉字中,汉字已经在计算机中以某种编码形式存在了,以GB2312为例,如下面语句:
unsigned char incode[] = "啊";
那么,incode将占用3个字节,前面说了,一个汉字占2个字节,最后一个字节是“\0”。如果分别打印incode[0]和incode[1]的话,将得到0xb0,0xa1这两个数。它便是“啊”的内码。当然,这是GB2312编码,如果是UTF-8,又不一样了。可以使用百度和google分别搜索“啊”,查看浏览器地址栏出现的十六进制数(使用百度搜索“啊”,地址栏有“wd=%B0%A1”字样,其中的B0、A0便是GB2312编码中“啊”的内码)。
PS: 经常在VC6.0下写代码的可能会经常碰到“烫烫烫烫烫烫烫烫”这个东西。在VC6.0下,未手动初始化的内存(数组),编译器会自动初始化为0xcc的,而两个0xcc就是中文“烫”的内码。
那么如何 得到区号和位号?,区位号加上0x20是国标码,国标码加上0x80就是内码,则区位号等于内码减去0xA0。如下:
qh = incode[0] - 0xA0;// 区号
wh = incode[1] - 0xA0;// 位号
得到了区号和位号,还不行,还要知道如何在HZK16这个文件中找到“啊”这个汉字的 偏移量
计算公式:offset = ( 94*(qh-1) + (wh-1) ) * 32;
得到的偏移量便是HZK16文件中“啊”的偏移量。经过计算,知道offset为0xb040,用hexdump看一下这个地址的32个字节数据:
$ hexdump -C HZK/HZK16 | grep b040
0000b040 00 04 2f 7e f9 04 a9 04 aa 14 aa 7c ac 54 aa 54 |../~.......|.T.T|
这种数据不直观,将这些数据以二进制形式写出来,16个二进制一行,将得到如下数据:
00000000000000100 // 0x00 0x04
00101111001111110
11111001000000100
10101001000000100
10101010000010100
10101010001111100
10101100001010100
10101010001010100
10101010001010100
10101001001010100
11101001001110100
10101101001010100
00001010000000100
00001000000000100
00001000000010100
00001000000001100
如果将其中的“0”用空格替换,则效果如下(因网页问题有所调整(就是将原来的1个空格替换成2个空格),字符外观一致,但与实际数据不一致。
                            1   
    1  1111    111111 
11111    1            1   
1  1  1    1            1   
1  1  1  1          1  1   
1  1  1  1      11111   
1  1  11        1  1  1   
1  1  1  1      1  1  1   
1  1  1  1      1  1  1   
1  1  1    1    1  1  1   
111  1    1    111  1   
1  1  11  1    1  1  1   
        1  1              1   
        1                  1   
        1              1  1   
        1                11  
这个便是传说的“啊”字了。
总结一下,汉字在计算机中是内码, 内码-0xa0a0等于 区位号(用十进制表示,就是第xx区yy位), 内码-0x8080就是 国标码(十六进制),而 (区码-1)*94 + (位码-1)就是“字库码”——即这个 汉字在字库文件中的偏移量。找到了这个偏移量,就可读取数据,显示出来了。

3、显示

        将读到的数据中,为1的就是某种字符打印,为0的就打印空格。为方便起见,统一使用星号(“*”)打印。这个打印当然是逐位打印了,就是对每个字节都进行判断。在下面代码中将会看到。【在终端显示】
void display_font(char *mat)
 {
 	int i, j, k;
 	for(j=0;j<16;j++)
 	{
 		for(i=0;i<2;i++) /* 一个汉字占两个字节 */
 		{
 			for(k=0;k<8;k++)
 			{
 				/* 逐位相与,为1者打印 */
 				if(mat[j*2+i] & (0x80 >> k))
 					printf("*");
 				else
 					printf(" ");
 			}
 		}
 		printf("\n");
 	}
 }
 void DisplayFont(){
 	int i;
 	unsigned char incode[] = "你好吗";         /* 字符集编码为gb2312下可显示该汉字 */
 	unsigned char qh,wh;
 	unsigned long offset;
 	FILE    *HZK;
 	char *mat;
 	
 	if((HZK=fopen("HZK16","rb"))==NULL)
 	{
 		perror("Can't Open HZK16");
 		exit(0);
 	}
 	
 	mat=(char *)malloc(32);
 	memset(mat,0,32);
 	
 	for (i = 0; i< sizeof(incode)-1; i+=2)
 	{
 		qh = incode[i]   - 0xa0;//区号
 		wh = incode[i+1] - 0xa0;//位号
 		printf("code : %x %x\n", incode[i], incode[i+1]);
 		offset = ( 94*(qh-1) + (wh-1) ) * 32;  /* 寻址 */
 		printf("code : %x %x %x\n", incode[i], incode[i+1], offset);
 		fseek(HZK,offset,SEEK_SET);
 		fread(mat,32,1,HZK);
 		display_font(mat);
 	}
 	free(mat);
     	fclose(HZK);
 }





你可能感兴趣的:(MSP430,学习笔记,C语言)