裸機系列——s3c2440lcd漢字顯示

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 ;
}




發佈了53 篇原創文章 · 獲贊 21 · 訪問量 37萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章