基於三星S3C2440的文字顯示 【轉載】

基於三星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 代碼相應的顯示效果

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章