以下内容源于朱有鹏嵌入式课程的学习与整理,如有侵权请告知删除。
参考博客
s5pv210 LCD编程原理 - biaohc - 博客园
一、关于LCD的简介
1、LCD简介
(1)什么是LCD
LCD(Liquid Crystal Display)俗称液晶。液晶是一种材料,这种材料具有一种特点,在电信号的驱动下液晶分子进行旋转,而旋转时会影响透光性,因此我们可以在整个液晶面板后面用白光照(称为背光),可以通过不同电信号让液晶分子进行选择性的透光,此时在液晶面板前面就可以看到各种各样的颜色,这就是LCD显示。
有些显示器(比如LED显示器)本身会发光,称为主动发光。有些(比如LCD)本身不会发光而只会透光,需要背光的协助才能看起来是发光的,称为被动发光。
液晶多应用于电视机、电脑显示屏、手机显示屏、工业显示屏等领域。(2)其他主流显示设备
CRT:阴极摄像管显示器。
等离子显示:未成为主流。
OLED:目前未成为主流,但是很有市场潜力。
LED:主要用在户外大屏幕。
LCD:目前是主流显示器。
(3)LCD的显示原理(液晶分子透光+背光)
白光由各种不同颜色的光组成,被选择性透光之后可以产生各种不同颜色的光。
(4)LCD的发展史和种类(TN/STN/TFT)
TN最早。坏处是响应性不够好,有拖尾现象。
STN是TN的升级版。有效解决拖尾现象,显示更清晰。
TFT的最大特点就是超薄。
2、LCD的接口技术
(1)LCD的硬件接口采用TTL电平
+5V表示逻辑1,0V表示逻辑0,这种就叫TTL电平。
SoC的LCD控制器硬件接口是TTL电平的,LCD的硬件接口也是TTL电平的。所以他们可以直接对接,比如手机、平板、开发板,一般都使用软排线连接。
TTL电平的缺陷就是传输距离短,如果LCD屏幕和主板控制器太远(比如大于1米)就不能直接TTL连接,而要进行转换。转换方式为:主机SoC(TTL) —>VGA —> LCD屏幕(TTL)。
(2)各种接口(TTL、LVDS、EDP、MIPI)的传输速率、距离、适配性
http://blog.csdn.net/wocao1226/article/details/23870149
(3)RGB接口详解(参考数据手册P1207页时序图)
(1)VD[23:0],24根数据线,用来传输图像信息。可见LCD是并行接口,速率才够快。
(2)HSYNC(水平同步信号)
(3)VSYNC(垂直同步信号):时序信号线,为了让LCD能够正常显示给的控制信号。
(4)VCLK(像素时钟):LCD工作时需要主板控制器给LCD模组一个工作时钟信号,就是VCLK。
(5)VDEN(数据有效标志):时序信号,和HSYNC、VSYNC结合使用。
(6)LEND(行结束标志,不是必须的):时序信号,非必须,比如X210接口就没有。
3、LCD如何显示图像
(1)像素(pixel)
像素就是组成图像的最基本元素,或者说显示中可以被控制的最小单位,整个图像就是由很多个像素组成的。
像素可以被单独控制,或控制其亮或不亮(单色屏)、或控制其亮度强弱(譬如亮50%,35%,这样叫灰度屏,以前的黑白电视机)、或控制其显示一定的颜色(现在最常用的彩色显示屏)。
总结:整个显示图像是由一个个的像素组成的。我们要在显示器上显示一个图像,就是把这个图像离散化成一个个的点,然后把各个点的颜色对应在显示器的像素上。(2)扫描
扫描就是依次将颜色数值放入屏幕中所有像素中的这个过程。扫描这个词是由最早的CRT显示器遗留下来的,到LCD显示器的年代已经失去意义,但是我们还是延续着这么叫。
显示器的扫描显示原理依赖于人眼的视觉暂留。只要显示器扫描频率大于人眼的发现频率,人眼看到的图像就是恒定的。如果扫描频率偏小人眼就会看到闪动。
(3)LCD驱动器、LCD控制器
LCD驱动器一般和LCD显示面板集成在一起。这两者本来是分开的,做面板的是只做面板的,比如三星、LG、友达、奇美都是做面板的;驱动器也由专门的IC厂商生产;集成厂商买来面板和驱动器后集成在一起做成LCD屏幕。
面板只负责液晶分子的旋转透光,需要一定的模拟电信号来控制液晶分子。这模拟电信号由LCD驱动器芯片负责提供,而LCD驱动器的控制信号(数字信号)来自于自己的数字接口,这个接口就是LCD屏幕的外部接口(即上面第2节中讲到的接口)。
LCD控制器一般集成在SoC内部,负责通过数字接口向远端的LCD驱动器提供控制像素显示的数字信号。LCD控制器的关键在于时序,它必须按照一定的时序和LCD驱动器通信。LCD控制器受到SoC控制,SoC会从内存中拿像素数据给LCD控制器并最终传给LCD驱动器。
(4)显示内存(简称显存)
SoC在内存中挑选一段内存(程序员随便挑的,但是必须符合一定规矩),然后通过配置将LCD控制器和这一段内存形成一个映射关系。这个关系建立之后,LCD控制器会自动从显存中读取像素数据传输给LCD驱动器。这个过程不需要CPU的参与。
这关系建立之后,CPU不用再理会LCD控制器、驱动器、面板,只需要关心显存即可,因为只要把要显示的图像的像素数据丢到显存中,硬件就会自动响应,屏幕上就能自动看到显示的图像。
总结:LCD显示分为2个阶段,第一个阶段就是CPU初始化LCD控制器,使其和某段显存联系起来构成映射;第二个阶段就是将要显示的图像丢到显存中去。
4、LCD的六个主要时序参数
(1)LCD显示单位:帧(frame)
显示器整个画面的内容为一帧(frame)。
显示器工作时其实是一帧一帧地在显示,比如电影以每秒24帧的速度在播放图片。
一帧分为多行,一行分为多像素,因此一帧图像其实就是多个像素组成的矩阵。
(2)LCD显示一帧图像的过程
首先把帧分为行,然后再把行分为像素,然后逐个像素去显示。
其实就是LCD驱动器按照LCD控制器给的显示数据,驱动一个像素的液晶分子旋转,让这个像素显示出相应的颜色值的过程。
LCD控制器和驱动器之间一次只能传一个像素点的显示数据,所以一帧图像在屏幕上其实是逐行地依次被显示上去的,不是同一时间显示出来的。(3)为了向前兼容出现的六个时序参数
HSPW 水平同步信号脉宽 HBPD 水平同步信号前肩 HFPD 水平同步信号后肩 VSPW 垂直同步信号脉宽 VBPD 垂直同步信号前肩 VFPD 垂直同步信号后肩 (1)一行的通信过程是这样的:LCD控制器先发送一个HSYNC高电平脉冲(脉冲宽度是HSPW),脉冲告诉驱动器下面的信息是一行信息。然后开始这一行信息,这一行信息包括3部分:HBPD+有效行信息+HFPD。其中前肩和后肩都属于时序信息(和LCD屏幕具体有关),有效行信息就是横向分辨率。所以你可以认为一行总共包含4部分:HSPW+HBPD+有效行信息+HFPD。
(2)一帧图像其实就是一列,一列图像由多个行组成,每行都是上面讲的这个时序。
(3)一帧图像的通信过程是这样的:整个帧图像信号分为4部分:VSPW+VBPD+帧有效信号+VFPD。VSPW是帧同步信号宽度,用来告诉驱动器一帧图像要开始了;VBPD和VFPD分别是垂直同步信号前后肩。
(4)必须说明:这6个参数对于LCD显示器其实本来是没用的,这些信号其实是老式的CRT显示器才需要的,LCD本身不需要,但是出于历史兼容性要求,LCD选择了兼容CRT显示器的这些时序要求,所以理解LCD显示器时序和编程时,用CRT的方式来理解不会错。
(5)这几个时序参数本身是LCD屏幕本身的参数,与LCD控制器无关。同一个主板如果接的屏幕不一样,则时序参数设置也会不同。这些参数来源一般是:
第一,厂家会一般以实例代码的形式给出。
查看九鼎的210裸机教程(s5pv210-fb.c的第774行)
.h_fp = 210, // 160-210-354.h_bp = 38, // 46.h_sw = 10, // 1-40.v_fp = 22, // 7-22-147.v_fpe = 1,.v_bp = 18, // 23.v_bpe = 1, .v_sw = 7, // 1-20
第二,来自于LCD的数据手册。
比如查看LCD数据手册(X210光盘资料\A盘\DataSheet\AT070TN92.pdf)
补充
1、注意这些数字的单位。H开头的三个单位都是DCLK(像素时钟),V开头的三个单位是TH。这样设置的好处是我们改变了像素时钟的设置时,不用改变这里的时序参数。
2、这些时序参数如果没设置好会影响什么?屏幕会跑偏。
5、LCD显示的相关概念
(1)像素(pixel)
整个图像是由一个个的像素组成的,像素就是一个显示点。
(2)像素间距(pitch)
pitch是连续2个像素的像素中心的距离。一般的像素是方形的,所以横向pitch和纵向的pitch一样的。但是也有不一样的。
像素间距会影响屏幕的最佳观看距离。像素间距大的适合远距离看,像素间距小的适合近距离看。
(3)分辨率(resolution)
整个屏幕的横向和纵向的像素个数就叫分辨率,譬如X210开发板用的屏幕是800×480。
屏幕尺寸和分辨率无关的,像开发板的屏幕尺寸是7寸的(纯屏幕对角线尺寸是7英寸)。
屏幕尺寸和分辨率和像素间距三者之间有关联。
(4)清晰度
清晰度是一个主观概念,是人眼对显示效果的一个主观判断。说白了就是人看起来感觉清晰不清晰。
客观来讲,清晰度由分辨率和像素间距共同决定。一般的,屏幕尺寸固定时分辨率越高越清晰,分辨率越低就越不清晰;分辨率固定下,屏幕尺寸越小越清晰,越大越不清晰。
清晰度还由其他很多因素共同决定。
(5)像素深度(bits per pixel,简称bpp)
一个像素在计算机中由多少个字节数据来描述。
计算机中用二进制位来表示一个像素的数据,用来表示一个像素的数据位越多,则这个像素的颜色值更加丰富、分的更细,颜色深度就更深。
一般来说像素深度有这么几种:1位、8位、16位、24位、32位。
6、颜色在计算机中的表示
(1)颜色的本质
颜色是主观存在,颜色其实是自然光在人的眼睛中和大脑中产生的一种映像。
颜色的本质决定于光的波长。
(2)自然光的颜色是连续的
光的波长是连续的,导致颜色也是连续的。理论上,只要你的眼睛分辨能力足够好,可以在自然界中发现无数种颜色。
(3)计算机中的颜色是离散的
计算机中不可能存储无数种颜色,所以必须将颜色有限化,所以就用有限种颜色来代表自然界中的无限种颜色。这个理论非常类似于之前学过的AD转换。
这种离散化表达颜色的缺点是不够真实,漏掉了很多种颜色。因此计算机中所能表达的颜色没有自然界中丰富,计算机屏幕上显示的图像和真实图像有差别。
计算机所能表达的颜色种类个数,这个参数叫:像素深度bpp。
(4)常见像素深度:1位、8位、16位、24位、32位
1位:用1个二进制位来表示颜色,这种就叫单色显示。示例就是理发店门口的LED屏。
8位:用8个二进制位来表示颜色,此时能表示256种颜色。这种叫灰度显示。这时候是黑白的,没有彩色,我们把纯白到纯黑分别对应255到0,中间的数值对应不同的灰。示例就是以前的黑白电视机。
16位:用16个二进制位表示颜色,此时能表示65536种颜色。这时候就可以彩色显示了,一般是RGB565的颜色分布(用5位二进制表示红色、用6位二进制表示绿色、用5位二进制表示蓝色)。这种红绿蓝都有的颜色表示法就是一种模拟自然界中所有颜色的表示方式。但是因为RGB的颜色表达本身二进制位数不够多(导致红绿蓝三种颜色本身分的都不够细致),所以这样显示的彩色失真比较重,人眼能明显看到显示的不真实。
24位:用24个二进制位来表示颜色,此时能表示16777216种颜色。这种表示方式和16位色原理是一样的,只是RGB三种颜色各自的精度都更高了(RGB各8位),叫RGB888。此时颜色比RGB565更加真实细腻,虽然说比自然界无数种颜色还是少了很多,不过由于人眼的不理想性,所以人眼几乎不能区分1677万种颜色和无数种颜色的差别了。于是乎就把这种RGB888的表示方法叫做真彩色。(RGB565就是假彩色)
32位:总共用32位二进制来表示颜色,其中24位表示红绿蓝三元色(还是RGB888分布),剩下8位表示透明度。这种显色方式就叫ARGB(A是阿尔法,表示透明度),现在PC机中一般都用ARGB表示颜色。补充:颜色的三基色是RGB,也就是说所有的颜色都可以由红绿蓝三种颜色组成。
二、S5PV210的LCD控制器
1、LCD控制器结构框图
LCD控制器部分内容在数据手册的第1162页。
S5PV210的LCD控制器叫做FIMD,它是与图像处理相关的一些部件,与摄像头、图像处理部分有关联。FIMD在内部与AHB总线等相连接,在外部提供RGB接口、I80接口、YUV接口。我们实际使用的是RGB接口。
2、“虚拟屏幕”的概念
该内容位于数据手册1194页。
我们平时看到的屏幕所显示的场景,实际是由很多个虚拟屏幕叠加在一起的效果,比如新闻图像、电视台台标、下方飘动的字幕新闻。
虚拟屏幕其实就是内存中的一个显存区域,有几个显存区域就有几个虚拟屏幕。这些虚拟屏幕被映射到一个真实的显示屏,将来显示屏所显示的内容,其实是这几个虚拟屏幕所显示的内容的叠加。叠加时,上面一层会覆盖下面一层,因此要注意谁在前谁在后,这可以通过相关寄存器进行设置
使用(虚拟屏幕)而非(整个LCD只使用一个显存)的好处:第一,不污染源图像,方便程序处理;第二,减少屏幕刷新,提高显示效率,减少CPU工作量。
S5PV210的LCD控制器中有5个虚拟屏幕,Window0到Window4。
3、“虚拟显示”的概念
该内容位于数据手册1206页。
当我们需要在屏幕上看到不同的图像时,就需要对显存区域进行刷新。即使我们只需要将屏幕的显示稍微移动,也要将整个屏幕对应的显存空间全部刷新,其工作量和完全重新显示一幅图像是一样的。这样显然不好,因为CPU刷新屏幕的工作量很大,效率很低。
虚拟显示解决的问题,就是在小分辨率的屏幕上真实地显示大分辨率的图像。具体做法就是在内存中建立显存时,建立一个很大的显存区域,然后让LCD与其中的一部分区域对应,作为有效显示区域。将来要显示大图像时,将图像信息一次性全部加载到显示缓存区,然后通过移动有效显示区域就可以显示大图像的不同区域了。
4、主要寄存器简介
(1)DISPAY_CONTROL寄存器
- 设置为10或11,即RGB模式可行。
(2)VIDCON0寄存器
- bit0~1:为使能控制信号都使能;
- bit2:选择时钟源,选HCLK,连的是HCLC_DSYS 为166MHz;
- bit4:开启分频;
- bit13~6:设置时钟大小,时钟频率要小于控制器的最大时钟,也要小于LCD驱动器的最大时钟。
- bit18:设置RGB数据传输为并行还是串行,因为有24根数据线所以为并行;
- bit28~26:选择为RGB模式。
(3)VIDCON1寄存器
- bit5~6:设置HSYNC和VSYNC的极性,如果LCD的高低电平脉冲是相同的话,则Normal,如果极性相反则Invert。
(4)VIDTCONn寄存器
- n=0,1,2,3。
- 这些寄存器主要用来设置时序,需要根据LCD数据手册中的时序来设置。
(5)WINCONn寄存器
- n=0~4;
- bit0:使能window0 ;
- bit5-2:选择RGB888模式;
- bit15:设置输出顺序为 red green blue还是 blue green red,设置为1时BGR,设置为0时RGB。
(6)VIDOSD0A、VIDOSD0B、VIDOSD0C寄存器
- 都是用来设置内存中window0的大小;
- 比如设置为LCD屏幕的尺寸,即左上坐标为(0,0),右下坐标为(1023,767)。
(7)VIDW0xADD0Bx寄存器、VIDW0xADD1Bx寄存器
- VIDW0xADD0Bx寄存器,设置内存中window0的起始地址;
- VIDW0xADD1Bx寄存器,设置内存中window0的结束地址。
(8)SHODOWCON寄存器
- 设置虚拟windows显示,以下位可以分别设置哪个windows显示。
5、LCD有关的原理图
二、代码实战
1、宏定义
首先是一些寄存器或者常量相关的宏定义:
#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 (0) #define HBPD (40 - 1) #define HFPD (5 - 1) #define VSPW (0) #define VBPD (8 - 1) #define VFPD (8 - 1)// FB地址 #define FB_ADDR (0x23000000) //这个是任意的,只要对齐就好 #define ROW (480) #define COL (800) #define HOZVAL (COL-1) #define LINEVAL (ROW-1)
2、LCD进行初始化
// 初始化LCD void lcd_init(void) {// 配置引脚用于LCD功能/**LED、LCD、蜂鸣等,都是与gpio口有关的*因此,涉及这些器件的,都需要初始化gpio口*而初始化gpio,需要用到相关的配置寄存器,比如GPIOCON寄存器控制引脚的模式*而至于配置哪个GPIO,需要看原理图。*这里从原理图知LCD接到gpf0123,所以要到相应的配置寄存器中进行配置*/GPF0CON = 0x22222222;GPF1CON = 0x22222222;GPF2CON = 0x22222222;GPF3CON = 0x22222222;// 打开背光 GPD0_0(PWMTOUT0)/**由原理图可知,当PWMTOUT0接低电平时,正5V电压加到背光上,也就打开了背光灯*而查阅PWMTOUT0可知,它就是GPD0_0这个引脚*把GPD0_0这个引脚配置为输出模式,通过GPD0CON寄存器配置*然后配置GPD0_0这个引脚输出值为0,通过GPD0DAT寄存器配置*/GPD0CON &= ~(0xf<<0);GPD0CON |= (1<<0); // output modeGPD0DAT &= ~(1<<0); // output 0 to enable backlight// 10: RGB=FIMD I80=FIMD ITU=FIMD//由上面寄存器的分析可知,这里可以设置为10DISPLAY_CONTROL = 2<<0;// bit[26~28]:使用RGB接口// bit[18]:RGB 并行// bit[2]:选择时钟源为HCLK_DSYS=166MHzVIDCON0 &= ~( (3<<26)|(1<<18)|(1<<2) );// bit[1]:使能lcd控制器// bit[0]:当前帧结束后使能lcd控制器VIDCON0 |= ( (1<<0)|(1<<1) );// bit[4]:选择需要分频// bit[6~13]:分频系数为15,即VCLK = 166M/(14+1) = 11M,那么bit[6~13]=14;VIDCON0 |= 14<<6 | 1<<4;//屏幕有的是高电平脉冲提示开始,有的是低脉冲提示开始// H43-HSD043I9W1.pdf(p13) 时序图:VSYNC和HSYNC都是低脉冲提示开始 // s5pv210芯片手册(p1207) 时序图:VSYNC和HSYNC都是高脉冲提示开始,所以需要反转VIDCON1 |= 1<<5 | 1<<6;// 设置时序VIDTCON0 = VBPD<<16 | VFPD<<8 | VSPW<<0;VIDTCON1 = HBPD<<16 | HFPD<<8 | HSPW<<0;// 设置长宽(这里设置的是物理尺寸)VIDTCON2 = (LINEVAL << 11) | (HOZVAL << 0);// 设置windows0// bit[0]:使能// bit[2~5]:24bppWINCON0 |= 1<<0;WINCON0 &= ~(0xf << 2);//先清零WINCON0 |= (0xB<<2) | (1<<15);//再设置#define LeftTopX 0 #define LeftTopY 0 #define RightBotX 479 #define RightBotY 271// 设置windows1的上下左右//这里设置的是显存空间的大小,可以比屏幕大。//这里设置和物理屏幕一样大VIDOSD0A = (LeftTopX<<11) | (LeftTopY << 0);VIDOSD0B = (RightBotX<<11) | (RightBotY << 0);VIDOSD0C = (LINEVAL + 1) * (HOZVAL + 1);// 设置fb的地址VIDW00ADD0B0 = FB_ADDR;//这个可以任选的,但必须对齐(比如按照1M对齐)//每个像素点3个字节(24bit的bpp)就可以了的,但是为了对齐,用了4字节。VIDW00ADD1B0 = (((HOZVAL + 1)*4 + 0) * (LINEVAL + 1)) & (0xffffff);//上述两句表明了一个屏幕占用的空间大小// 使能channel 0传输数据SHADOWCON = 0x1; }
3、一些功能函数
(1)清屏
void lcd_clear_screen(int color) {int i, j;for (i = 0; i < ROW; i++)for (j = 0; j < COL; j++)lcd_draw_pixel(i, j, color); }
(2)显示点、线
// 描点 void lcd_draw_pixel(int row, int col, int color) {unsigned long * pixel = (unsigned long *)FB_ADDR;*(pixel + row * COL + col) = color;//假设像素点坐标为(row,col),则该像素点在内存中的位置计算方法如下 //有一个基地址,pixel(这里是一个指针,注意它是指针,加1会加上4个字节) //偏移量=每行多少个像素*有多少行*每个像素占用多少个字节+col个像素*每个像素多少字节 // COL * row * 4 + col * 4 //那么所处的位置应该是(int)pixel+COL*row*4 + col * 4 //或者简单地写成 pixel + row * COL + col }// 划横线 void lcd_draw_hline(int row, int col1, int col2, int color) {int j;// 描第row行,第j列for (j = col1; j <= col2; j++)lcd_draw_pixel(row, j, color); }// 划竖线 void lcd_draw_vline(int col, int row1, int row2, int color) {int i;// 描第i行,第col列for (i = row1; i <= row2; i++)lcd_draw_pixel(i, col, color); }// 划十字 void lcd_draw_cross(int row, int col, int halflen, int color) {lcd_draw_hline(row, col-halflen, col+halflen, color);lcd_draw_vline(col, row-halflen, row+halflen, color); }
(3)显示英文字符
每个英文字符占用16*8个像素,如果单色显示则每个像素占1bit,每个英文字符是16Byte。
要想得到显示,必须知道该字符的字模,然后填充即可。
// 写字 // 写字的左上角坐标(x, y),字的颜色是color,字的字模信息存储在data中 static void show_8_16(unsigned int x, unsigned int y, \unsigned int color, unsigned char *data) { // count记录当前正在绘制的像素的次序int i, j, count = 0; for (j=y; j<(y+16); j++) { for (i=x; i<(x+8); i++) { if (i<XSIZE && j<YSIZE) { // 在坐标(i, j)这个像素处判断是0还是1,如果是1写color;如果是0直接跳过if (data[count/8]) //表示一个字模中(16行,每行8个像素)的 //第几行(每行8bit)*/ & (1<<(count%8))/*表示该行的第几bitlcd_draw_pixel(i, j, color);} count++; } } } // 写字符串 // 字符串起始坐标左上角为(x, y),字符串文字颜色是color,字符串内容为str void draw_ascii_ok(unsigned int x, unsigned int y, \unsigned int color, unsigned char *str) {int i; unsigned char *ch;for (i=0; str[i]!='\0'; i++) { ch = (unsigned char *)ascii_8_16[(unsigned char)str[i]-0x20];show_8_16(x, y, color, ch); x += 8;if (x >= XSIZE){x -= XSIZE; // 回车y += 16; // 换行}} }
(4)显示中文字符
(5)显示图像
之前都是单色显示,每个像素点用一个bit来表示(不是0就是1)。
而图像是彩色的,每个像素点占用4字节(RGB888时),像素点情况很多。
显示图像需要取模,这里使用软件image2LCD来取模。
只要知道RGB顺序的含义,知道生成的步骤即可(一般设置输出的和屏幕实际大小一样)。
// 画800×480的图,图像数据存储在pData所指向的数组中 void lcd_draw_picture(const unsigned char *pData) {u32 x, y, color, p = 0;for (y=0; y<480; y++){for (x=0; x<800; x++){// 在这里将坐标点(x, y)的那个像素填充上相应的颜色值即可color = (pData[p+0] << 0) | (pData[p+1] << 8) | (pData[p+2] << 16);lcd_draw_pixel(x, y, color);p += 3;//注意这里的p不是指针,而是int数。//由于RGB888,三个一组,所以下一个像素是p+3}} }
4、验证步骤
由于这样处理得到的bin文件大于16KB,所以需要分成BL1,BL2部分。这里引用chapter10的分割方法,详见chapter14\6.LCD目录下的内容。最后使用烧录脚本(./write2sd),不能使用windows里的烧录工具。write2sd是一个脚本,内容如下:
#!/bin/sh sudo dd iflag=dsync oflag=dsync if=./BL1/BL1.bin of=/dev/sdb seek=1 sudo dd iflag=dsync oflag=dsync if=./BL2/BL2.bin of=/dev/sdb seek=45
bmp格式是原始图像,没有经过压缩?因此可以直接使用image2LCD软件解释成数据。而jpg、png、gif等经过压缩的图像不可以直接用image2LCD解释。需要先用对应的解压缩库对其解压缩,才能使用image2LCD软件?