基于三星S3C2440的文字显示 【转载】

来源:互联网 发布:网络传真机服务 编辑:程序博客网 时间:2024/05/16 17:52

基于三星S3C2440的文字显示* 

 

Abstract:   As a result of Samsung S3C2440 supports read and write the NAND flash, while the capacity of the Nand flash is bigger, therefore, we can implement mixed typesetting the text of multiple font style, multiple font size, and multiple language in S3C2440. This article will expatiate the text displays based on Samsung S3C2440, the content including the font library’s store style, font library’s loading, text display, the realization of mix typesetting of multiple font style, multiple font size, and multiple language , wrap Automatically and so on.

 

Key words:  multiple font style; multiple font size; multiple language; mixed typesetting

 

摘  要:  由于三星S3C2440支持对Nand flash的读写,同时Nand flash的容量比较大,因此,在S3C2440上,我们完全可以实现多种字体,多种字号的文字,多语言混排。本文将详细阐述基于三星S3C2440的文字显示,内容包括字库的存储方式、字库的加载、文字的显示、多种字体字号及多语言混排和自动换行的实现等。

关键词:  多字体;多字号;多语言;混排

 

1引言

    在嵌入式系统中,无操作系统的情况下,文字显示大概有两种方法。

    第一种方法就是将所需的文字的点阵数据放在源代码中,与源代码一起编译,这种处理方法优缺点很明显,优点在于,首先,操作简单;其次在于,根据需要将用到的文字的点阵数据导入,所需要的空间比较小。这样的操作方式,缺点也是非常明显的,首先,根据需要将数据导入,这样的操作缺乏灵活性,每个程序所需的文字并不完全一致,同时实现多字体、多字号的输出比较麻烦;接着,增加编译负担,由于与源代码一起编译,编译的时候也会对数据进行语法检查,而且通常情况下,点阵数据量也是比较大的;最后,增加了调试和烧写的时间,每次调试或者烧写,都涉及到大数据量的点阵数据,这样大大增加了速度。

    第二种方法是,将大部分的文字的点阵数据直接烧写到嵌入式系统的存储器中,不参与到源代码中。相对第一种方法,缺点在于,首先,由于将大部分的文字点阵数据烧写到存储器,这样占用存储器空间大。接着,由于点阵数据是烧写到存储器中,所以在显示文字之前必须将数据进行加载,同时,多种存储器读取方法不尽相同,这样就更大程序地加大了操作的难度。需要指出的是,特殊情况下,如果是将点阵数据存储于片内存储器的话,加载操作是不需要的。优点在于,首先,文字比较齐全;其次,代码与数据分离,不增加编译的负担;接着,系统的管理方便了多字体、多字号、多语言的混合排版。

    综上所述,两种方法并无完全的优劣之分,第一种方法比较适合于存储器比较小,所需文字显示比较固定的嵌入式系统,而第二种方法比较适合存储器比较大,所需文字未知的情况的嵌入式系统。本人主要阐述的是在三星S3C2440嵌入式系统下文字的显示,采用的是第二种方法。由于S3C2440支持大容量存储器Nand flash的读写操作,因此第二种方法中的缺点并不十分明显,而可以将第二种方法中的优点体现出来。

设计方案

2.1 字库的存储

    字库的存储包括三个方面,一是字库点阵的排列形式,二是Nand flash中的存储,三是代码中的定义。

2.1.1 字库点阵的排列形式

    本文的所述的字库均是以从左到右,从上到下的排列形式。

2.1.2 Nand flash中存储

    以16*8的ASCII点阵数据的存储为例,以与代码分离的原则,使用H-jtag软件将16*8的ASCII点阵数据存储于Nand flash的第2048块第0页,这样就不会与代码相互干扰。

    在下一个字库烧写的时候,要计算好字库文件的大小,及其占用Nand flash的块数和页数。一般情况下,以块为单位,而不是以页为单位,比如,16*8的ASCII字库只有2048B大小,只占到4个页的空间,但在计算的时候,要认为它占1个块的空间,下一字库的地址应该是第2049块第0页,而不是第2048块第5页。

    这样的目的在于,第一,方便读取,第二,由Nand flash本身的结构决定的,虽然其读操作是以页为单位,但其写与擦除操作是以块为单位,当要对字库进行写或者擦除操作时,不会影响到其它的数据。

