天天看點

LCD-中文顯示-超級菜鳥版

      液晶是什麼?字模是什麼?GBK是什麼?gram是什麼?HZK16是什麼?bin是什麼?漢字内碼是什麼?UNICODE又是什麼?..

      液晶真是小東西大學問,我是道地的門外漢,一塊液晶,一個開發闆,顯示一個中文字,連個例也沒有,好在有網絡,從一篇文章裡遇到一堆聽都沒聽過的專業詞彙,然後在從查找這些詞彙的過程中遇到更多的詞彙,真是張見識了。

      感覺接觸一個新事物,難度不在它本身的技術有多複雜,再高深的技術都是靠千千萬萬個邏輯組建起來的,隻要靜下心來理,總是能理出點頭緒的。倒是一點概念都沒有的時候最惶惑。而這個階段的超級菜鳥也是舉步維艱的,很多資料文章都看不懂(不是似懂非懂,是一點都不懂~~),而一般人又沒時間給超級菜鳥把一個個基礎的概念解釋清楚,更郁悶的是,市面上,海一般的教程資料又不一定合用。最終求助無門,要麼望而怯步,放棄,要麼硬啃。好在隻要是有邏輯的東西,都是能啃的,雖然不好消化,但是絕對比别人告訴自己來得深刻,而且能培養探索新事物的能力。(當然,有時時間緊迫,不容許慢慢消化,還是趕緊求助好心高人的好。)

      據說,液晶帶中文字庫能顯示中文,那不帶中文字庫怎麼顯示啊?字庫又長什麼樣呢?

static u8 GBK16[32];

unsigned char *Read_One_GBK16(unsigned char *ch)

{

   unsigned int  temp1;

   unsigned char temp2;

   unsigned char *p;

   p=&GBK16[0];

   temp1=*ch;

   temp2=*(ch+1); //有個快典網http://bm.kdd.cc/ 能查,查到“歌”字GBK碼為:0XB8E8,正好兩個位元組。

// if(temp1<0x81||temp2<0x40)return 1;//不合法的漢字

   temp1-=0xa0;                                     //計算漢字區碼 //不懂

   temp2-=0xa0;                                 //計算漢字位碼

   temp1=((INT32U)(94*(temp1-1)+(temp2-1)))*32;     //計算漢字在字庫中的偏移位址

 //  sector_offset = temp1/(512/32);//算出要讀哪個扇區  933

 // byte_offset = (temp1%(512/32))*32;//算出要讀扇區的哪個位元組 //更不懂了

   f_open(&fii,"sys/HZK16.bin", FA_OPEN_EXISTING | FA_READ); //f_open打開了一個“HZK16.bin”的檔案啥東東~

   f_lseek(&fii,temp1);

   f_read(&fii, GBK16, 32, &br);

   f_close(&fii); 

//   GBK_Buffer=buffer;

   return p;

}

“Read_One_GBK16”--“讀一個GBK”同類的還有unsigned char *Read_One_GBK32(unsigned char *ch),

unsigned char *Read_One_GBK12(unsigned char *ch),

WCHAR *GBKTOUnicode(unsigned char *ch,啥是GBK啊?

百科說:“GBK: 漢字國标擴充碼,基本上采用了原來GB2312-80所有的漢字及碼位,并涵蓋了原Unicode中所有的漢字20902,總共收錄了883個符号, 21003個漢字及提供了1894個造字碼位。 Microsoft簡體版中文Windows 95就是以GBK為内碼,又由于GBK同時也涵蓋了Unicode所有CJK漢字,是以也可以和Unicode做一一對應。”

( 是不是可以了解為GBK是漢字在庫中的一個編号?)

bin:百科說:“ bin (binary)其中文意思既是:二進制,二進制檔案,其用途依系統或應用而定 。

  也就是說,一般來講是機器代碼,彙編語言編譯後的結果,(DOS下彙編語言編譯後與.com檔案相類似),用debug、WINHEX,U_EDIT等軟體打開(通常不一定能看得懂是些什麼除非精通彙編語言)

  所有的檔案, 無論字尾名是什麼, 一律分為兩種格式. text 和 binary.

  一種檔案格式binary的縮寫。一個字尾名為.bin的檔案, 隻是想表明它是binary格式.,但并不表明它與某種應用程式有必然的聯系性”

(下了一個WINHEX,的确能打開^^,原來每個字對應的就是一堆數組,用網上下載下傳的字模生成工具,生成也是一樣的)

網友說:“以指定的方式建立字庫 字庫分3類

(1) 常用可見ASCII字 0-9, A-Z及a-z,各種符号*#?()等 數字字庫0-9 ,這是XY長度為6*8點的

(2) 半角字元 0-9,A-Z 也是我們常用的數字和英文字元顯示方式,占半個漢字大小,是8*16點。半角字元,就是指占漢字一一半大小

(3) 漢字字庫常用HZK16(6763個漢字) 顯然這是16*16的, 标準的全角字元

一般應用不建議采用第(1)項來顯示數字與字母,一是字型太小,二是不便于和漢字混排,不好對齊。”

那這樣就明了了,沒有字庫的話隻要用工具(比如PCtoLCD2002.exe)把具體的字的“字模”(就是點點排成的數組),給函數,就不用上面的函數讀庫裡的GBK了。(工具要選好,不然摸半天都摸不出來)

 },/*"歌"字,16*16*/

