1.先了解显示器们
CRT显示器
原理,使用电子轰击荧光粉实现显示。
特点,主动发光,颜色绚丽,但是大。
等离子显示器(PDP)
原理,在显示屏上排列上千个密封的小低压气体室,通过电流激发使其发出肉眼看不见的紫外光,然后紫外光碰击后面玻璃上的红、绿、蓝3色荧光体发出肉眼能看到的可见光,以此成像。
特点,主动发光,颜色绚丽,可以做很薄,但是耗电。
液晶屏(LCD)
原理,分两部分,一个背光光源,一个液晶盒,使用电压改变来控制液晶分子的转动方向,从而达到控制每个像素点偏振光出射与否而达到显示目的。
特点,被动发光,颜色不够亮,可以做很薄。
OLED
原理,为有机发光二极管。
特点,主动发光,颜色绚丽,可以做很薄很轻,柔性屏。
2. 大致了解下LCD的相关模块
显存,就是DDR上一部分用来专门存放图像信息。
LCD控制器,负责与LCD驱动器进行时序通信。
LCD驱动器,完成图像数字信号转换模拟信号,并输出给LCD面板
LCD面板,按照LCD驱动器给的模拟信号,通过电磁改变液晶分子的运动,从而改变偏振光,从而改变显示的颜色。
由于上面的整个流程都是硬件实现,所以操作LCD就只需要操作显存。
1. 对于LCD从两个层次来学习
(1)计算机中图像的表示方法和对LCD数据传输接口
(2)LCD时序通信和控制器设置,显存设置
2.1. 计算机中图像的表示方法
显示器的基本显像单位是像素,每个像素点只能显示一种颜色,而计算机使用二进制位指示该像素点的显示。
按照使用二进制位的数量,分为 1,8,16,32位色
1位色:只有亮和灭两种。
8位色:比如黑白影片就是8位色表示
16位 :彩色
32位:真彩色,人眼镜能分辨的颜色有限,32位就可以囊括大部分人能识别的颜色。
2.3. LCD数据传输接口
LCD数据传输的方式依照使用的传输接口不同而不同。
我这里是 RGB接口,如下
24位数据线,说明支持并行传输
HSYNC、VSYNC、VDEN、VCLK: 为时序信号线。
3.1 LCD的时序和控制器
首先需要知道LCD驱动器是如何将像素点设置颜色的。
LCD驱动器,按照从上到下,从左至右的顺序进行扫描,将像素点颜色设置。
在每次进行扫描时,需要一段等待时间
扫描一行时,当开始需要等待 HSPW 时间
然后再 等待 HBPD 时间
扫描一行使用 HOZVAL
完成后,还需要等待 HFPD 时间,
其中 HOVZAL 与 一行的像素点个数有关
HSPW HBPD HFPD 与LCD设备本身相关。
扫描一列,也有上面的时序要求
具体如下:
这些时序信息,只需要写入LCD控制器,LCD控制器就会按照时序信息与LCD驱动器通信。
3.2 显存
显存本质就是内存,被设置用来专门存放图片信息,也就是像素点信息。
对于显存有几个重要属性
(1)显存的基地址
(2)该显存存储像素点的表示方式
(3)多窗口
(4)虚拟显示
对于多窗口,
每个窗口对应自己的显存,
通过调整窗口之间的关系,在一个物理屏幕上显示。
多窗口的好处是,多物理屏幕上一块空间的刷新,可以只重绘一个窗口,不需要重绘所有像素点。
虚拟显示
对于一个窗口中存放的图片,可以指定部分显示。
4.代码
#include "main.h" #define GPF0CON (*(volatile unsigned long *)0xE0200120) #define GPF1CON (*(volatile unsigned long *)0xE0200140) #define GPF2CON (*(volatile unsigned long *)0xE0200160) #define GPF3CON (*(volatile unsigned long *)0xE0200180) #define GPD0CON (*(volatile unsigned long *)0xE02000A0) #define GPD0DAT (*(volatile unsigned long *)0xE02000A4) #define CLK_SRC1 (*(volatile unsigned long *)0xe0100204) #define CLK_DIV1 (*(volatile unsigned long *)0xe0100304) #define DISPLAY_CONTROL (*(volatile unsigned long *)0xe0107008) #define VIDCON0 (*(volatile unsigned long *)0xF8000000) #define VIDCON1 (*(volatile unsigned long *)0xF8000004) #define VIDTCON2 (*(volatile unsigned long *)0xF8000018) #define WINCON0 (*(volatile unsigned long *)0xF8000020) #define WINCON2 (*(volatile unsigned long *)0xF8000028) #define SHADOWCON (*(volatile unsigned long *)0xF8000034) #define VIDOSD0A (*(volatile unsigned long *)0xF8000040) #define VIDOSD0B (*(volatile unsigned long *)0xF8000044) #define VIDOSD0C (*(volatile unsigned long *)0xF8000048) #define VIDW00ADD0B0 (*(volatile unsigned long *)0xF80000A0) #define VIDW00ADD1B0 (*(volatile unsigned long *)0xF80000D0) #define VIDTCON0 (*(volatile unsigned long *)0xF8000010) #define VIDTCON1 (*(volatile unsigned long *)0xF8000014) #define HSPW (40) // 1~40 DCLK #define HBPD (10 - 1) // 46 #define HFPD (240 - 1) // 16 210 354 #define VSPW (20) // 1~20 DCLK #define VBPD (10 - 1) // 23 #define VFPD (30 - 1) // 7 22 147 // FB地址 #define FB_ADDR (0x23000000) #define ROW (480) #define COL (800) #define HOZVAL (COL-1) #define LINEVAL (ROW-1) #define XSIZE COL #define YSIZE ROW // 初始化LCD void lcd_init(void) { // 配置引脚用于LCD功能 GPF0CON = 0x22222222; GPF1CON = 0x22222222; GPF2CON = 0x22222222; GPF3CON = 0x22222222; // 打开背光 GPD0_0(PWMTOUT0) GPD0CON &= ~(0xf<<0); GPD0CON |= (1<<0); // output mode GPD0DAT &= ~(1<<0); // output 0 to enable backlight // 10: RGB=FIMD I80=FIMD ITU=FIMD DISPLAY_CONTROL = 2<<0; // bit[26~28]:使用RGB接口 // bit[18]:RGB 并行 // bit[2]:选择时钟源为HCLK_DSYS=166MHz VIDCON0 &= ~( (3<<26)|(1<<18)|(1<<2) ); // bit[1]:使能lcd控制器 // bit[0]:当前帧结束后使能lcd控制器 VIDCON0 |= ( (1<<0)|(1<<1) ); // bit[6]:选择需要分频 // bit[6~13]:分频系数为5,即VCLK = 166M/(4+1) = 33M,设置实际工作频率为33M,是由于我的LCD驱动器最大工作频率为44M VIDCON0 |= 4<<6 | 1<<4; // H43-HSD043I9W1.pdf(p13) 时序图:VSYNC和HSYNC都是低脉冲 // s5pv210芯片手册(p1207) 时序图:VSYNC和HSYNC都是高脉冲有效,所以需要反转 VIDCON1 |= 1<<5 | 1<<6; // 设置时序,可以在LCD的手册中找到 VIDTCON0 = VBPD<<16 | VFPD<<8 | VSPW<<0; VIDTCON1 = HBPD<<16 | HFPD<<8 | HSPW<<0; // 设置长宽(物理屏幕) VIDTCON2 = (LINEVAL << 11) | (HOZVAL << 0); // 设置window0 // bit[0]:使能 // bit[2~5]:24bpp(RGB888) WINCON0 |= 1<<0; WINCON0 &= ~(0xf << 2); WINCON0 |= (0xB<<2) | (1<<15); #define LeftTopX 0 #define LeftTopY 0 #define RightBotX 799 #define RightBotY 479 // 设置window0的上下左右 // 设置的是显存空间的大小 VIDOSD0A = (LeftTopX<<11) | (LeftTopY << 0); VIDOSD0B = (RightBotX<<11) | (RightBotY << 0); VIDOSD0C = (LINEVAL + 1) * (HOZVAL + 1); // 设置显存基地址和大小 VIDW00ADD0B0 = FB_ADDR; VIDW00ADD1B0 = (((HOZVAL + 1)*4 + 0) * (LINEVAL + 1)) & (0xffffff); // 使能channel 0传输数据 SHADOWCON = 0x1; }