2.1.3 代码中的定义

   以16*8的ASCII为例,定义如下:

   uint8 EN8[128][16];

   该定义是一个二维的数组,列代表的是对应的ASCII码,而行代表的是对应的ASCII码的点阵数据。ASCII码有128个,而每个ASCII码占用的空间是16*8Bits/8=16Bytes。这样的设计对文字的显示非常方便,而且无须用到指针,减少了指针造成的错误的风险。具体的实现在下文有详细阐述。

16*8的点阵中,16bits与8bits都可以转化为整数个Byte,如果遇到非整数个Byte的数据,也是以整数个Byte来处理,以24*12的ASCII为例,定义如下:

   uint8 EN12[128][48];

   24bits与12bits中,12bits并不等于整数的Byte,而Nand flash的读取是以字节为单位的,这将给数据的加载带来麻烦,已经方便的方法是将12bits在空间上算作2bytes,这样二维数组定义的行大小是24*16 Bits/8=48Bytes,而不是24*12 Bits/8=36Bytes。

2.2 文字的显示

2.2.1 字库的加载

以下以16*8的ASCII的字库加载为例。

void LcdDriver_S3C2440::Load_16_8_ASCII( )        //字库存在Nand Flash第2048块第0页

{

         uint16 i,j;

         uint32 x=0,y=0;

         state_16_EN=1;  //加载状态变量,在文字显示时,会检查该变量值,当为0时,将执行该方法

         uint32 BaseAddr=0x10000;  //该字库存储在Nand flash的初始地址

 

         for(i=0;i<4;i++) //ASCII_24_12_宋体.hzk大小为2,048 字节,占Nand Flash 4个Page

         {

                   this-> Nand_Device->ReadPage(BaseAddr++,page_buf);//以页为单位读取字库数据

                   for(j=0;j<512;j++)        //每页占512个字节,不包括ECC校验码.

                   {

                             EN8[x][y++]=page_buf[j];

                             if(y>=16)   //判断该字库的行的加载范围是否超出

                             {

                                      x++;

                                      y=0;

                             }

                   }

         }

}

    state_16_EN是该字库的加载状态变量,当为1时,表示该字库已经加载,反之为未加载,这样在文字的显示中实现字库的自动加载。同时也不会造成字库的重复加载。变量BaseAddr表示该字库在Nand flash的初始地址。

    整个程序的思路是,首先将状态变量置1,然后循环以页为单位读取字库数据,最后将读取到的数据放入字库定义的二维数组里。

2.2.2 文字的显示

    以下以16*8的ASCII的英文显示为例。

void LcdDriver_S3C2440::PutEN0816(int x,int y,char *ascii_codes)

{

       if(state_16_EN==0) Load_16_8_ASCII();//检查字库加载状态,如果为0,则加载

       uint8 i,j;

 

       for(j=0;j<16;j++)

       {

             data=EN8[*ascii_codes][j];

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

             {

                   if(data&(128>>i)) //如果该点是1,则显示文字的前景色;如果该是0,则显示背景色

                         LCD_write_dot(x+i,y+j,Font.ForeColor);

                   else

                         LCD_write_dot(x+i,y+j,Font.BackColor);

             }

       }

}

    二维数组的使用的便捷性就在这里可以明显地体现出来,每个文字只需要读取其相应的行数据然后调用点绘制方法就行。

    文字显示有两个重要的概念,前景色和背景色,前景色即文字的颜色。在字库的点阵数据中,0表示该点为空,这时就显示背景色;1表示该点要填满,这时就显示前景色。

整个程序的思路是,首先检查状态变量,决定是否进行字库加载,然后循环二维数组里数据,最后将数据进行与操作,判断前景色与背景色并显示在规定的位置上。

    而中文显示与英文显示有些许不同,以下以16*16的宋体汉字的显示为例。

