×
单片机 > 单片机程序设计 > 详情

S3C2440的LCD简单应用与实现

发布时间:2020-06-06 发布时间:
|
        LCD的种类可分为:STN ,TFT ,LTPS ,OLED。其他类别各自有各自的优缺点。由于FL2440上面用的是TFT类型,我们单独来说一下这个。TFT LCD大大缩短了屏幕响应时间,其响应时间小于80ms。并且改善了STN连续显示时屏幕模糊闪烁,提高了动态画面的播放力,呈现出色彩饱和度和对比度都非常不错,缺点就是功耗太高。

        TFT LCD的TTL信号

     VSYNC                        垂直同步信号

     HSYNC                        水平同步信号

     HCLK                           像素时钟信号

     VD[23:0]                       数据信号

     LEND                           行结束信号(非必须)                   

     PWREN                       电源开关信号

 

显示器上的数据组成格式

       一幅图像被称为一帧(frame),每帧由多行组成,每行有多个像素组成,每一个像素的颜色用若干位的数据来表示。对于单色显示器,每个像素使用1位来表示,称为1BPP;对于256色显示器,每个像素使用8位来表示,称为8BPP.

       显示器从屏幕左上方开始,一行一行地取得每个像素的数据并显示出来,当显示到一行的最右边时,跳到下一行的最左边开始显示下一行,当显示完所有行时,跳到左上边开始下一帧。显示器沿着“Z”字行的路线进行扫描,使用HSYNC、VSYNC信号来控制扫描路线跳转,HSYNC表示“是跳到最左边的时候了”,VSYNC表示“是跳到最上边的时候了”。

     VSYNC信号出现的频率表示一秒钟内能显示多少帧图像,称为垂直频率或者场频率。就是常说的“显示器频率”;HSYNC信号出现的频率称为水平频率。现在来看一下时序图。

       VSYNC可以理解为一帧图像有效地信号,在它低电平有效的时候,要连续发出(LINEVAL+1)个行有效数据HSYNC信号;而在HSYNC有效地时候,要连续发出(HOZVAL+1)个像素有效数据,这时像素数据的频率是由VCLK控制,VCLK是作为时序图的基准信号。我们开发板上用的屏是240*320的3.5寸触摸屏,那么LINEVAL+1=240,HOZVAL+1=320。开始时,对垂直频率理解很模糊,后面干脆理解为一帧图像有效地信号,这样正好与它的“显示器频率”相对应。在时序图中,可以看见VSWP/VBPD/VFPD和HSPW/HBPD/HFPD这几个参数,这是由于LCD在工作中往往四周会有黑框,我们通过设置这几个参数,可以控制使LCD的实际显示区域(数据有效区)与屏幕大小相当,这样就看不到黑框。

         VSPW表示VSYNC信号的脉冲宽度为(VSPW+1)个HSYNC信号周期,即VSPW+1行,这VSPW+1行数据无效。

         VSPD表示VSYNC信号脉冲之后,还要经过VSPD+1个HSYNC信号周期,有效行才出现。

         VFPD表示在连续发出LINEVAL+1行有效数据后,还要经过VFPD+1个无效行,之后完整的一帧结束。

 

         HSPW表示HSYNC信号脉冲宽度为(HSPW+1)个VCLK信号周期,即HSPW+1个像素是无效的。

         HBPD表示在HSYNC信号脉冲之后,还要经过HBPD+1个VCLK信号周期,有效像素才能够出现。

         HFPD表示在连续发出HOZVAL+1个像素的有效数据之后,还要发出(HFPD+1)个无效像素,完整的一行结束。

 

          VCLK是像素时钟,计算公式如下:

           VCLK=HCLK/[(CLKVAL+1)*2]

          CLKVAL可以通过LCDCON1设置,HCLK是100MHz,根据驱动的LCD的像素时钟为6.4MHz,代入得到CLKVAL值为6.8,取整后(6)存入到LCDCON1中,此时得到的VCLK为7.1MHz。

            现在看一下场频(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模式下图像数据格式。

         现在设置好VSYNC、HSYNC、VCLK等信号的参数之后,并将帧内存(frame memory)d地址告诉LCD控制器,它即可自动的发起DMA传输从帧内存中得到图像数据,最终在上述信号的控制下出现在数据总线VD[23:0]上。在内存中使用4个字节(32位)来表示一个像素,其中的3个字节从高到低分别表示红、绿、蓝,剩余的一个字节无效。是低字节还是高字节无效,可以通过LCDCON5[12]来设置,设置为0,低字节有效,设置为1,高字节有效。
----------------------------------------------------------华丽分割------------------------------------------------------------------------------------------
现在还要说一个问题就是 显示缓存区。这是要用到三个帧内存地址寄存器LCDSADDR1~LCDSADDR3
先来看一下帧内存与视口(view point)对应关系。视口就是要真正显示的区域
关于缓存区(内存地址)我们定义一个二维数组LCD_BUFFER[240][320],来存储像素数据。在LCDSADDR1中,用来保存帧内存的起始地址,视口所对应的内存起始地址。看一下具体寄存器格式:
可以看出,帧内存地址A[30:22]对应LCDBANK[29:21],视口的起始地址LCDBASEU[21:0]对应帧内存起始地址A[21:1]。
 在LCDSADDR2中,用来保存帧缓存区结束地址A[21:1]。LCDBASEL等于LCD_BUFFER+(240*320*4)的结果的21位到1位的数据值。
在LCDSADDR3中,OFFSIZE用于虚拟屏幕偏移长度,不用可以设置为0;PAGEWIDTH用于定义视口宽度,以半字为单位。因此我们定义PAGEWIDTH=320*32/16。
 
 
 现在我们来看一段代码分析:

#inlcude "2440addr.h"
#define U32 unsigned int

#define M5D(n)            ((n) & 0x1fffff)     /*用于设置显示缓存区时,取低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位数据表示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];

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++ )/*将屏幕分成四个区域*/

    {

           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的类型、像素时钟、设置像素位数、使能LCD信号的输出。*/

       rLCDCON1=(CLKVAL_TFT<<8)|(MVAL_USED<<7)|(PNRMODE_TFT<<5)|(BPPMODE_TFT<<1)|0;

/*这个非常重要。设置垂直方向各信号时间参数。*/

       rLCDCON2=(VBPD<<24)|(LINEVAL<<14)|(VFPD<<6)|(VSPW);                         

       rLCDCON3=(HBPD<<19)|(HOZVAL<<8)|(HFPD);                     /*设置水平方向各信号的时间参数*/

       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用于设置显示缓存区,即把我们定义的那个二维数组告诉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。

*/   
/***********************************************************************************************/

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

    }

}

 


『本文转载自网络,版权归原作者所有,如有侵权请联系删除』

热门文章 更多
LCD驱动-JZ2440