15_I.MX6ULL_LCD显示原理

Posted Tree-gg

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了15_I.MX6ULL_LCD显示原理相关的知识,希望对你有一定的参考价值。

目录

LCD简介

分辨率

像素格式

LCD屏幕接口

LCD时间参数

RGB LCD屏幕时序

像素时钟

显存


LCD简介

LCD全称是Liquid Crystal Display,也就是液晶显示器,是现在最常用到的显示器,手机、电脑、各种人机交互设备等基本都用到了LCD,最常见就是手机和电脑显示器了。LCD的构造是在两片平行的玻璃基板当中放置液晶盒,下基板玻璃上设置TFT(薄膜晶体管),上基板玻璃上设置彩色滤光片,通过TFT上的信号与电压改变来控制液晶分子的转动方向,从而达到控制每个像素点偏振光出射与否而达到显示目的。

分辨率

提起LCD显示器,我们都会听到720P、1080P、2K 或 4K 这样的字眼,这个就是LCD 显示器分辨率。LCD显示器都是由一个一个的像素点组成,像素点就类似一个灯(在OLED显示器中,像素点就是一个小灯),这个小灯是RGB灯,也就是由R(红色)、G(绿色)和B(蓝色)这三种颜色组成的,而RGB就是光的三原色。1080P的意思就是一个LCD 屏幕上的像素数量是1920*1080 个,也就是这个屏幕一列1080个像素点,一共 1920 列,如图所示:

 在图就是1080P显示器的像素示意图,X 轴就是LCD显示器的横轴,Y轴就是显示器的竖轴。图中的小方块就是像素点,一共有1920*1080=2073600个像素点。左上角的A点是第一个像素点,右下角的C点就是最后一个像素点。2K就是2560*1440个像素点,4K是3840*2160 个像素点。很明显,在 LCD尺寸不变的情况下,分辨率越高越清晰。同样的,分辨率不变的情况下, LCD尺寸越小越清晰。比如我们常用的24寸显示器基本都是1080P的,而我们现在使用的5寸的手机基本也是1080P的,但是手机显示细腻程度就要比24寸的显示器要好很多!由此可见,LCD 显示器的分辨率是一个很重要的参数,但是并不是分辨率越高的LCD就越好。衡量一款LCD的好坏,分辨率只是其中的一个参数,还有色彩还原程度、色彩偏离、亮度、可视角度、屏幕刷新率等其他参数。

像素格式

上面讲了,一个像素点就相当于一个RGB小灯,通过控制R、G、B这三种颜色的亮度就可以显示出各种各样的色彩。那该如何控制R、G、B 这三种颜色的显示亮度呢?一般一个R、G、 B这三部分分别使用8bit 的数据,那么一个像素点就是8bit*3-24bit,也就是说一个像素点3个字节,这种像素格式称为RGB888,如果再加入8bit的Alpha(透明)通道的话一个像素点就是 32bit,也就是 4 个字节,这种像素格式称为 ARGB8888。ARGB8888这种像素格式,一个像素占用4个字节的内存,这四个字节每个位的分配如图所示:

 在图中,一个像素点是4个字节,其中bit31~bit24是Alpha通道,bit23-bit16是RED通道, bit15-bit14是GREEN通道, bit7-bit0是BLUE通道。所以红色对应的值就是0X00FF0000,蓝色对应的值就是0X000000FF,绿色对应的值为0X0000FF00。通过调节R、G、B的比例可以产生其它的颜色,比如0X00FFFF00就是黄色,0X00000000就是黑色,0X00FFFFFF就是白色。大家可以打开电脑的“画图”工具,在里面使用调色板即可获取到想要的颜色对应的数值,如图所示:

 

LCD屏幕接口

LCD屏幕或者说显示器有很多种接口,比如在显示器上常见的VGA、HDMI、DPMIPI等等,但是 I.MX6U不支持这些接口。I.MX6U支持RGB接口的LCD,RGBLCD接口的信号线如表所示:

表就是RGBLCD的信号线,R[7:0]、G[7:0]和B[7:0]这24根是数据线,DE、VSYNC、HSYNC和 PCLK这四根是控制信号线。RGB LCD一般有两种驱动模式:DE模式和HV模式,这两个模式的区别是DE模式需要用到DE信号线,而HV模式不需要用到DE信号线,在DE模式下是可以不需要HSYNC信号线的,即使不接HSYNC信号线LCD也可以正常工作。 

LCD时间参数