u8 song[]= {0x01,0x00,0x5D,0x78,0x55,0x48,0x55,0x48,0x5D,0x7A,0x41,0x01,0x7F,0xFE,0x45,0x02,

0x09,0x04,0x30,0x18,0xD7,0xE0,0x10,0x10,0x14,0x0C,0x18,0x07,0x10,0x02,0x00,0x00}

void Lcd_WriteChinese(u8 x,u8 y,u16 x_offset,u16 y_offset,u16 CharColor,u16 CharBackColor,u8 *ChineseCode,u8 mode)

{

  u8 ByteCounter,BitCounter;   

  u8 *ChinesePointer;

  Lcd_SetBox(x*16,y*16,16,16,x_offset,y_offset);        

  Lcd_WR_Start();

  ChinesePointer=Read_One_GBK16(ChineseCode); //這裡用改為:ChinesePointer=&song[0];就可以用了。

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

//這裡連續寫入了32個位元組,那掃描應該是橫掃了,而不是下面說的先上半個後下半個,生成字模的時候要注意。

  {

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

    {

      if((*ChinesePointer & (0x80 >> BitCounter)) == 0x00)

      {

       Set_Rs;

  if(!mode)

  {

      GPIOx->ODR = CharBackColor;//DataToWrite(CharBackColor);

        Clr_nWr;

        Set_nWr;

  }

      }

      else

       GPIOx->ODR =CharColor;  //DataToWrite(CharColor);

      }    

    }

    ChinesePointer++;

  }

  Set_Cs; 

}

還有個問題,就是數組的存儲方式,寄存器存儲方式,液晶的掃描方式,怎一個亂字了得~~

以下來自http://www.ourdev.cn的huasoft網友的文章:

取出漢字字庫向LCD寫屏的方式

液晶NOKIA5110的X,Y概念及寫屏方式:

液晶5110由84點*48點組成。 可以看到,最多顯示的半角字元是10*6個, 最多顯示的漢字是5*3個

液晶5110的規格書上是這樣描述它的寫入坐标概念的,首先,每次寫入指令是寫一個豎着的8個bit即一個位元組,這是它的一個最基本的寫入元單元。(寫入時先寫高位,這一點對掌握整體概念不重要,先不讨論)。以這樣的元單元為計數,螢幕整個被分成了84*6 個這樣的元單元。

NOKIA5110的LCD的XY坐标概念

寫入一個漢字“一”,字模如下

/*--  文字:  一  --*/

/*--  宋體12;  此字型下對應的點陣為:寬x高=16x16   --*/

0x00,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0xC0,0x80,0x00,

0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,

寫入過程的函數一般是這樣的:

LCD_set_XY(row*8, page);// 列,頁 

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

LCD_write_byte(pgm_read_byte(hanzi+c*32+i),1); 

    LCD_set_XY(row*8, page+1);// 列,頁 

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

LCD_write_byte(pgm_read_byte(hanzi+c*32+i),1);

寫入示意圖如下:

NOKIA5110LCD寫入漢字一的過程

 好了,現在問題來了,HZK16和 我們在5110LCD上用的字庫是不同的組織方式,一個先行後列, 一個先上半部後下半部。如何轉換?

 (我就顯示一個字,直接用工具改字模更友善~這裡學習下前輩改掃描方式的程式)

-----------------------------------------------------------

