LCD操作原理

一、LCD原理介绍

  1. LCD内部内部结构
    (1)lcd由Framebuffer、lcd屏幕、信号线、电子枪、lcd控制器组成。
    (2)Framebuffer提供显示数据、lcd屏幕显示、信号线传输Frambuffer中的数据和lcd控制器发出的信号、电子枪根据数据将颜色打在lcd屏幕上。
  2. LCD电路图在这里插入图片描述在这里插入图片描述
    (1)DE:LCD控制信号;
    (2)VLINE:HSYNC,换行信号;
    (3)R1~B4:RGB565,像素数据线;
    (4)YU~XR:中断信号线;
    (5)LEDL~LEDR:LCD背光线;
    (6)CLK:时钟线;
    (7)VFRAME:VSYNC信号;
  3. LCD操作原理
    (1)lcd显示的数据存储在FrameBuffer中,FrameBuffer是内存中的一块的区域,可以自己设定;
    (2)FrameBuffer中的数据存储方式,需要参考lcd芯片手册的bpp(bit per pixel每个像素占了多少位);
    (3)bpp分为24(32)bpp、16bpp、8bpp,lcd上每个像素所显示的颜色分别占用FramBuffer中的4Byte、2Byte、1Byte;
    (4)24bpp的R:G:B(红绿蓝)分配为8:8:8,16bpp为5:6:5;8bppFrameBuffer中存储的非像素数据,而是RGB在调色板中的地址;
    (5)由于8bpp在FrameBuffer中无法存储颜色数据,因此会在内存特定的区域即调色板中存放16bpp的数据,而存放的地址会放到FrameBuffer中,lcd控制器会自动根据8pp的数据索引到调色板中对应的像素数据;
    (6)需要根据lcd芯片手册中的时序、引脚极性、分辨率、bpp,以及设定的FrameBuffer地址,结合2440芯片手册,来设置lcd控制器,使lcd控制器会在适当的时候发出对应的数据信号和控制信号
    (7)lcd控制器将像素数据发送给lcd屏幕,lcd根据像素数据,每一个VCLK时钟周期,就在屏幕上从左到右显示一个像素点;
    (8)当像素点移到最右端时,lcd控制器从会发出HSYNC信号,像素点就会移到下一行的行首,如此循环;
    (9)当移到最下端最后一个像素点时,lcd控制器会发出VHYNC信号,像素点回到第一行的行首,如此循环;
    (10)lcd屏幕像素如何显示主要取决于FrameBuffer中数据的存储,因此要实现画点画线画圆显示字符,都要向FrameBuffer中写入不同的数据。

二、编程实验
本次实验尝试使用面向对象的编程思路,本程序可以满足添加多款不同的lcd和lcd控制器而无需改动的需求。

  1. 抽象出多款lcd参数作为调用模板:引脚极性、时序、分辨率、bpp、FrameBuffer地址
typedef struct lcd_params{
	char *name;
	pins_polarity pin_pol;	//引脚极性
	time_sequence time_seq;	//信号时序	
	int xres;	//分辨率、bpp
	int yres;
	int bpp;
	unsigned int FB_addr;	//FB_addr
}lcd_params, *p_lcd_params;

  1. 抽象出多款lcd控制器操作作为调用模板:初始化lcd控制器、使能、禁止使能lcd控制器
typedef struct lcd_con {
	char *name;
	void (*init)(p_lcd_params plcd);
	void (*enable)(void);
	void (*disable)(void);
}lcd_con, *p_lcd_con;
  1. 调用lcd参数模板,设置lcd_4_3的参数
lcd_params lcd_4_3 = {
	.name = "lcd_4_3",
	.pin_pol = {
		 .vclk  = normal,
 		 .hsync = invert,
		 .vsync = invert,
		 .VD = normal,
		 .DE = normal,
		 .INVPWREN = normal,
	},
	.time_seq = {
		.thf = 2,
		.thb = 2,
		.thp = 41,
		.tvf = 2,
		.tvb = 2,
		.tvp = 10,
		.vclk = 9,
	},
	.xres = 480,
	.yres = 272,
	.bpp = 16,
	.FB_addr = 0x33a00000,
};
  1. 调用lcd控制器模板设置2440的lcd控制器
/*初始化函数*/
void lcd_con_2440_init(p_lcd_params plcd)	
{
	LCDCON1 = (CLKVAL << 8) | (PNRMODE << 5) | (BPPMODE << 1);
	LCDCON2 = (VBPD << 24) | (LINEVAL << 14) | (VFPD << 6) | (VSPW << 0);
	LCDCON3 = (HBPD << 19) | (HOZVAL << 8) | (HFPD << 0);
	LCDCON4 = (HSPW << 0);
	LCDCON5 = (FRM565 << 11) | (INVVCLK << 10) | (INVVLINE << 9)|\
			  (INVVFRAME << 8) | (INVVD << 7) | (INVVDEN << 6) |\
			  (INVPWREN << 5) | (BPP_Display << 0);
	LCDSADDR1 = (plcd->FB_addr & ~(1 << 31)) >> 1;
	LCDSADDR2 = (FB_end_addr >> 1) & 0x1fffff;
}
/*使能函数*/
void lcd_con_2440_enable(void)
{
	LCDCON1 |= (1 << 0); 
	LCDCON5 |= (1 << 3);
	GPBDAT |= (1 << 0);
}
/*关闭使能函数*/
void lcd_con_2440_disable(void)
{
	LCDCON1 &= ~(1 << 0); 	 //Disable the video output and the LCD control signal.
	LCDCON5 &= ~(1 << 3);	 //Disable PWREN signal
	GPGDAT &= ~(1 << 0);	 //KEYBOARD
}

