新聞中心

        EEPW首頁 > 嵌入式系統 > 設計應用 > 基于ARM9的LCD程序編寫

        基于ARM9的LCD程序編寫

        作者: 時間:2016-11-11 來源:網絡 收藏
        人機交互是嵌入式系統必須具有的功能。比較簡單的人機交互有按鍵、LED、蜂鳴器,稍微
        復雜的有7 段數碼管和點陣。但如今這些都不能滿足人們的需求了,所以又出現了LCD
        觸摸屏技術。s3c2440 具有LCD 和觸摸屏接口,可以很好的連接LCD 和觸摸屏。這篇文章
        主要介紹TFT 型LCD 的用法。
        要想正確使用LCD,必須注意兩點:1、時序;2、顯示緩存區。
        1、時序
        LCD 一般需要三個時序信號:VSYNC、HSYNC 和VCLK。VSYNC 是垂直同步信號,在每
        進行一個幀(即一個屏)的掃描之前,該信號就有效一次,由該信號可以確定LCD 的場頻,
        即每秒屏幕刷新的次數(單位Hz)。HSYNC 是水平同步信號,在每進行一行的掃描之前,
        該信號就有效一次,由該信號可以確定LCD 的行頻,即每秒屏幕從左到右掃描一行的次數
        (單位Hz)。VCLK 是像素時鐘信號。
        s3c2440 處理LCD 的時鐘源是HCLK,通過寄存器LCDCON1 中的CLKVAL 可以
        調整VCLK 頻率大小,它的公式為:
        VCLK=HCLK÷[(CLKVAL+1)×2]
        例如,HCLK 的頻率為100MHz,要想驅動像素時鐘信號為6.4MHz 的LCD 屏,則通過上
        式計算CLKVAL 值,結果CLKVAL 為6.8,取整后(值為6)放入寄存器LCDCON1 中相
        應的位置即可。由于CLKVAL 進行了取整,因此我們把取整后的值代入上式,重新計算
        VCLK,得到VCLK=7.1MHz。
        按理說,對于一個已知尺寸(即水平顯示尺寸HOZVAL 和垂直顯示尺寸LINEVAL 已知)
        的LCD 屏,只要確定了VCLK 值,行頻和場頻就應該知道了。但這樣還不行的,因為在每
        一幀時鐘信號中,還會有一些與屏顯示無關的時鐘出現,這就給確定行頻和場頻帶來了一定
        的復雜性。如在HSYNC 信號先后會有水平同步信號前肩(HFPD)和水平同步信號后肩
        (HBPD)出現,在VSYNC 信號先后會有垂直同步信號前肩(VFPD)和垂直同步信號后
        肩(VBPD)出現,在這些信號時序內,不會有有效像素信號出現,另外HSYNC 和VSYNC
        信號有效時,其電平要保持一定的時間,它們分別叫做水平同步信號脈寬HSPW 和垂直同
        步信號脈寬VSPW,這段時間也不能有像素信號。因此計算行頻和場頻時,一定要包括這些
        信號。HBPD、HFPD 和HSPW 的單位是一個VCLK 的時間,而VSPW、VFPD 和VBPD 的
        單位是掃描一行所用的時間。在s3c2440 中,所有的這些信號(VSPW、VFPD、VBPD、
        LINEVAL、HBPD、HFPD、HSPW 和HOZVAL)都是實際值減1 的結果。這些值是通過寄
        存器LCDCON2、LCDCON3 和LCDCON4 來配置,只要把這些值配置成與所要驅動的LCD
        中相關內容的數據一致即可。例如,我們所要顯示的LCD 屏大小為320×240,因此HOZVAL
        =320-1,LINEVAL=240-1。水平同步信號的脈寬、前肩和后肩分別為30、20 和38,則
        HSPW=30-1,HFPD=20-1,HBPD=38-1;垂直同步信號的脈寬、前肩和后肩分別為
        3、12 和15,則VSPW=3-1,VFPD=12-1,VBPD=15-1。
        下面我們就具體計算一下行頻(HSF)和場頻(VSF):
        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
        在有些情況下,s3c2440 的LCD 時鐘信號的默認極性與所控制的LCD 時鐘信號的極性相反,
        這時可以通過寄存器LCDCON5 的相關位來改變某些時鐘信號的極性。
        2、顯示緩存區
        只要把所要顯示的數據放入顯示緩存區內,就可以在屏幕上呈現內容。該緩存區是
        我們自己編程時開辟的一段內存區。一般我們是通過定義一個與屏幕尺寸大小相同的二維數
        組來開辟該空間的,這樣控制屏幕內容會方便一些,如當屏幕的尺寸為320×240 時,可以
        定義該緩存區為LCD_BUFFER[240][320]。由于s3c2440 支持16 位和24 位的非調色板真彩
        色的TFT 型LCD 模式,而24 位顏色模式是用32 位數據來表示的,所以前面定義的那個二
        維數據的數據類型應該是半字整型或全字整型的。例如,在24 位顏色模式下,我們想要在
        尺寸大小為320×240 屏幕的中心處設置為白色像素,則:LCD_BUFFER[120][160]=0xffffffff。
        在s3c2440 中,寄存器LCDSADDR1 和LCDSADDR2 用于設置顯示緩存區,即把
        我們定義的那個二維數組告訴s3c2440。其中LCDBANK 的9 位數據指定LCD 的BANK,
        即顯示緩存區的第30 位到第22 位地址;LCDBASEU 的21 位數據指定了LCD 的基址,即
        顯示緩存區開始地址的第21 位到第1 位;LCDBASEL 的21 位數據指定了LCD 的尾址,即
        顯示緩存區結束地址的第21 位到第1 位。例如,我們想要在尺寸為320×240 的屏幕上顯示
        24 位顏色, 定義的顯示緩存區數組為LCD_BUFFER[240][320] , 則LCDBANK 等于
        LCD_BUFFER 的第30 位到第22 位數據值(因為LCD_BUFFER 表示的就是數組的首地址),
        LCDBASEU 等于LCD_BUFFER 的第21 位到第1 位數據值,由于是用32 位數據表示24 為
        顏色,因此每個像素值是4 個字節,所以LCDBASEL 等于(LCD_BUFFER+(240×320×4))
        結果的第21 位到第1 位的數據值。另外寄存器LCDSADDR3 有兩個內容:OFFSIZE 和
        PAGEWIDTH。OFFSIZE 用于虛擬屏幕的偏移長度,如果我們不使用虛擬屏幕,就把它置為
        0;PAGEWIDTH 定義了視口的寬,單位是半字,如在上面的例子中,PAGEWIDTH 應該為
        320×32÷16。
        下面我們給出一段具體的TFT 型LCD 顯示的實例,其中,屏幕的大小為320×240,所設置
        的顏色為24 位真彩色模式。
        #define U32 unsigned int
        #define M5D(n) ((n) & 0x1fffff) //用于設置顯示緩存區時,取低21 位地址
        #define rGPCCON (*(volatile unsigned *)0x56000020) //Port C control
        #define rGPCDAT (*(volatile unsigned *)0x56000024) //Port C data
        #define rGPCUP (*(volatile unsigned *)0x56000028) //Pull-up control C
        #define rGPDCON (*(volatile unsigned *)0x56000030) //Port D control
        #define rGPDDAT (*(volatile unsigned *)0x56000034) //Port D data
        #define rGPDUP (*(volatile unsigned *)0x56000038) //Pull-up control D
        #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 rLCDCON1 (*(volatile unsigned *)0x4d000000) //LCD control 1
        #define rLCDCON2 (*(volatile unsigned *)0x4d000004) //LCD control 2
        #define rLCDCON3 (*(volatile unsigned *)0x4d000008) //LCD control 3
        #define rLCDCON4 (*(volatile unsigned *)0x4d00000c) //LCD control 4
        #define rLCDCON5 (*(volatile unsigned *)0x4d000010) //LCD control 5
        #define rLCDSADDR1 (*(volatile unsigned *)0x4d000014) //STN/TFT Frame buffer start
        address 1
        #define rLCDSADDR2 (*(volatile unsigned *)0x4d000018) //STN/TFT Frame buffer start
        address 2
        #define rLCDSADDR3 (*(volatile unsigned *)0x4d00001c) //STN/TFT Virtual screen
        address set
        #define rLCDINTMSK (*(volatile unsigned *)0x4d00005c) //LCD Interrupt mask
        #define rTCONSEL (*(volatile unsigned *)0x4d000060) //LPC3600 Control --- edited by
        junon
        #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
        //for LCDCON5
        #define BPP24BL 0 //32 位數據表示24 位顏色值時,低位數據有效,高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 BSWP 0 //顏色數據字節不交換
        #define HWSWP 0 //顏色數據半字不交換
        //定義顯示緩存區
        volatile U32 LCD_BUFFER[LCD_HEIGHT][LCD_WIDTH];
        //延時程序
        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++ )
        {
        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;
        }
        if ((tempY*tempY+tempX*tempX)<=SquareOfR)
        LCD_BUFFER[y][x] = c ;
        }
        }
        }
        void Main(void)
        {
        //配置LCD 相關引腳
        rGPCUP = 0x00000000;
        rGPCCON = 0xaaaa02a9;
        rGPDUP = 0x00000000;
        rGPDCON=0xaaaaaaaa;
        rLCDCON1=(CLKVAL_TFT<<8)|(MVAL_USED<<7)|(PNRMODE_TFT<<5)|(BPPMODE_TF
        T<<1)|0;
        rLCDCON2=(VBPD<<24)|(LINEVAL<<14)|(VFPD<<6)|(VSPW);
        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);
        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;
        rLCDINTMSK|=(3); // 屏蔽LCD 中斷
        rTCONSEL = 0; //無效LPC3480
        rGPGUP=rGPGUP&(~(1<<4))|(1<<4); //GPG4 上拉電阻無效
        rGPGCON=rGPGCON&(~(3<<8))|(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 開啟
        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);
        }
        }


        關鍵詞: ARM9LCD程序編

        評論


        技術專區

        關閉
        主站蜘蛛池模板: 灌阳县| 环江| 富宁县| 桐乡市| 揭西县| 旌德县| 迁安市| 长兴县| 石渠县| 临汾市| 肇庆市| 和静县| 阳城县| 义乌市| 禹州市| 白水县| 汉寿县| 葵青区| 南木林县| 临汾市| 兴安盟| 龙泉市| 武川县| 宁河县| 清远市| 靖西县| 香河县| 伊川县| 普陀区| 军事| 元谋县| 望城县| 泽州县| 隆林| 兴宁市| 景谷| 吉水县| 屯昌县| 抚顺县| 页游| 韩城市|