為了讓NOKIA5110直接用hzk16字庫形式而不需要轉換, 我們直接把hzk16轉成适合Nokia5110的掃描方式,

關鍵代碼段

//>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

//2.将标準hzk16.bin的16*16的先行後列字模轉換成NOKIA5110屏用的先刷漢字上半部分16列,再刷下半部分16列的方式(見文檔)

//add hzk16fornokia5110.bin write routine here

FILE *HZK1 = 0, *HZK2 = 0;

unsigned long offset1 = 0, offset2 =0;

if((HZK1=fopen("hzk16.bin", "rb")) == NULL)  

{  

printf("Can't Open hzk16.bin/n");  

getchar(); 

return 0; 

}  

if((HZK2=fopen("hzk16fornokia5110.bin", "wb")) == NULL)  

printf("Can't Open hzk16fornokia5110.bin/n");  

offset1=0;

unsigned char mat1[2][16],mat2[2][16];

//int i,j,k,m;

while( !feof(HZK1) )

fseek(HZK1, offset1, SEEK_SET);

fread(mat1, 32, 1, HZK1); 

//mat1-->mat2

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

  {

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

  for(k=0;k<8;k++) //bit

//mat2[0][j].bit[k]= mat1[0][j*2].bit[7-k];

if( bit_isset(mat1[i][k*2],(7-j))==1 )

bit_set(mat2[i][j],k);

else

bit_clr(mat2[i][j],k);

  }

//mat2[0][j+8].bit[k]= mat1[0][j*2+1].bit[7-k];

if( bit_isset(mat1[i][k*2+1],(7-j))==1)

bit_set(mat2[i][j+8],k);

bit_clr(mat2[i][j+8],k);

  }//for(i=0;i<2;i++)

//write mat2

printf("write offset: %ld/n",offset1);

fseek(HZK2, offset1, SEEK_SET);

fwrite(mat2,32,1,HZK2);

offset1+=32;

}//while

printf("I find the feof()!=0!/n");

fclose(HZK1); 

fclose(HZK2);

//<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<

 在函數裡Lcd_WriteChinese用到Lcd_SetBox(x*16,y*16,16,16,x_offset,y_offset) ,内容如下,        

 void Lcd_SetBox(u8 xStart,u16 yStart,u8 xLong,u16 yLong,u16 x_offset,u16 y_offset)

#if ID_AM==000   

 Lcd_SetCursor(xStart+xLong-1+x_offset,yStart+yLong-1+y_offset);

#elif ID_AM==001

#elif ID_AM==010

 Lcd_SetCursor(xStart+x_offset,yStart+yLong-1+y_offset);

#elif ID_AM==011

#elif ID_AM==100

 Lcd_SetCursor(xStart+xLong-1+x_offset,yStart+y_offset);    

#elif ID_AM==101

#elif ID_AM==110

 Lcd_SetCursor(xStart+x_offset,yStart+y_offset);

#elif ID_AM==111

 Lcd_SetCursor(xStart+x_offset,yStart+y_offset); 

#endif

 LCD_WR_REG(0x0050,xStart+x_offset);//水準 GRAM起始位置

 LCD_WR_REG(0x0051,xStart+xLong-1+x_offset);//水準GRAM終止位置

 LCD_WR_REG(0x0052,yStart+y_offset);//垂直GRAM起始位置

 LCD_WR_REG(0x0053,yStart+yLong-1+y_offset);//垂直GRAM終止位置

void Lcd_SetCursor(u8 x,u16 y)

 LCD_WR_REG(0x20,x);

 LCD_WR_REG(0x21,y);   

函數名:Lcd塊選函數

功能:標明Lcd上指定的矩形區域

應該是控制顯示區域和定位的吧,現在漢字已經可以顯示了,但是,是從右到左,而且x軸y軸混了,改了一下也沒成功,咋整啊~~

好像位圖顯示也是鏡像的,什麼原因呢?~~

可以把字庫和位圖放在sd卡裡,液晶從裡面讀不?跟gram有什麼關系啊?(gram是什麼~)

ILI9325是什麼?跟用軟體從屏中讀出來的DeviceCode有什麼關系呢?

液晶定時變暗,然後關閉,看屏的時候再用按鍵喚醒,跟手機螢幕一樣,能麼?

好像觸摸屏這塊兒也挺龐大的~

問題多多啊,菜鳥的道路很艱辛,但也很充實,菜并快樂着~

繼續閱讀