lcd_con lcd_con_2440 = {
	.name = "lcd_con_2440",
	.init 		= lcd_con_2440_init,
	.enable 	= lcd_con_2440_enable,
	.disable 	= lcd_con_2440_disable,
};
  1. 将所有的lcd控制器集合成一个数组,将lcd参数传给对应的lcd控制器
//==============================================
p_lcd_con lcd_con_arry[10];	//lcd_con数组
p_lcd_con g_lcd_con_selected;	//被选的lcd_con	

/*注册lcd控制器*/
int lcd_con_register(p_lcd_con clcd)
{
	p_con_arry[i] = clcd;
}

/*选择lcd控制器*/
int lcd_con_selected(char *name)
{
	g_lcd_con_selected = lcd_con_arry[i];
}
//================================================
/*传递lcd参数给lcd控制器*/
void lcd_con_init(p_lcd_params plcd)
{
		g_lcd_con_selected->init(plcd);
}
void lcd_con_enable(void)
{
		g_lcd_con_selected->enable();
}
void lcd_con_disable(void)
{
		g_lcd_con_selected->disable();
}

  1. 将所有的lcd控制器集合成一个数组,选择某款lcd和lcd控制器,将lcd的参数传给lcd控制器
//=============================================
/*注册lcd*/
p_lcd_params lcd_params_arry[10];
p_lcd_params g_lcd_params_selected;	

int lcd_params_register(p_lcd_params plcd)
{
	lcd_params_arry[i] = plcd;
}
/*选择lcd*/
int lcd_params_select(char *name)
{
	g_lcd_params_selected = lcd_params_arry[i];
}

//==========================================
/*选择lcd及lcd控制器,进行操作*/
void lcd_init(void)
{
	lcd_params_4_3_registe();	//注册lcd
	lcd_con_regist_add();	//注册lcd控制器
	lcd_params_select("lcd_4_3");	//选择lcd
	lcd_con_selected("lcd_con_2440");	//选择lcd控制器
	lcd_con_init(g_lcd_params_selected);	//初始化lcd
}
  1. 对lcd进行测试:向FrameBuffer中写数据
    (1)获取lcd的参数:根据分辨率,来设置显示多少数据及每个像素显示什么颜色;根据bpp,来设置向FrameBuffer写入数据的格式;以及FrameBuffer地址。
void lcd_test(void)
{
	int xres, yres, bpp;
	unsigned int FB_addr;
	unsigned short *p_16;
	unsigned int *p_32;
	int i, j;

	lcd_init();	//初始化lcd
	lcd_enable();	//使能lcd
	lcd_params_get(&xres, &yres, &bpp, &FB_addr);	//获取lcd参数
	
	/*显示整屏颜色*/	
	if (bpp == 16)	
	{
		p_16 = (unsigned short *)FB_addr;
		for (j = 0; j < yres; j++)
		{
			for (i = 0; i < xres; i++)
			{
				*p_16++ = 0x1f;
			}
		}
	if (bpp == 32)
	{
		for (j = 0; j < yres; j++)
		{
			for (i = 0; i < xres; i++)
			{
				*p_32 = 0x0000ff00;
			}
		}
	}

/*画圆*/
draw_circle(xres/2, yres/2, yres/4, 0xaabbcc);

/*画线*/
draw_line(xres, 0, xres, yres, 0xff0000);
  1. 屏幕显示字符
    (1)根据字符的ascii码,获得该字符在字符数组的位置,每个字符在数组中由8bit16Byte组成,每bit代表一个行像素,每byte代表一个列像素,所以每个字符由816个像素组成
    (2)将每个字符在数组的数据读出,逐个分析数据每行的8个bit,若1则对应的1个像素显示,若0则不显示,8bit结束后换下一个Byte,像素也换到下一行,以此来显示字符。
/*显示字符*/
void lcd_font_ascii(int x, int y, char c, int color)
{
	pc = (unsigned char *)fontdata_8x16[c * 16];	//得到字符在数组的位置
	int bit = 7;
	for (j = y; j < y + 16; j++)	//逐个Byte分析
	{
		for (i = x; i < x + 8; i++)	//逐个bit分析
		{
			if (*pc & (1 << bit))	//若bit - 1,则显示
			{
				lcd_FB_input(i, j, color);
			}
			bit--;	
		}
	}
}

(3)显示字符串就是在显示完一个字符后,在上一个字符的起始像素位置上行像素+8,如果到达屏幕最右端,则行像素 = 0,列像素+16;
(4)如果遇到的字符为换行字符,则行像素=0,列像素+16。

void lcd_str_ascii(int x, int y, char *str, int color)
{
	int i = 0, j;
	while(str[i])	//当字符串存在时
	{
		if (str[i] == '\r')	//如果字符为回到行首
		{
			x = 0;
		}
		else if(str[i] == '\n')	//如果字符为换行字符
		{
			y = y + 16;
		}
		else
		{
			lcd_font_ascii(x, y, str[i], color);	//打印当前字符
			x = x+8;	//原来起始地址 +8
			if( x > xres)	//屏幕最右端
			{
				x = 0; 
				y = y+16;
			}
		}
	}
}

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值