1、lcd裸機寫好後在來弄lcd的字符顯示就容易多了,理解字符其實就是一副圖,比如16*16的漢子顯示就是長寬16的一個正方形中用點來顯示一個漢字,這樣就只有弄清楚哪些點是要顯示的就行了,比如第一行要顯示一個點我們就可以 xxxxxxxoxxxxxxxx 現在只有把中間的圈顯示其他的不顯示這個點就出來了,那好我們就可以用一個數組來保存哪些是要顯示的點,每一位表示是否要顯示,當然這一位要顯示什麼顏色就是前面lcd的內容了。這裏只是說明這個點要不要顯示的問題,具體用什麼顏色顯示是可以設置的。
2、對於字模數組的提取現在已經有很多好用的字模提取軟件,字庫軟件的,到網上搜一個然後就很容易了,只要輸入想要顯示的漢字軟件就幫你把字模的數組顯示好了,你只有把這個字模數組放到程序當中去就可以了。當然這裏要注意字模提取的順序,還有有些字模軟件中可以設置要不要倒序的問題,這裏我用的是 ZIMO221.EXE 這個軟件,我的lcd的取模方式是 橫向取模,字節不倒序,C51格式 ,當然要是有很多漢字要顯示的話一個一個字去提取就不容易了,現在已經有人或者有一些標準已經把漢字弄成了一些字庫,像16*16的話就標準庫GB2312 ,但是注意,這些庫好像要麼是沒有後綴名要麼是數據庫形式,對於裸機還是比較不方便,這裏的話可以去找一下有人把這些做成了C語言數組形式這樣就比較好用了,不過這樣有點佔內存,16*16 / 8 = 32 就是一個字佔32個字節,常用漢字字符庫的話一般有6 7千個,那麼簡單算一下應該就需要差不多200k的內存,對於單片機來說還是比較難以消化的。
3、有了字庫我們就只需要找個我們需要的漢字然後取出來顯示就好了,但是怎麼找這麼漢字,當然這麼問題別人早已經解決了,首先對於漢字用倆個字節來編碼的這一點要明白,然後GB2312將代碼表分爲94個區,對應第一字節(0xa1-0xfe);每個區94個位(0xa1-0xfe),對應第二字節,兩個字節的值分別爲區號值和位號值加32(2OH),因此也稱爲區位碼。01-09區爲符號、數字區,16-87區爲漢字區(0xb0-0xf7),10-15區、88-94區是有待進一步標準化的空白區。GB2312將收錄的漢字分成兩級:第一級是常用漢字計3755個,置於16-55區,按漢語拼音字母/筆形順序排列;第二級漢字是次常用漢字計3008個,置於56-87區,按部首/筆畫順序排列。故而GB2312最多能表示6763個漢字。這樣我們查找漢字是就比較方便了,首先我們通過區號找個是屬於哪個區,然後再通過位號找個屬於哪個位就可以找到漢字了,注意上面說的區號值和位號值加32(2OH)纔是分別對於編碼漢字的倆個字節值,然後還有一點那就是找到位號後,因爲一個漢字佔32個字節,所以最後的索引位置還有乘以32,最後漢字在字庫中的位置[94×區號+位號]×32 。
4、我們瞭解了上面的字庫知識後還有一個問題,那是我們不是直接使用字庫,而是把字庫中的漢字提取出來做成了數組,這裏存在倆個問題,一是,數組的索引是從0開始的,而字庫是從1開始,所以索引的時候需要減1;二是有時候只需要用到漢字所以做成的數組就會把前面的字符去掉,或者我們手上只有漢字字庫的數組的時候我們就要注意,這裏因爲前面去掉了字符和一些空的內容,索引值應該從第16個區開始,前面去掉了15個區,15個區,每個區94個位,15 x 94 = 1410 所以我們索引到時候還需要減去1410個位,得到的最後的索引就是[( 94*(qh-1)+(wh-1) -1410 )*32] ,qh 是區號 ,wh 是位號 。如果沒有去掉前面15個區的內容的話那麼索引就是 [94×(區號-1)+(位號-1)]×32 綜合前面得到的區號和位號就可以得到字庫的位置了。GB2312的編碼範圍爲2121H-777EH,與ASCII有重疊,通行方法是將GB碼兩個字節的最高位置1以示區別。
代碼:
/*************************************************
file name LCD_hanzi
function 顯示16*16漢字 和 16*8 ASCII碼字符
硬件設備 mini2440開發板
索尼X-35 3.5寸液晶屏
lcd參數 寬和高 240x320
TFT 16bpp顯示
完成時間 2011-08-10
作者 周茂夫
problem 暫無
修改記錄 暫無
*************************************************/
#define GLOBAL_CLK 1
#include <stdlib.h>
#include <string.h>
#include "def.h"
#include "option.h"
#include "2440addr.h"
#include "2440lib.h"
#include "2440slib.h"
#include "mmu.h"
#include "profile.h"
#include "memtest.h"
#include "zifu.h"
#define baudrate 115200
#define LCD_WIDTH 240
#define LCD_HEIGHT 320
//#define LCD_CLKCAL 17 //這個我計算出來是17參考程序給的是4 測試倆個都可以
//影響不大 測試25 30 都還可以
#define LCD_CLKCAL 17
#define LCD_RIGHT_MARGIN 25
#define LCD_LEFT_MARGIN 0
#define LCD_HSYNC_LEN 4
#define LCD_UPPER_MARGIN 0
#define LCD_LOWER_MARGIN 4
#define LCD_VSYNC_LEN 9
#define LCD_XSIZE LCD_WIDTH
#define LCD_YSIZE LCD_HEIGHT
#define SCR_XSIZE LCD_WIDTH
#define SCR_YSIZE LCD_HEIGHT
extern const unsigned char sunflower_240x320[] ;
extern const unsigned char GB2312Dot16X16[] ;
volatile static unsigned short LCD_BUFFER[SCR_YSIZE][SCR_XSIZE] ; //LCD BUFFER
#define M5D(n) ((n)&0x1fffff) //設置顯示緩存區時取地址的低21位
#define LCD_ADDR ((U32)(LCD_BUFFER))
/********橫向取模,字節不倒序,C51格式 *******/
unsigned char zhou[] =
{
0x00,0x00,0x1F,0xFC,0x10,0x84,0x13,0xE4,0x10,0x84,0x10,0x84,0x17,0xF4,0x10,0x04,
0x13,0xE4,0x12,0x24,0x12,0x24,0x13,0xE4,0x22,0x24,0x20,0x04,0x40,0x14,0x80,0x08,
} ;
unsigned char mao[] =
{
0x04,0x40,0x04,0x40,0xFF,0xFE,0x04,0x40,0x00,0xA0,0x00,0x90,0x3F,0xFE,0x20,0x80,
0x20,0x84,0x20,0x48,0x20,0x50,0x20,0x60,0x20,0xA0,0x43,0x12,0x4C,0x0A,0x80,0x04,
} ;
unsigned char Y[] =
{
0x00,0x00,0x00,0xEE,0x44,0x44,0x28,0x28,0x10,0x10,0x10,0x10,0x10,0x38,0x00,0x00,
} ;
unsigned char zhao[] =
{
0x00,0x00, 0xF7,0x7E, 0x95,0x04, 0x95,0x04,
0x96,0x74, 0x96,0x54, 0x95,0x54, 0x95,0x54,
0x95,0x54, 0xF5,0x54, 0x97,0x74, 0x04,0x04,
0x04,0x04, 0x04,0x04, 0x04,0x14, 0x04,0x08,
} ;
/**********************************
void delay(int times)
{
int i = 1000 ;
while(times--)
{
for(; i>0; --i)
;
}
}
************************************/
/***********************************
UART_int初始化led IO端口GPBCON5-8
初始化GPBHCON爲串口通信
配置串口通信寄存器
配置中斷寄存器
************************************/
void UART_int_init(void)
{
/********configuration LED IO port**********/
rGPBCON &= ~(0xff<<10) ;
rGPBCON |= 0x55<<10 ;
/*******configuration GPHCON to UART*******/
rGPHCON &= ~(0xf<<4) ;
rGPHCON |= 0xa<<4 ;
/****configuration UART0 communication register******/
rULCON0 = 0x03 ; //8-bits,1 stop bit, no parity
rUCON0 = 0x05 ;
rUBRDIV0= (int)(PCLK/baudrate/16) -1 ; //configuration UART baudrate
/*****clean interrupt bit clea RX_INT******/
rSUBSRCPND |= 0x1 ;
rSRCPND |= 1<<28 ;
rINTPND |= 1<<28 ;
/******open UART interrupt*********/
rINTSUBMSK &= ~(0x1) ;
rINTMSK &= ~(0x1<<28) ;
}
//UART send byte
void UART_send_byte(char Tx_data)
{
while(!(rUTRSTAT0&0x2)) ;//wait Tx empty
if(Tx_data == '\n') //Tx '\n'
{
rUTXH0 = 0x0d ;
while(!(rUTRSTAT0&0x2)) ;
rUTXH0 = 0x0a ;
}
else
{
rUTXH0 = Tx_data ;
}
}
//UART send string
void UART_send_string(const char *str)
{
while(*str)
{
UART_send_byte(*str) ;
str++ ;
}
}
//UART receive byte
void UART_receive_byte(void)
{
char temp ;
while(!(rUTRSTAT0&0x1)) ; //wait RX ready
temp = rURXH0 ;
switch(temp) //測試發送單個字符
{
case 's': rGPBDAT &= ~(0xf<<5) ; break ;
case 'p': rGPBDAT |= (0xf<<5) ; break ;
}
UART_send_byte(temp) ;
}
/*******************************************
中斷處理函數
置1清除中斷,注意順序,先子中斷後父中斷
點亮led燈
********************************************/
void __irq UART0_interrupt(void)
{
/******clean interrupt bit*************/
rSUBSRCPND |= 0x1 ;
rSRCPND |= 1<<28 ;
rINTPND |= 1<<28 ;
rGPBDAT &= ~(0xf<<5) ; //lighten led
UART_receive_byte();
}
/****************************************************************
function initialize LCD IO port VD[0:15] VM VLINE VCLK VFREAM
input void
return void
*****************************************************************/
static void Lcd_port_init(void)
{
rGPCUP = 0xffffffff ; //Disable Pull-up register
rGPCCON = 0xaaaa02a8 ; //Initialize VD[7:0],VM,VFREAM,VLINE,VCLK
rGPDUP = 0xffffffff ; //Disable Pull-up register
rGPDCON = 0xaaaaaaaa ; //Initialize VD[15:8]
}
/****************************************************************
function configarution LCDCON1-5 LCDSADDR1-3 LCD INTERRUPT TPAL
etc register TFT 16bpp
input void
return void
*****************************************************************/
static void Lcd_init(void)
{
rLCDCON1 = (LCD_CLKCAL<<8) | (3<<5) | (12<<1) ;
rLCDCON2 = (LCD_UPPER_MARGIN << 24) | ((LCD_HEIGHT - 1) << 14) | (LCD_LOWER_MARGIN << 6) | (LCD_VSYNC_LEN << 0);
rLCDCON3 = (LCD_RIGHT_MARGIN << 19) | ((LCD_WIDTH - 1) << 8) | (LCD_LEFT_MARGIN << 0);
rLCDCON4 = (LCD_HSYNC_LEN << 0);
rLCDCON5 = (1<<11) | (1 << 9) | (1 << 8) | (1<<6) | (1 << 3) | (1 << 0) ;
rLCDSADDR1 = ((LCD_ADDR>>22)<<21) | (M5D(LCD_ADDR>>1)) ;
//LCDBASEL OFFSIZE=0,PAGEWIDTH=LCD_WIDTH, x2的原因 16bpp 每個像素點2個字節,>>1見地址對應關係 16bpp
rLCDSADDR2 = M5D((LCD_ADDR + LCD_WIDTH * LCD_HEIGHT * 2)>>1) ;
rLCDSADDR3 = LCD_WIDTH ;
rLCDINTMSK |= 3 ; //屏蔽中斷
rTCONSEL = 0 ; //LPC3600 LCC3600 無效
rTPAL = 0 ; //禁止臨時調色板
}
/****************************************************************
function Envid turn on or off
input onoff 1,Envid turn on
return void
*****************************************************************/
static void Lcd_EnvidOnOff(int onoff)
{
if(onoff==1)
rLCDCON1 |= 1 ; //ENVID ON
else
rLCDCON1 &= ~(1<<0) ; //ENBID OFF
}
/****************************************************************
function LCD power enable
input pwren 1, enable lcd power
return void
*****************************************************************/
static void Lcd_PowerEnable(int pwren)
{
rGPGUP |= (1<<4) ; //Pull-up Disable
rGPGCON |= (3<<8) ; //GPG4 is LCD_PWREN
rLCDCON5&= ~(1<<5) ; //invpwren 正常極性
rLCDCON5 = rLCDCON5 & ~(1<<3)|(pwren<<3) ; //PWREN 使能
}
/****************************************************************
function Filling sole colour into LCD background
input c colour
return void
*****************************************************************/
static void Lcd_FillCor(U16 c)
{
unsigned int x,y ;
for(y=0; y<SCR_YSIZE; y++)
{
for(x=0; x<SCR_XSIZE; x++)
{
LCD_BUFFER[y][x] = c ;
}
}
}
/****************************************************************
function Paint picture
input x0 y0 assign start bit
level vertical the wide and high of picture
*bmp the picture string
return void
*****************************************************************/
static void Paint_BMP(int x0, int y0, int level, int vertical, const unsigned char *bmp)
{
int x, y ;
U32 col ;
int p = 0 ;
for(y=0; y<vertical; y++)
{
for(x=0; x<level; x++)
{
col = bmp[p+1] | (bmp[p]<<8) ; //16bpp 一個像素點用倆個字節
if( ((x0+x)<SCR_XSIZE) && ((y0+y)<SCR_YSIZE))
LCD_BUFFER[y0+y][x0+x] = col ;
p += 2 ;
}
}
}
/****************************************************************
function Display 像素點
input x y display start bit
col color of the char
return void
*****************************************************************/
static void PutPixel(U32 x, U32 y, U16 col)
{
LCD_BUFFER[y][x] = col ;
}
/****************************************************************
function Display 漢字 hzk16 16*16
input x y display start bit
col color of the char
ch[] 字模數組
return void
*****************************************************************/
static void Draw_Text16(U32 x, U32 y, U16 col, const unsigned char ch[])
{
unsigned short i, j ;
unsigned char mask, tem ;
for(i=0; i<16; i++)
{
mask= 0x80 ;
tem = ch[i*2] ; //倆個字節一組16位,取第一個字節
for(j=0; j<8; j++)
{
if(tem & mask)
{
PutPixel(x+j, y+i, col) ;
}
mask = mask >> 1 ;
}
mask = 0x80 ;
tem = ch[i*2 + 1] ;
for(j=0; j<8; j++)
{
if(tem & mask)
{
PutPixel(x+j+8, y+i, col) ;
}
mask = mask >> 1 ;
}
}
}
/****************************************************************
function Display ASCII 字符 16*8
input x y display start bit
col color of the char
ch[] 字模數組
return void
*****************************************************************/
static void Draw_ASCII(U32 x, U32 y, U16 col, const unsigned char ch[])
{
unsigned short i, j ;
unsigned char temp, mask ;
for(i=0; i<16; i++)
{
mask = 0x80 ;
temp = ch[i] ;
for(j=0; j<8; j++)
{
if(mask & temp)
{
PutPixel(x+j, y+i, col) ;
}
mask = mask >> 1 ;
}
}
}
/****************************************************************
function Display 漢字字符 16*16
input x y display start bit
col color of the char
str[] 字符數組
strlen 字符串長度 字節表示
return void
*****************************************************************/
static void Draw_ch_lib(U32 x, U32 y, U16 col, const unsigned char str[], unsigned int strlen)
{
int loc, i ;
unsigned char qh, wh ;
const unsigned char *pchlib ;
for(loc=0, i=0; i<strlen; i++)
{
if(str[i] & 0x80)
{
qh = str[i] - 0xa0 ;
wh = str[i+1] - 0xa0 ;
pchlib = &GB2312Dot16X16[( 94*(qh-1)+(wh-1) -1410 )*32] ;
Draw_Text16( x+loc, y, col, pchlib ) ;
i++ ;
loc += 16 ;
}
}
}
/*******************************************************************
串口UART是掛在PCLK總線上的,需要設置PCLK時鐘,即需要設置2440時鐘。
首先需要設置PLLCON寄存器設置CPU時鐘(FCLK),然後設置FCLK HCLK PCLK的
分頻比,確定好PCLK時鐘。
*****************************************************************/
int Main(void)
{
unsigned int length ;
unsigned char display[] = "啊周茂夫是個大笨蛋" ;
/*****************【CLOCK】******************/
MMU_Init();
ChangeMPllValue(127,2,1); //405MHZ
ChangeClockDivider(13,12); //1:3:6
/**************【UART】**********************/
UART_int_init() ;
UART_send_string("wo zhen de hen yun si \n") ;
pISR_UART0 = (U32)UART0_interrupt ;
/*************【LCD】************************/
Lcd_port_init() ;
Lcd_init() ;
Lcd_PowerEnable(1) ;
Lcd_EnvidOnOff(1) ;
UART_send_string("LCD initial \n") ;
Lcd_FillCor(0xffff) ;
Draw_Text16(16, 20, 0x0, zhou) ;
Draw_Text16(32, 20, 0x0, mao) ; //漢字後需要16位
Draw_ASCII (48, 20, 0x0, Y ) ;
Draw_ASCII (56, 20, 0x0, Y ) ;
Draw_Text16 (100, 20, 0x0, zhao ) ;
Draw_Text16(80, 20, 0x0, zhou) ;
length = sizeof(display) - 1 ; //用sizeof可以直接算出數組佔內存的字節數,減去1
//字符串結束符佔一個字節
Draw_ch_lib(10, 100,0x0, display, length) ;
while(1)
{
//Lcd_FillCor((0x00<<11) | (0x00<<5) | (0x00<<0)) ; //clear screen
//Paint_BMP(0,0,240,320,sunflower_240x320) ; //filling picture sunflower
}
return 0 ;
}