如果将LCD显示一帧图像的过程想象成绘画,那么在显示的过程中就是用一根“笔”在不同的像素点画上不同的颜色。这根笔按照从左至右、从上到下的顺序扫描每个像素点,并且在像素画上对应的颜色,当画到最后一个像素点的时候一幅图像就绘制好了。假如一个LCD的分辨率为1024*600,那么其扫描如图所示:

 

结合图来看一下LCD是怎么扫描显示一帧图像的。一帧图像也是由一行一行组成的。HSYNC是水平同步信号,也叫做行同步信号,当产生此信号的话就表示开始显示新的一行了,所以此信号都是在图的最左边。当VSYNC信号是垂直同步信号,也叫做帧同步信号,当产生此信号的话就表示开始显示新的一帧图像了,所以此信号在图的左上角。

在图可以看到有一圈“黑边”,真正有效的显示区域是中间的白色部分。那这一圈“黑边”是什么东西呢?这就要从显示器的“祖先” CRT显示器开始说起了, CRT显示器就是以前很常见的那种大屁股显示器,在2019年应该很少见了,如果在农村应该还是可以见到的。CRT显示器屁股后面是个电子枪,这个电子枪就是我们上面说的“画笔”,电子枪打出的电子撞击到屏幕上的荧光物质使其发光。只要控制电子枪从左到右扫完一行(也就是扫描一行),然后从上到下扫描完所有行,这样一帧图像就显示出来了。也就是说,显示一帧图像电子枪是按照‘Z’形在运动,当扫描速度很快的时候看起来就是一幅完成的画面了。

 当显示完一行以后会发出 HSYNC 信号,此时电子枪就会关闭,然后迅速的移动到屏幕的左边,当 HSYNC信号结束以后就可以显示新的一行数据了,电子枪就会重新打开。在 HSYNC信号结束到电子枪重新打开之间会插入一段延时,这段延时就图中的HBP。当显示完一行以后就会关闭电子枪等待HSYNC信号产生,关闭电子枪到HSYNC信号产生之间会插入一段延时,这段延时就是图中的HFP 信号。同理,当显示完一帧图像以后电子枪也会关闭,然后等到VSYNC信号产生,期间也会加入一段延时,这段延时就是图中的VFPVSYNC信号产生,电子枪移动到左上角,当 VSYNC信号结束以后电子枪重新打开,中间也会加入一段延时,这段延时就是图中的VBP

HBP、HFP、VBP 和 VFP 就是导致图中黑边的原因,但是这是CRT显示器存在黑边的原因,现在是LCD显示器,不需要电子枪了,那么为何还会有黑边呢?这是因为RGB LCD屏幕内部是有一个IC的,发送一行或者一帧数据给IC, IC是需要反应时间的。通过这段反应时间可以让IC识别到一行数据扫描完了,要换行了,或者一帧图像扫描完了,要开始下一帧图像显示了。因此,在LCD屏幕中继续存在HBP、HFP、VPB和VFP这四个参数的主要目的是为了锁定有效的像素数据。这四个时间是LCD重要的时间参数,后面编写LCD驱动的时候要用到的,至于这四个时间参数具体值是多少,那要需要去查看所使用的LCD数据手册了。

RGB LCD屏幕时序

上面讲了行显示和帧显示,看一下行显示对应的时序图,如图所示:

 

HSYNC:行同步信号,当此信号有效的话就表示开始显示新的一行数据,查阅所使用的LCD数据手册可以知道此信号是低电平有效还是高电平有效,假设此时是低电平有效。

HSPW:有些地方也叫做thp,是HSYNC信号宽度,也就是HSYNC信号持续时间。HSYNC信号不是一个脉冲,而是需要持续一段时间才是有效的,单位为CLK。

HBP:有些地方叫做thb,前面已经讲过了,术语叫做行同步信号后肩,单位是CLK。

HOZVAL:有些地方叫做thd,显示一行数据所需的时间,假如屏幕分辨率为1024*600,那么HOZVAL就是1024,单位为CLK。

HFP:有些地方叫做thf,前面已经讲过了,术语叫做行同步信号前肩,单位是CLK。

当HSYNC信号发出以后,需要等待HSPW+HBP个CLK时间才会接收到真正有效的像素数据。当显示完一行数据以后需要等待HFP个CLK时间才能发出下一个HSYNC 信号,所以显示一行所需要的时间就是: HSPW + HBP+ HOZVAL +HFP

一帧图像就是由很多个行组成的,RGB LCD 的帧显示时序如图所示:

 

VSYNC:帧同步信号,当此信号有效的话就表示开始显示新的一帧数据,查阅所使用的LCD数据手册可以知道此信号是低电平有效还是高电平有效,假设此时是低电平有效。

