LCD字符顯示有兩種方式,一個是通過字模提取軟件,將字符轉化成一個字節型的數組,另一個是使用字庫。如果字符較多的時候,直接使用字庫比較方便,F在說一下中英文字符的存儲結構和編碼方式。中英文的字符點陣結構有4*8,8*16,16*16,24*24,32*32,48*48等結構形勢,不同點陣漢字的字體又有宋體,仿宋體,黑體,楷體等之分。在計算機中,相同點陣結構和相同字體的字符存放在同一字庫中。本文使用的是16*16的宋體。16*16的點陣字庫中,字符的信息結構采用以行排列的形式,共有16行,每行有16個點,分別存放在兩個字節內。因此每個字符共占用16*16/2=32個字節。字節的存放順序為從左到右,從上到下。將漢字變成字符模式,使用16*16個像素表示一個漢字。在字模提取的過程中,還要注意取模的順序,順序不同,得到的數組就不同,一般式從左向右,從上到下。取模方式,逐行式。ASCII型字符的寬度是漢字的一半,即8。 #define rGPCCON (*(volatile unsigned *)0x56000020) #define rGPCUP (*(volatile unsigned *)0x56000028) #define rGPDCON (*(volatile unsigned *)0x56000030) #define rGPDUP (*(volatile unsigned *)0x56000038) #define rLCDCON1 (*(volatile unsigned *)0x4d000000) #define rLCDCON2 (*(volatile unsigned *)0x4d000004) #define rLCDCON3 (*(volatile unsigned *)0x4d000008) #define rLCDCON4 (*(volatile unsigned *)0x4d00000c) #define rLCDCON5 (*(volatile unsigned *)0x4d000010) #define rLCDSADDR1 (*(volatile unsigned *)0x4d000014) #define rLCDSADDR2 (*(volatile unsigned *)0x4d000018) #define rLCDSADDR3 (*(volatile unsigned *)0x4d00001c) #define rLCDINTMSK (*(volatile unsigned *)0x4d00005c) #define rTPAL (*(volatile unsigned *)0x4d000050) #define rGPGCON (*(volatile unsigned *)0x56000060) //Port G control #define rGPGDAT (*(volatile unsigned *)0x56000064) //Port G data #define rGPGUP (*(volatile unsigned *)0x56000068) //Pull-up control G #define rLCDINTMSK (*(volatile unsigned *)0x4d00005c) #define rTCONSEL (*(volatile unsigned *)0x4d000060) //LPC3600 Control --- edited by junon //垂直同步信號的脈寬、后肩和前肩 #define VSPW 15 #define VBPD 3 #define VFPD 5 //水平同步信號的脈寬、后肩和前肩 #define HSPW 8 #define HBPD 58 #define HFPD 15 #define CLKVAL 10 #define HOZVAL 319 #define LINEVAL 239 #define PWREN 1 #define MMODE 0 #define PNRMODE 3 #define BPPMODE 13 #define INVVCLK 0 #define INVVD 0 #define INVVDEN 0 #define U32 unsigned int #define M5D(n) ((n) & 0x1fffff) #define PAGEWIDTH 320 #define OFFSIZE 0 #define LCD_XSIZE 320 #define LCD_YSIZE 240 #define SCR_XSIZE 320 #define SCR_YSIZE 240 #define INVVLINE 1 #define INVVFRAME 1 #define BPP24BL 0 #define BSWP 0 #define HWSWP 0 volatile U32 LCD_BUFFER[240][320]; unsigned char li[]={ 0x01,0x00,0x01,0x00,0x7F,0xFC,0x03,0x80,0x05,0x40,0x09,0x30,0x31,0x0E,0xDF,0xE4, 0x00,0x80,0x01,0x00,0x7F,0xFE,0x01,0x00,0x01,0x00,0x01,0x00,0x05,0x00,0x02,0x00}; //"李",0 unsigned char wan[]={ 0x00,0x00,0x7F,0xFE,0x02,0x00,0x02,0x00,0x02,0x10,0x03,0xF8,0x02,0x10,0x04,0x10, 0x04,0x10,0x04,0x10,0x08,0x10,0x08,0x10,0x10,0x10,0x20,0xE0,0x40,0x40,0x00,0x00}; //"萬",1 unsigned char peng[]={ 0x00,0x10,0x77,0x20,0x55,0x7C,0x55,0x64,0x77,0x54,0x55,0x54,0x55,0x4C,0x55,0x40, 0x77,0x7E,0x55,0x02,0x55,0x02,0x55,0xFA,0x55,0x02,0xB9,0x14,0x13,0x08,0x00,0x00}; //"鵬",2 unsigned char L[]={0X00,0X00,0X00,0XE0,0X40,0X40,0X40,0X40,0X40,0X40,0X40,0X40,0X42,0XFE,0X00,0X00}; //L unsigned char I[]={0X00,0X00,0X00,0X7C,0X10,0X10,0X10,0X10,0X10,0X10,0X10,0X10,0X10,0X7C,0X00,0X00}; //I unsigned char N[]={0X00,0X00,0X00,0XC7,0X62,0X62,0X52,0X52,0X4A,0X4A,0X4A,0X46,0X46,0XE2,0X00,0X00}; //N unsigned char U[]={0X00,0X00,0X00,0XE7,0X42,0X42,0X42,0X42,0X42,0X42,0X42,0X42,0X42,0X3C,0X00,0X00}; //U unsigned char X[]={0X00,0X00,0X00,0XE7,0X42,0X24,0X24,0X18,0X18,0X18,0X24,0X24,0X42,0XE7,0X00,0X00}; //X unsigned char AND[]={0X00,0X00,0X00,0X30,0X48,0X48,0X48,0X50,0X6E,0XA4,0X94,0X88,0X89,0X76,0X00,0X00}; //& unsigned char A[]={0X00,0X00,0X00,0X10,0X10,0X18,0X28,0X28,0X24,0X3C,0X44,0X42,0X42,0XE7,0X00,0X00}; //A unsigned char R[]={0X00,0X00,0X00,0XFC,0X42,0X42,0X42,0X7C,0X48,0X48,0X44,0X44,0X42,0XE3,0X00,0X00}; //R unsigned char M[]={0X00,0X00,0X00,0XEE,0X6C,0X6C,0X6C,0X6C,0X54,0X54,0X54,0X54,0X54,0XD6,0X00,0X00}; //M void Init_LCD(){ rLCDCON1=(CLKVAL<<8)|(MMODE<<7)|(PNRMODE<<5)|(BPPMODE<<1)|0; //設置CLKVAL,VCLK=HCLK/[(CLKVAL+1)*2],決定VM的觸發方式,選擇顯示模式和BPP模式,暫時不要開啟LCD,因為還沒有設置好 rLCDCON2=(VBPD<<24)|(LINEVAL<<14)|(VFPD<<6)|(VSPW); //rLCDCON2,rLCDCON3和rLCDCON4主要設置時序 rLCDCON3=(HBPD<<19)|(HOZVAL<<8)|(HFPD); rLCDCON4=(HSPW); rLCDCON5 = (BPP24BL<<12) | (INVVCLK<<10) | (INVVLINE<<9) | (INVVFRAME<<8) | (0<<7) | (INVVDEN<<6) | (PWREN<<3) |(BSWP<<1) | (HWSWP); //INVVLINE和INVVFRAME需要進行翻轉,因為CPU發出的是正脈沖,LCD使用的是負脈沖,所以要改變極性,PWREN使能電源信號 rLCDSADDR1=(((U32)LCD_BUFFER>>22)<<21)|M5D((U32)LCD_BUFFER>>1); rLCDSADDR2=M5D(((U32)LCD_BUFFER+(SCR_XSIZE*SCR_YSIZE*4))>>1 ); rLCDSADDR3=PAGEWIDTH*32/16; rLCDINTMSK|=(3); rTCONSEL = 0; rGPCUP = 0x0; rGPDCON = 0xaaaaaaaa; rGPCCON = 0xaaaa02a9; rGPDUP = 0x0; rGPGUP=rGPGUP&("(1<<4))|(1<<4); rGPGCON=rGPGCON&("(3<<8))|(3<<8); rLCDCON1 |= 1; //使能數據輸出和LCD控制信號 } void Paint_text(U32 x, U32 y, U32 color, unsigned char ch[]){ int i, j, test, s, t = 0; for(i = 0; i < 16; i++){ test = 0x80; for(j = 0; j < 16; j++){ if(j == 8){ test = 0x80; t++; } if(ch[t] & test) LCD_BUFFER[x+i][y+j] = color; test >>= 1; } t++; } } void Paint_text_8(U32 x, U32 y, U32 color, unsigned char ch[]){ int i, j, test; for(i = 0; i < 16; i++){ test = 0x80; for(j = 0; j < 8; j++){ if(test & ch[ i]) LCD_BUFFER[x+i][y+j] = color; test >>= 1; } } } void Paint_background(U32 c){ unsigned int i, j; for(j = 0; j < LCD_YSIZE; j++) for(i = 0; i < LCD_XSIZE; i++) LCD_BUFFER[j][ i] = c; } int LcdMain(){ Init_LCD(); Paint_background(0xFFFFFF); Paint_text(100,100,0x000000,li); Paint_text(100,116,0x000000,wan); Paint_text(100,132,0x000000,peng); Paint_text_8(116,100,0x000000,L); Paint_text_8(116,108,0x000000,I); Paint_text_8(116,116,0x000000,N); Paint_text_8(116,124,0x000000,U); Paint_text_8(116,132,0x000000,X); Paint_text_8(116,140,0x000000,AND); Paint_text_8(116,148,0x000000,A); Paint_text_8(116,156,0x000000,R); Paint_text_8(116,164,0x000000,M); while(1); } 如果使用字庫,每個漢字的地址由兩個字節表示。一個是區號,一個是區中的位置,即位號。16*16的點陣字庫中,每個字符占32個字節,每94個字符為一個區,共87個區,其中1"15區為常用符號區(包括數字0"9及大小寫英文字母),16"86為常用漢字,其排列是以漢語拼音為序,從一聲到四聲,第87區為生僻漢字。漢字的起始地址是0xA1A1,A1+94=255,所以一個區有94個字符。區和位的起始號都是1,數組是從0開始,所以如果想在字庫中定位一個字符,(94*(qu-1)+wei)*32。如果中文字符和ASCII碼混合在一樣,如何區分它們呢?其實也很簡單,ASCII碼的最高位是0,而中文的最高位是1,因此當讀取到的一個字節的最高位是0,則該字節為ASCII碼,它的下一個字節與這個字節無關;當取得到的字節的最高位是1,則表示的是中文字符,并且該字節與它的下一個字節組合在一起表示完整的一個漢字。 #include "Font_Libs.h" #define rGPCCON (*(volatile unsigned *)0x56000020) #define rGPCUP (*(volatile unsigned *)0x56000028) #define rGPDCON (*(volatile unsigned *)0x56000030) #define rGPDUP (*(volatile unsigned *)0x56000038) #define rLCDCON1 (*(volatile unsigned *)0x4d000000) #define rLCDCON2 (*(volatile unsigned *)0x4d000004) #define rLCDCON3 (*(volatile unsigned *)0x4d000008) #define rLCDCON4 (*(volatile unsigned *)0x4d00000c) #define rLCDCON5 (*(volatile unsigned *)0x4d000010) #define rLCDSADDR1 (*(volatile unsigned *)0x4d000014) #define rLCDSADDR2 (*(volatile unsigned *)0x4d000018) #define rLCDSADDR3 (*(volatile unsigned *)0x4d00001c) #define rLCDINTMSK (*(volatile unsigned *)0x4d00005c) #define rTPAL (*(volatile unsigned *)0x4d000050) #define rGPGCON (*(volatile unsigned *)0x56000060) //Port G control #define rGPGDAT (*(volatile unsigned *)0x56000064) //Port G data #define rGPGUP (*(volatile unsigned *)0x56000068) //Pull-up control G #define rLCDINTMSK (*(volatile unsigned *)0x4d00005c) #define rTCONSEL (*(volatile unsigned *)0x4d000060) //LPC3600 Control --- edited by junon //垂直同步信號的脈寬、后肩和前肩 #define VSPW 15 #define VBPD 3 #define VFPD 5 //水平同步信號的脈寬、后肩和前肩 #define HSPW 8 #define HBPD 58 #define HFPD 15 #define CLKVAL 10 #define HOZVAL 319 #define LINEVAL 239 #define PWREN 1 #define MMODE 0 #define PNRMODE 3 #define BPPMODE 13 #define INVVCLK 0 #define INVVD 0 #define INVVDEN 0 #define U32 unsigned int #define M5D(n) ((n) & 0x1fffff) #define PAGEWIDTH 320 #define OFFSIZE 0 #define LCD_XSIZE 320 #define LCD_YSIZE 240 #define SCR_XSIZE 320 #define SCR_YSIZE 240 #define INVVLINE 1 #define INVVFRAME 1 #define BPP24BL 0 #define BSWP 0 #define HWSWP 0 volatile U32 LCD_BUFFER[240][320]; void Init_LCD(){ rLCDCON1=(CLKVAL<<8)|(MMODE<<7)|(PNRMODE<<5)|(BPPMODE<<1)|0; //設置CLKVAL,VCLK=HCLK/[(CLKVAL+1)*2],決定VM的觸發方式,選擇顯示模式和BPP模式,暫時不要開啟LCD,因為還沒有設置好 rLCDCON2=(VBPD<<24)|(LINEVAL<<14)|(VFPD<<6)|(VSPW); //rLCDCON2,rLCDCON3和rLCDCON4主要設置時序 rLCDCON3=(HBPD<<19)|(HOZVAL<<8)|(HFPD); rLCDCON4=(HSPW); rLCDCON5 = (BPP24BL<<12) | (INVVCLK<<10) | (INVVLINE<<9) | (INVVFRAME<<8) | (0<<7) | (INVVDEN<<6) | (PWREN<<3) |(BSWP<<1) | (HWSWP); //INVVLINE和INVVFRAME需要進行翻轉,因為CPU發出的是正脈沖,LCD使用的是負脈沖,所以要改變極性,PWREN使能電源信號 rLCDSADDR1=(((U32)LCD_BUFFER>>22)<<21)|M5D((U32)LCD_BUFFER>>1); rLCDSADDR2=M5D(((U32)LCD_BUFFER+(SCR_XSIZE*SCR_YSIZE*4))>>1 ); rLCDSADDR3=PAGEWIDTH*32/16; rLCDINTMSK|=(3); rTCONSEL = 0; rGPCUP = 0x0; rGPDCON = 0xaaaaaaaa; rGPCCON = 0xaaaa02a9; rGPDUP = 0x0; rGPGUP=rGPGUP&("(1<<4))|(1<<4); rGPGCON=rGPGCON&("(3<<8))|(3<<8); rLCDCON1 |= 1; //使能數據輸出和LCD控制信號 } void Paint_text16(U32 x, U32 y, U32 color, unsigned char ch[]){ int i, j, test, t = 0; for(i = 0; i < 16; i++){ test = 0x80; for(j = 0; j < 16; j++){ if(j == 8){ test = 0x80; t++; } if(ch[t] & test) LCD_BUFFER[x+i][y+j] = color; test >>= 1; } t++; } } void Paint_Ascii(U32 x, U32 y, U32 color, unsigned char ch[]){ int i, j, test; for(i = 0; i < 16; i++){ test = 0x80; for(j = 0; j < 8; j++){ if(test & ch[ i]) LCD_BUFFER[x+i][y+j] = color; test >>= 1; } } } void Paint_background(U32 c){ unsigned int i, j; for(j = 0; j < LCD_YSIZE; j++) for(i = 0; i < LCD_XSIZE; i++) LCD_BUFFER[j][ i] = c; } int LcdMain(){ int qu, wei, i, test = 0x80, t; unsigned char * head; unsigned char fuck[] = "李萬鵬專注于linux+arm"; Init_LCD(); Paint_background(0xFFFFFF); for(i = 0,t = 0; i < sizeof(fuck); i++){ if(test & fuck[ i]){ qu = fuck[ i] - 0xA0; wei = fuck[i+1] - 0xA0; head = &__HZK[((qu-1)*94+wei-1)*32]; Paint_text16(100, 100+t*16, 0x000000, head); i++; } else{ head = &__ASCII[fuck[ i]*16]; Paint_Ascii(100, 100+i*8 , 0x000000, head); } t++; } while(1); } 李萬鵬 |