Chinaunix首页 | 论坛 | 博客
  • 博客访问: 13160
  • 博文数量: 11
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 10
  • 用 户 组: 普通用户
  • 注册时间: 2013-04-14 22:16
文章分类
文章存档

2013年(11)

我的朋友

分类: LINUX

2013-04-17 23:18:58

原文地址:裸奔之LCD 作者:草根老师

一、LCD的介绍
LCD 是 Liquid Crystal Display 的简称,LCD 的构造是在两片平行的玻璃基板当中放置液晶盒,下基板玻璃上设置TFT(薄膜晶体管),上基板玻璃上设置彩色滤光片,通过TFT上的信号与电压改变来控制液晶分子的转动方向,从而达到控制每个像素点偏振光出射与否而达到显示目的。现在LCD已经替代CRT成为主流,价格也已经下降了很多,并已充分的普及。

上面的这种定义方式说的是LCD众多类型中的TFT-LCD,LCD按其控制方式不同,有多种类型。比如:STN、TFT、LTPS,OLED等,各有优缺点.这里简单介绍一下STN-LCD(Super Twisted Nematic-Liquid Crystal Display)和TFT-LCD(Thin Film Transistor-Liquid Crystal Display)两类显示器的工作原理,其他的读者自行了解.

二、TFT和LCD

STN-LCD和TFT-LCD都使用一种被称为"向列型"的丝状液晶物质,利用电场来控制"丝状"液晶的方向。通常液态晶体包在两片玻璃中间,在玻璃的表面上先镀有一层透明而且导电的薄膜以作电极之用,然后在有薄膜的玻璃上镀一层称为配向剂的物质,以使液晶随着一个特定且平行于玻璃表面的方向扭转。

STN-LCD显示屏中的液晶,其自然状态具有90度的扭转,利用电场可使液晶再进行旋转,液晶的折射系数随液晶的方向改变而改变,光经过STN型液晶后,偏极性发生变化,只要选择适当,使光的偏极性旋转到180度到270度,就可以利用两个平行偏光片使光完全不能通过。若使液晶方向和电场方向平行,这样光的偏极性就不会改变,光就可以通过第二个偏光片。于是,就可以控制光的明暗了。而STN液晶之所以可以显示彩色,那是因为它在STN液晶显示屏上加了一个彩色的滤光片,并将单色显示矩阵中的每一个像素分成三个子像素,分别通过彩色滤光片显示红,绿,蓝三原色,就可以显示出彩色。STN型液晶属于放射式LCD器件,它的好处是功耗小,但在比较暗的环境中清晰度很差,所以不得不配置外部照明光源。

而TFT液晶显示技术采用了"主动式矩阵"的方式来驱动。方法是利用薄膜技术所做成的电晶体电极,利用扫描的方法"主动的"控制任意一个显示点的开和关。电极通过时,液晶分子就像STN液晶的排列状态一样会发生改变,也通过折光和透光来达到显示的目的。看起来和STN原理差不多。但不同的是,由于 TFT 晶体管具有电容效应,能够保持电位状态,已经透光的液晶分子会一直保持这种状态,知道TFT电极下一次再加电改变其排列方式为止,而STN型液晶就没有找个特性,液晶分子一旦没有电场,立刻就返回了原来的状态,这是TFT液晶和STN液晶显示原理的最大不同之处。


三、FrameBuffer机制

FrameBuffer也叫帧缓存,它的意思是在我们的内存中开辟出以块内存,当作显存用。我们只需要将我们要显示的一副图片像素数据存放到这一块内存中,就能在LCD上显示我们的图片了。
 
这里以S3C2410为例,LCD控制器内部有一个专用的DMA。在这里我们只需要配置好LCD控制器就可以了,将显存的地址告诉LCD控制器。当LCD内部DMA的FIFO为空时,LCD控制器会自动发起DMA传输从内存中获取图像数据。
 
四、TFT-LCD的时序

要想很好的操作TFT-LCD显示屏,首先得搞清楚其时序:
每个VSYNC信号表示一帧数据的开始,每个HSYNC信号表示一行数据的开始,每个VCLK表示正在传输一个像素的数据。LCD根据VSYNC、HSYNC、VCLK不停地读取总线数据、显示。
 
下面我们简单来说一下时序图:

(1)VSYNC信号有效时,表示一帧数据的开始
(2)VSPW表示VSYNC信号的脉冲宽度为(VSPW 1)个HSYNC信号周期,即(VSPW 1)行,这(VSPW 1)行数据无效
(3)VSYNC信号脉冲之后,还要经过(VBPD 1)个HSYNC信号周期,有效的行数据才出现。所以,在VSYNC信号有效之后,总共还要经过(VSPW 1 VBPD 1)个无效的行,第一个有效的数据才会出现。
(4)随后即连续发出(LINEVAL 1)行的有效数据。
(5)最后是(VFPD 1)个无效的行,完整的一帧结束,紧接着就是下一个帧的数据了(即下一个VSYNC信号)

现在深入一行中像素数据传输的过程:
(1)HSYNC信号有效时,表示一行数据的开始
(2)HSPW表示HSYNC信号的脉冲宽度为(HSPW 1)个VCLK信号周期,即(HSPW 1)个像素,这(HSPW 1)个像素的数据无效。
(3)HSYNC信号脉冲之后,还要经过(HBPD 1)个VCLK信号周期,有效的像素数据才出现。所以,在HSYNC信号有效之后,总共还要经过(HSPW 1 HBPD 1)个无效的像素,第一个有效的像素才出现。
(4)随后即连续发出(HOZVAL 1)个像素的有效数据
(5)最后是(HFPD 1)个无效的像素,完整的一行结束,紧接着下一行的数据了(即下一个HSYNC信号)
 