VSPW:有些地方也叫做tvp,是VSYNC信号宽度,也就是VSYNC信号持续时间,单位为1行的时间。

VBP:有些地方叫做tvb,前面已经讲过了,术语叫做帧同步信号后肩,单位为1行的时间。

LINE:有些地方叫做tvd,显示一帧有效数据所需的时间,假如屏幕分辨率为1024*600,那么 LINE就是600行的时间。

VFP:有些地方叫做tvf,前面已经讲过了,术语叫做帧同步信号前肩,单位为1 行的时间。

显示一帧所需要的时间就是: VSPW+VBP+LINE+VFP个行时间,最终的计算公式:

T=(VSPW+VBP+LINE+VFP)* (HSPW+ HBP+HOZVAL+HFP)

因此我们在配置一款RGB LCD的时候需要知道这几个参数:HOZVAL(屏幕有效宽度)、LINE(屏幕有效高度)、HBP、HSPW、HFP、VSPW、VBP 和 VFP。RGB LCD屏幕的参数如表所示:

 

像素时钟

像素时钟就是RGBLCD的时钟信号,以ATK7016这款屏幕为例,显示一帧图像所需要的时钟数就是:

=(VSPW+VBP+LINE+VFP) * (HSPW+HBP+ HOZVAL+ HFP)

= (3 + 20 + 600 + 12) * (20 + 140 + 1024+ 160)

= 635 *1344

= 853440

显示一帧图像需要853440个时钟数,那么显示60帧就是:853440* 60=51206400~51.2M,所以像素时钟就是51.2MHz。

显存

在讲像素格式的时候就已经说过了,如果采用ARGB8888格式的话一个像素需要4个字节的内存来存放像素数据,那么1024*600分辨率就需要1024*600*4=2457600B≈2.4MB内存。但是RGB LCD内部是没有内存的,所以就需要在开发板上的DDR3中分出一段内存作为RGBLCD屏幕的显存,如果要在屏幕上显示什么图像的话直接操作这部分显存即可。方法很简单,直接定义一个32位的数组。u32 lcdframe[1024*600],一个像素占32位,创建分辨率等于多少个像素的数组。

求51单片机红外摇控接收c程序,并在数码管上显示键值出来?

求51单片机摇控接收c程序,就是按一下摇控就能在二位数码管上显示出对应的码值。

#include<reg51.h>
#include <intrins.h>
#define uchar unsigned char
#define uint unsigned int
#define ulong unsigned long

#define Nop() _nop_(); _nop_(); _nop_(); _nop_(); _nop_();

volatile ulong IRcode=0x00000000; //32位的键代码
volatile ulong Irdcode=0x00000000;
volatile uint customcode=0x0000; //16位用户码
volatile uint time_us=0x0000; //两个下降沿之间的时间

volatile uchar timeH,timeL; //保存TH1 TL的值

uchar Lcustomcode; //低8用户码
uchar Hcustomcode; //高8
uchar datacode; //8位键数据码
uchar mycode;
uchar Rdatacode; //8位键数据反码
uchar uc1ms;
uchar uc10ms;
uchar uc3ms;

uchar ucDispTime;
uchar ucDispOrder;
uchar ucDispCon;
uchar ucSpeakerTime;
unsigned char code LedData[16] = 0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90,0x88,0x83,0xc6,0xa1,0x86,0x8e;
unsigned char code LedCon[2] = 0x8f,0x4f;
unsigned char ucDispData[2]; // 存放显示数据
sbit led1 = P3^7;
sbit led2 = P3^6;
sbit power=P1^0; //电源开关
sbit BEEP= P2^1;
bit NewIRcode=0; //指示当处理完了32位码后,就有了新的遥控码
bit DataRight=0; //为1时读取数据正确
bit bSampleOk;
bit bSampling;
bit b10msInt;
bit b1msInt;
bit bKeySound;
bit b1msMain;
bit IR_E; //表示有新的遥控键控下就更新扫描数据
bit b3msint;

void SendDataToDispDevice();
void Ir_process();
void display();
void beeping();

/****** 晶振为12 MHZ*******/
/**定时器1,12 MHZ最大定时为65.53ms***/
//------------------------------------------------------------------------------
void init()

IP=0x09; //定时器1,外部中断0优先级高
TMOD=0x11; //定时器0,工作方式1 ; 定时器1,工作方式1
TCON=0x01; //外中断0下降沿触发,(包括TR1=0,TR0=0)
TH0=0xff; //初始化定时器0,定时0.2ms
TL0=0x47;
TH1=0x00; //初始化定时器1
TL1=0x00;