void LcdDriver_S3C2440::PutHZ16(int x,int y,char * ascii_codes)

{

       if(state_16_CN==0)         Load_16_GB2312_Song();

       uint8 i,j,k=0;

       uint8 qh=0,wh=0;

       uint16 offset;

       char *p;

       p=ascii_codes;

       qh = (*p++)-0xA0;  //获得区码      (p[i] && 0xff)     

       wh = *p-0xA0;  ///获得位码              

       offset = (94*(qh-1)+(wh-1));

 

      for(j=0;j<16;j++)

      {

              data1=HZ16[offset][k++];

              data2=HZ16[offset][k++];

              data=(data1<<8)|data2;

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

              {

                   if(data&(32768>>i))

                        LCD_write_dot(x+i,y+j,Font.ForeColor);

                   else

                        LCD_write_dot(x+i,y+j,Font.BackColor);                   

               }

      }

}

    与英文显示相对,中文显示多了区码、位码的处理,以及每个汉字的点阵数据占用的空间变大而进行了相应的处理。

2.2.3 多字体、多字号、多语言混排

void LcdDriver_S3C2440::PutString(int x,int y,char *p)

{

         uint16 i=0,j=0;

         uint16 k;

         uint8 width;

         k=i+x;

         switch(Font.Font_Wrod)  //字号与字符宽度转换

         {

                   case Asic8:width=16;break;

                   case GB16:width=16;break;

                   case GB32:width=32;break;

                   case GB24:width=24;break;

                   case GB12:width=12;break;

         }

         while (*p!='/0') //循环显示文字

         {

                   if((*p)>=128) //如果要显示的文字为汉字

                   {

                            if(320-k<=width) //判断是否需要换行

                            {

                                     j+=width;

                                     k=0;

                            }

                            switch(Font.Font_Wrod) //根据对应的字号转入相应的文字显示方法.

                            {

                                     case GB16:PutHZ16(k,y+j,p) ;break;

                                     case GB24:PutHZ24(k,y+j,p) ;break;

                                     case GB32:PutHZ32(k,y+j,p) ;break;

                            }

                            p+=2;

                            k+=width;

                  }

                  else //如果要显示的文字为英文

                  {

                            if(320-k<=(width/2))   //判断是否需要换行

                            {

                                     j+=width;

                                     k=0;

                            }

                            switch(Font.Font_Wrod) //根据对应的字号转入相应的文字显示方法.

                            {

                                     case Asic8:

                                     case GB16:PutEN0816(k,y+j,p++) ;break;

                                     case GB24:PutEN1224(k,y+j,p++) ;break;

                                     case GB32:PutEN1632(k,y+j,p++) ;break;

                            }

                            k+=width/2;

                            }

         }

}

    整个程序的思路是,首先进行字号与字符宽度进行转换,其次,判断要显示的文字的语言,然后,判断是否达到行末而需要换行,最后,根据对应的语言和字号转入相应的文字显示方法。

对于多字体,还没有完成,这个是可以实现的,只是稍微繁琐一些。

应用与实例

    下面列举相应的代码与图片来更清楚地说明,文字显示中的多字体,多语言混排。

    代码如下:

 

LCD.font.ForeColor=White;

LCD.font.BackColor=0x14DF;

LCD.Font.Font_Wrod=GB24;

LCD.PutString(22,5,"NR嵌入式操作系统");

LCD.Font.Font_Wrod=GB16;

LCD.PutString(32,26,"NR嵌入式操作系统是广东海洋大学嵌入式工作组自主研发的用于嵌入式开发的软件平台,对系统拥有完全的自主知识产权。实际上命名为操作系统有些不合适,因为开发系统综合了操作系统,软件架构,面向对象等技术,从结构上已经很大程度上不同于传统意义上的操作系统,之所以采用这个名称是为了方便使用者学习。");

 

由代码可知,调用只需要先定义前景色、背景色、字号,就可以直接显示出文字,而无需指定语言。

代码相应的显示效果如图1所示

 

基于三星S3C2440的文字显示*

图1 代码相应的显示效果