S3C2440的LCD簡單應用與實現(xiàn)
TFT LCD的TTL信號
本文引用地址:http://m.butianyuan.cn/article/201611/316627.htmVSYNC 垂直同步信號
HSYNC水平同步信號
HCLK 像素時鐘信號
VD[23:0] 數(shù)據(jù)信號
LEND 行結束信號(非必須)
PWREN 電源開關信號
顯示器上的數(shù)據(jù)組成格式
一幅圖像被稱為一幀(frame),每幀由多行組成,每行有多個像素組成,每一個像素的顏色用若干位的數(shù)據(jù)來表示。對于單色顯示器,每個像素使用1位來表示,稱為1BPP;對于256色顯示器,每個像素使用8位來表示,稱為8BPP.
顯示器從屏幕左上方開始,一行一行地取得每個像素的數(shù)據(jù)并顯示出來,當顯示到一行的最右邊時,跳到下一行的最左邊開始顯示下一行,當顯示完所有行時,跳到左上邊開始下一幀。顯示器沿著“Z”字行的路線進行掃描,使用HSYNC、VSYNC信號來控制掃描路線跳轉,HSYNC表示“是跳到最左邊的時候了”,VSYNC表示“是跳到最上邊的時候了”。
VSYNC信號出現(xiàn)的頻率表示一秒鐘內能顯示多少幀圖像,稱為垂直頻率或者場頻率。就是常說的“顯示器頻率”;HSYNC信號出現(xiàn)的頻率稱為水平頻率?,F(xiàn)在來看一下時序圖。
VSYNC可以理解為一幀圖像有效地信號,在它低電平有效的時候,要連續(xù)發(fā)出(LINEVAL+1)個行有效數(shù)據(jù)HSYNC信號;而在HSYNC有效地時候,要連續(xù)發(fā)出(HOZVAL+1)個像素有效數(shù)據(jù),這時像素數(shù)據(jù)的頻率是由VCLK控制,VCLK是作為時序圖的基準信號。我們開發(fā)板上用的屏是240*320的3.5寸觸摸屏,那么LINEVAL+1=240,HOZVAL+1=320。開始時,對垂直頻率理解很模糊,后面干脆理解為一幀圖像有效地信號,這樣正好與它的“顯示器頻率”相對應。在時序圖中,可以看見VSWP/VBPD/VFPD和HSPW/HBPD/HFPD這幾個參數(shù),這是由于LCD在工作中往往四周會有黑框,我們通過設置這幾個參數(shù),可以控制使LCD的實際顯示區(qū)域(數(shù)據(jù)有效區(qū))與屏幕大小相當,這樣就看不到黑框。
VSPW表示VSYNC信號的脈沖寬度為(VSPW+1)個HSYNC信號周期,即VSPW+1行,這VSPW+1行數(shù)據(jù)無效。
VSPD表示VSYNC信號脈沖之后,還要經(jīng)過VSPD+1個HSYNC信號周期,有效行才出現(xiàn)。
VFPD表示在連續(xù)發(fā)出LINEVAL+1行有效數(shù)據(jù)后,還要經(jīng)過VFPD+1個無效行,之后完整的一幀結束。
HSPW表示HSYNC信號脈沖寬度為(HSPW+1)個VCLK信號周期,即HSPW+1個像素是無效的。
HBPD表示在HSYNC信號脈沖之后,還要經(jīng)過HBPD+1個VCLK信號周期,有效像素才能夠出現(xiàn)。
HFPD表示在連續(xù)發(fā)出HOZVAL+1個像素的有效數(shù)據(jù)之后,還要發(fā)出(HFPD+1)個無效像素,完整的一行結束。
VCLK是像素時鐘,計算公式如下:
VCLK=HCLK/[(CLKVAL+1)*2]
CLKVAL可以通過LCDCON1設置,HCLK是100MHz,根據(jù)驅動的LCD的像素時鐘為6.4MHz,代入得到CLKVAL值為6.8,取整后(6)存入到LCDCON1中,此時得到的VCLK為7.1MHz。
現(xiàn)在看一下場頻(VSF)和行頻(HSF)的計算公式:
HSF=VCLK/[(HSPW+1)+(HSPD+1)+(HFPD+1)+(HOZVAL+1)]=7.1/408=17.5KHz
VSF=HSF/[(VSPW+1)+(VBPD+1)+(VFPD+1)+(LINEVAL+1)]=17.5/270=64.8Hz
接下來了解一下24BPP模式下圖像數(shù)據(jù)格式。
#inlcude "2440addr.h"
#define U32 unsigned int
#define M5D(n) ((n) & 0x1fffff) /*用于設置顯示緩存區(qū)時,取低21位地址*/
#define LCD_WIDTH 320 /*屏幕的寬*/
#define LCD_HEIGHT 240 /*屏幕的高*/
/*垂直同步信號的脈寬、后肩和前肩*/
#define VSPW (3-1)
#define VBPD (15-1)
#define VFPD (12-1)
/*水平同步信號的脈寬、后肩和前肩*/
#define HSPW (30-1)
#define HBPD (38-1)
#define HFPD (20-1)
/*顯示尺寸*/
#define LINEVAL (LCD_HEIGHT-1)
#define HOZVAL (LCD_WIDTH-1)
/*for LCDCON1*/
#define CLKVAL_TFT 6 /*設置時鐘信號*/
#define MVAL_USED 0
#define PNRMODE_TFT 3 /*TFT型LCD*/
#define BPPMODE_TFT 13 /*24位TFT型LCD 24BPP*/
/*for LCDCON5*/
#define BPP24BL 0 /*32位數(shù)據(jù)表示24位顏色值時,低位數(shù)據(jù)有效,高8位無效*/
#define INVVCLK 0/*像素值在VCLK下降沿有效*/
#define INVVLINE 1/*翻轉HSYNC信號*/
#define INVVFRAME 1/*翻轉VSYNC信號*/
#define INVVD 0 /*正常VD信號極性*/
#define INVVDEN 0/*正常VDEN信號極性*/
#define PWREN 1 /*使能PWREN信號*/
#define BSWP0 /*顏色數(shù)據(jù)字節(jié)不交換*/
#define HWSWP 0 /*顏色數(shù)據(jù)半字不交換*/
/*定義顯示緩存區(qū)*/
volatile U32 LCD_BUFFER[LCD_HEIGHT][LCD_WIDTH];
extern unsigned char gImage_xiaogou[];
/*延時程序*/
void delay(int a)
{
int k;
for(k=0;k
}
/*繪制屏幕背景顏色,顏色為c*/
void Brush_Background( U32 c)
{
int x,y ;
for( y = 0 ; y < LCD_HEIGHT ; y++ )
{
for( x = 0 ; x < LCD_WIDTH ; x++ )
{
LCD_BUFFER[y][x] =c;
}
}
}
/*畫實心圓,顏色為c。圓心在屏幕中心,半徑為80個像素*/
void Draw_Circular(U32 c)
{
int x,y ;
int tempX,tempY;
int radius = 80;
int SquareOfR = radius*radius;
for( y = 0 ; y < LCD_HEIGHT ; y++ )/*將屏幕分成四個區(qū)域*/
{
for( x = 0 ; x < LCD_WIDTH ; x++ )
{
if(y<=120 && x<=160)
{
tempY=120-y;
tempX=160-x;
}
else if(y<=120&& x>=160)
{
tempY=120-y;
tempX=x-160;
}
else if(y>=120&& x<=160)
{
tempY=y-120;
tempX=160-x;
}
else
{
tempY = y-120;
tempX = x-160;
}
/*x2+y2與r2比較,畫圓,因為π(x2+y2)=πr2(圓),兩邊比較時把π約掉,進行比較*/
if ((tempY*tempY+tempX*tempX)<=SquareOfR)
LCD_BUFFER[y][x] = c ;
}
}
}
void Main(void)
{
/*配置LCD相關引腳*/
rGPCUP = 0x00000000;
rGPCCON = 0xaaaa02a9;
rGPDUP = 0x00000000;
rGPDCON=0xaaaaaaaa;
/*設置LCD的類型、像素時鐘、設置像素位數(shù)、使能LCD信號的輸出。*/
rLCDCON1=(CLKVAL_TFT<<8)|(MVAL_USED<<7)|(PNRMODE_TFT<<5)|(BPPMODE_TFT<<1)|0;
/*這個非常重要。設置垂直方向各信號時間參數(shù)。*/
rLCDCON2=(VBPD<<24)|(LINEVAL<<14)|(VFPD<<6)|(VSPW);
rLCDCON3=(HBPD<<19)|(HOZVAL<<8)|(HFPD);/*設置水平方向各信號的時間參數(shù)*/
rLCDCON4=(HSPW); /*設置HSYNC信號脈沖寬度*/
rLCDCON5 = (BPP24BL<<12) | (INVVCLK<<10) | (INVVLINE<<9) | (INVVFRAME<<8) | (0<<7) | (INVVDEN<<6) | (PWREN<<3) |(BSWP<<1) | (HWSWP);
/*******************************************************************************************/
rLCDSADDR1=(((U32)LCD_BUFFER>>22)<<21)|M5D((U32)LCD_BUFFER>>1);
rLCDSADDR2=M5D( ((U32)LCD_BUFFER+(LCD_WIDTH*LCD_HEIGHT*4))>>1 );
rLCDSADDR3=LCD_WIDTH*32/16;
/*在s3c2440中,寄存器LCDSADDR1和LCDSADDR2用于設置顯示緩存區(qū),即把我們定義的那個二維數(shù)組告訴s3c2440。其中LCDBANK的9位數(shù)據(jù)指定LCD的BANK,即顯示緩存區(qū)的第30位到第22位地址;LCDBASEU的21位數(shù)據(jù)指定了LCD的基址,即顯示緩存區(qū)開始地址的第21位到第1位;LCDBASEL的21位數(shù)據(jù)指定了LCD的尾址,即顯示緩存區(qū)結束地址的第21位到第1位。例如,我們想要在尺寸為320×240的屏幕上顯示24位顏色,定義的顯示緩存區(qū)數(shù)組為LCD_BUFFER[240][320],則LCDBANK等于LCD_BUFFER的第30位到第22位數(shù)據(jù)值(因為LCD_BUFFER表示的就是數(shù)組的首地址),LCDBASEU等于LCD_BUFFER的第21位到第1位數(shù)據(jù)值,由于是用32位數(shù)據(jù)表示24為顏色,因此每個像素值是4個字節(jié),所以LCDBASEL等于(LCD_BUFFER+(240×320×4))結果的第21位到第1位的數(shù)據(jù)值。另外寄存器LCDSADDR3有兩個內容:OFFSIZE和PAGEWIDTH。OFFSIZE用于虛擬屏幕的偏移長度,如果我們不使用虛擬屏幕,就把它置為0;PAGEWIDTH定義了視口的寬,單位是半字,如在上面的例子中,PAGEWIDTH應該為320×32÷16。
*/
/***********************************************************************************************/
rLCDINTMSK|=(3); /*屏蔽LCD中斷*/
rTCONSEL = 0; /*無效LPC3600*/
rGPGUP=rGPGUP|(1<<4); /*GPG4上拉電阻無效*/
rGPGCON=rGPGCON|(3<<8); /*設置GPG4為LCD_PWREN*/
rGPGDAT = rGPGDAT | (1<<4) ; /*GPG4置1*/
rLCDCON5=rLCDCON5&(~(1<<3))|(1<<3); /*有效PWREN信號*/
rLCDCON5=rLCDCON5&(~(1<<5))|(0<<5); /*PWREN信號極性不翻轉*/
rLCDCON1|=1; /*LCD開啟,必須設置,否則LCD不工作*/
while(1)
{
/*黑色背景,白色實心圓*/
Brush_Background(0x0);
Draw_Circular(0xffffff);
delay(5000000);
/*白色背景,黑色實心圓*/
Brush_Background(0xffffff);
Draw_Circular(0x0);
delay(5000000);
/*藍色背景,黃色實心圓 */
Brush_Background(0xff);
Draw_Circular(0xffff00);
delay(5000000);
/*綠色背景,品色實心圓*/
Brush_Background(0xff00);
Draw_Circular(0xff00ff);
delay(5000000);
/*紅色背景,青色實心圓*/
Brush_Background(0xff0000);
Draw_Circular(0xffff);
delay(5000000);
/*青色背景,紅色實心圓*/
Brush_Background(0xffff);
Draw_Circular(0xff0000);
delay(5000000);
/*品色背景,綠色實心圓*/
Brush_Background(0xff00ff);
Draw_Circular(0xff00);
delay(5000000);
/*黃色背景,藍色實心圓*/
Brush_Background(0xffff00);
Draw_Circular(0xff);
delay(5000000);
}
}
評論