EA=1; //开全中断
ET0=1; //开放T0中断
ET1=1; //开放T1中断
EX0=1; //开放INT0
TR1=0;
TR0=1;


//--------------------------------------
void TimeProg(void)

b1msMain = b1msInt;
b1msMain=0;
b10msInt = 0;

if(b1msInt == 1)

b1msMain=1;
if(++uc10ms == 10)

uc10ms = 0;
b10msInt = 1;
if(bKeySound==1)
beeping();
bKeySound=0;




//void TimeProg(void)
//-------------------------------------interrupt0-------------------------------------
void IR_ISR() interrupt 0 using 1 //遥控器中断处理函数

static uchar cn;

TR1=0;
timeH=TH1;
timeL=TL1;
TH1=0;
TL1=0;
TR1=1; //开定时器中断1

time_us=(unsigned int)timeH;
time_us=time_us<<8;
time_us=time_us|timeL;

if(time_us>12200&&time_us<13000) cn=1;IRcode=0; //遇到引导码,就把cn清0,IRcode清0
//引导码的时间长度为9ms+4.5ms
if(cn<34)

if(time_us>950&&time_us<1120) //0

IRcode=IRcode|0x00000000;
if(cn<33) IRcode=IRcode>>1;


else if(time_us>1920&&time_us<2120) //1t > 1950 && t < 2150

IRcode=IRcode|0x80000000;
if(cn<33) IRcode=IRcode>>1;


//else if(time_us>10000&&time_us<11000) Irdcode=IRcode;cn=34; //遇到重复码
//cn用于记录接收到的数据位

cn++;
if(cn==34)
NewIRcode=1;
TR1=0;

Irdcode= IRcode; cn=0;
//读完32位码,则有新码产生



//--------------------------------------timer_ISR------------------------------
void Timer0_ISR() interrupt 1 using 2 //定时器0中断函数

TR0=0;
TH0=0xff; //初始化定时器0,定时0.2ms 晶振为11.0592 MHZ
TL0=0x47;
TR0=1;
if(++uc1ms == 5)

uc1ms = 0;
b1msInt=1;
if(++uc3ms==8)

uc3ms=0;
b3msint=1;
SendDataToDispDevice(); //n* ms送一次显示



//void Timer0IntProg() interrupt 1 using 1

void Timer1_ISR() interrupt 3 using 3 //定时器1中断函数

TR1=0;
TH1=0x00; //初始化定时器1
TL1=0x00;
TR1=1;


//--------------------SendDataToDispDevice----------
void SendDataToDispDevice()

unsigned char n;
//watchdog();
if(++ucDispOrder >= 2) ucDispOrder = 0; // 下一显示巡回

// 下面为发送控制数据 位控

if(ucDispOrder==0)
led1=0;
led2=1;
Nop();
Nop();


if(b3msint==1)
if(ucDispOrder==1)
led2=0;
led1=1;
Nop();
Nop();


// 下面为发送显示数据
n = LedData[ucDispData[ucDispOrder]];
P0=n;

//void SendDataToDispDevice()

//------------------------------------main()----------------------------------------------
void main()


init();
beeping();
while(1)

TimeProg();
Ir_process();
display();





void Ir_process()



if(NewIRcode==1) //如果有新的遥控码就读

NewIRcode=0; //读完之后清零,表示新码已读
customcode=(Irdcode>>16); //取红外码中的按码键
//取低8位用户码
Lcustomcode=customcode>>8;//取低8位按码键
datacode=(unsigned char)(customcode&0x00ff); //取高8位按码键

Rdatacode=Lcustomcode; //取低8位按码键的反码

if(~Rdatacode!=datacode)
DataRight=0;
Irdcode=0;
datacode=Rdatacode=0;
//校验用户码,反码

else
DataRight=1;
IR_E=1;
mycode=datacode;
if(DataRight==1) bKeySound = 1;DataRight=0;





void display()

/* unsigned char a[2];
a[0] = mycode & 0x0f;
mycode = mycode >> 4;
a[1] = mycode & 0x0f;
ET0 = 0;
ucDispData[0] = a[0];
ucDispData[1] = a[1];
ET0 = 1;*/
if(IR_E==1)

ET0 = 0;
ucDispData[0] = mycode & 0x0f;
mycode = mycode >> 4;
ucDispData[1] = mycode & 0x0f;
IR_E=0;
ET0 = 1;



/**********************************************************/
void delay(unsigned char x) //x*0.14MS