这里需要注意的是上图给出的时序是S3C2410数据手册给出的一个范例,具体的LCD屏时序需要根据屏的数据手册获得。我使用的是
东华WXHAT35-TG2 320X240的TFT屏,时序如下:
 
可以看到和标准的时序很像,我们只需要配置LCD控制器,让其发出上图的时序,我们的屏就可以很好的工作了。


五、核心实验代码

如何配置其控制器,这里我就不再赘述了,网上的资料很多,说的都很详细。这里简单的说一下实验代码:
  1. //初始化LCD控制器
  2. int tft_lcd_init()
  3. {
  4.     unsigned int addr = (unsigned int )LCD_BUFER;
  5.     /*
  6.      *LCDCON1:
  7.      *设置VCLK的频率:VCLK(HZ) = HCLK/[(CLKVAL + 1) x 2]
  8.      *选择LCD类型:TFT LCD
  9.      *设置显示模式:16 BPP
  10.      *先禁止LCD信号输出
  11.      */
  12.     LCDCON1 = (CLKVAL << 8) | (PNRMODE << 5) | (BPPMODE << 1) | VID_DIS;
  13.     
  14.     /*
  15.      *LCDCON2:设置LCD的垂直同步信号时序参数
  16.      *VBPD:垂直同步信号的后肩
  17.      *LINEVAL:LCD屏上有效的行数
  18.      *VFPD:垂直同步信号的前肩
  19.      *VSPW:垂直同步信号的脉宽
  20.      */
  21.     LCDCON2 = S3C2410_LCDCON2_LINEVAL(LCD_Y_SIZE - 1) |\
  22.              S3C2410_LCDCON2_VBPD(UPPER_MARGIN - 1) |\
  23.              S3C2410_LCDCON2_VFPD(LOWER_MARGIN - 1) |\
  24.              S3C2410_LCDCON2_VSPW(VSYNC_LEN - 1);

  25.     /*
  26.      *LCDCON3:设置LCD的水平同步信号时序参数
  27.      *HBPD:水平同步信号的后肩
  28.      *HOZAL:LCD屏图像显示的宽度
  29.      *HFPD:水平同步信号的前肩
  30.      */
  31.     LCDCON3 = S3C2410_LCDCON3_HBPD(RIGHT_MARGIN - 1) |\
  32.              S3C2410_LCDCON3_HFPD(LEFT_MARGIN - 1) |\
  33.              S3C2410_LCDCON3_HOZVAL(LCD_X_SIZE - 1);

  34.      /*
  35.      *LCDCON4:水平同步信号的脉宽
  36.      */
  37.     LCDCON4 = S3C2410_LCDCON4_HSPW(HSYNC_LEN - 1);

  38.     /*
  39.      *LCDCON5:
  40.      *设置显示模式为16BPP时的数据格式: 5:6:5
  41.      *设置HSYNC,VSYN脉冲的极性(这需要参考具体LCD的接口信号)
  42.      */
  43.     LCDCON5 = (FORMAT_565 << 11) | (GET_DATA << 10) | (HSYNC_INV << 9)\
  44.              | (VSYNC_INV << 8) | (HWSWP << 1);
  45.     /*
  46.      *设置LCD控制器的地址寄存器LCDSADDR1~3
  47.      *帧内存与视口(view point)完全吻合
  48.      *1.LCDSADDR1:
  49.      *设置LCDBANK,LCDBASEU
  50.      *
  51.      *2.LCDSADDR2:
  52.      *设置LCDBASEL:帧缓冲的结束地址A[21:1]
  53.      *
  54.      *3.LCDSADDR3:
  55.      *OFFSIZE等于0,PAGEWIDTH等于(320/2)[注意:以半字为单位]
  56.      */
  57.      LCDSADDR1 = ((addr >> 22) << 21) | ((addr >> 1) & 0x1fffff);
  58.      LCDSADDR2 = ((addr + LCD_X_SIZE * LCD_Y_SIZE * 2) >> 1) & 0x1fffff;
  59.      LCDSADDR3 = (0 << 11) | (LCD_X_SIZE / 2);

  60.      //禁用条色板
  61.      TPAL = 0;
  62.     
  63.      //MASK LCD sub Interrupt
  64.      LCDINTMSK = 3;

  65.      //Disable LPC3480
  66.      LPCSEL &= ~7;
  67.     
  68.      return 0;
  69. }

  70. /*在LCD屏幕的指定坐标点绘制一幅图像*/
  71. static void paint_bmp(int x0,int y0,int x1,int y1,unsigned char bmp[])
  72. {
  73.     int x,y;
  74.     unsigned short c;
  75.     int p = 0;
  76.     unsigned int addr = (unsigned int)LCD_BUFER;

  77.     for(y = 0;y < y1;y ++)
  78.     {
  79.         for(x = 0;x < x1; x ++)
  80.         {
  81.             c = bmp[p+1] | ( bmp[p] << 8);

  82.             *(unsigned short *)(addr +((x + x0 + ((y + y0) * 320)) << 1)) = c;
  83. #if 0
  84.                         /*特别奇怪,使用二维数组的方式,LCD显示图片的时候有重叠,不清晰
  85.                         *但是用上面的一种写法就能正常显示,我感觉两种写法应该都可以,希望知道的
  86.                         *大神跟小弟说一下,不胜感激...
  87.                         */
  88.             if((x0 + x) < LCD_X_SIZE && (y0 + y) < LCD_Y_SIZE)
  89.             {
  90.                 LCD_BUFER[y0 + y][x0 + x] = c;
  91.             }
  92. #endif
  93.             p = p + 2;
  94.         }
  95.     }

  96.     return;
  97. }
最后附上整个实验的代码
阅读(301) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~