unsigned char a;
while(x--)

for (a = 0; a<13; a++) ;



/**********************************************************/
void beeping()

unsigned char i;

for (i=0;i<100;i++)

delay(4);
BEEP=!BEEP; //BEEP取反

BEEP=1;
//关闭蜂鸣器
参考技术A #include<reg52.h>
#include<intrins.h>
#define uchar unsigned char
#define uint unsigned int
sbit lcden = P2^7;
sbit lcdrs = P2^6;
sbit lcdwr = P2^5;
sbit IR = P3^2;
uchar IRCOM[6];//数组,用于存储红外编码
uchar code table1[] = "remote control";
uchar code table2[] = "CODE:";
void delayms(uchar x)// 延时x*0.14ms

uchar i;
while(x--)
for(i=0;i<13;i++)

void delay(uchar x) //延时xms

uchar i,j;
for(i=x;i>0;i--)
for(j=110;j>0;j--);

/****************************LCD部分***********************************************/
void write_com(uchar com)

lcden = 0;
lcdrs = 0;
lcdwr = 0;
P0 = com;
delay(5);
lcden = 1;
delay(5);
lcden = 0; //别忘了lcden拉低

void write_date(uchar date)

lcden = 0;
lcdrs = 1;
lcdwr = 0;
P0 = date;
delay(5);
lcden = 1;
delay(5);
lcden = 0;

void lcd_init(void)

lcden = 0;
lcdrs = 0;
lcdwr = 0;
delay(5);
write_com(0x38);
write_com(0x0c);
write_com(0x06);
write_com(0x01);

/*****************main()************************/
void main(void)

uchar count=0;
IR = 1;
lcd_init();
write_com(0x80);
while(table1[count]!='\0')

write_date(table1[count]);
count++;
delay(5);

count = 0;
write_com(0x80+0x40);
while(table2[count]!='\0')

write_date(table2[count]);
count++;
delay(5);


IE = 0x81; //开中断
TCON = 0x01;//脉冲负边沿触发
while(1);


/*********************红外中断**************************/
void IR_time() interrupt 0

uchar i,j,TimeNum=0;//TimeNum用来计IR高电平次数 从而判断是0还是1
EX0 = 0; //关闭中断
delayms(5);
if(1 == IR)

EX0 = 1;
return;

while(!IR) //跳过9ms前导低电平
delayms(1);
for(i=0;i<4;i++)

for(j=0;j<8;j++)

while(IR) //跳过4.5ms的前导高电平
delayms(1);
while(!IR) //跳过0.56ms的低电平
delayms(1);

while(IR)

TimeNum++; //计时高电平时间从而判断读取的是0还是1
delayms(1);

if(TimeNum>=30)//按键按下时间过长 跳过

EX0 = 1;
return;

IRCOM[i] = IRCOM[i]>>1;
if(TimeNum >= 8) //8*0.14ms 这时读取的是1;

IRCOM[i] = IRCOM[i]|0x80;

TimeNum = 0;


if(IRCOM[2]!=~IRCOM[3])//判断八位数据和八位数据反码是否相等

EX0 = 1;
return;

IRCOM[4] = IRCOM[2]&0x0f;//取低四位
IRCOM[5] = IRCOM[2]>>4; //IRCOM[5]取IRCOM[2]高四位
if(IRCOM[4] > 9) //转换成字符

IRCOM[4] = IRCOM[4] + 0x37;

else
IRCOM[4] = IRCOM[4] + 0x30;
if(IRCOM[5] > 9)

IRCOM[5] = IRCOM[5] + 0x37;

else
IRCOM[5] = IRCOM[5] + 0x30;
delay(5);
write_com(0x80 + 0x40 + 5);
write_date(IRCOM[5]);
write_date(IRCOM[4]);
EX0 = 1; //重新开启外部中断

参考资料来源 吴鉴鹰吧
参考技术B 自己到网上搜下啊,这么普遍的东西。随便找一个都能用。

以上是关于15_I.MX6ULL_LCD显示原理的主要内容,如果未能解决你的问题,请参考以下文章

51单片机LCD1602显示的例程

正点原子I.MX6U-MINI应用篇6嵌入式Linux在LCD屏幕上显示字符

硬件\_8080接口LCD时序分析

嵌入式开发(S5PV210)——LCD显示器

嵌入式Linux | 使Linux的启动信息显示到LCD上面&设置LCD屏幕为终端控制台

嵌入式Linux | 使Linux的启动信息显示到LCD上面&设置LCD屏幕为终端控制台