LCD显示原理及应用

Linux环境下LCD显示原理及应用

1. LCD原理概述

LCD(Liquid Crystal Display)液晶显示器是一种广泛应用于各种电子设备中的显示技术,它利用液晶分子在电场作用下的排列状态来控制光的透过,从而实现图像显示。

2. LCD驱动原理

LCD显示屏的驱动通常需要硬件和软件两方面的支持:

  • 硬件支持: LCD显示屏需要与嵌入式系统的硬件平台进行连接,通常需要考虑接口协议(如RGB、MIPI DSI)、电源管理、时序控制等。
  • 软件支持: 驱动程序负责控制LCD显示屏的初始化、数据传输、显示内容更新等操作。在Linux系统中,LCD驱动程序通常以设备驱动的形式存在,与内核紧密结合。

3. LCD驱动开发流程

LCD驱动的开发通常涉及以下几个主要步骤:

  • 1. 硬件平台支持: 确保嵌入式系统的硬件平台能够正确连接LCD显示屏,包括电源、信号线等连接。
  • 2. 内核配置: 确保Linux内核已经正确配置了LCD显示屏相关的驱动选项,如内核配置中的Framebuffer支持、LCD显示屏驱动支持等。
  • 3. 驱动程序编写: 编写LCD显示屏的驱动程序,包括初始化、数据传输、显示内容更新等功能。驱动程序通常以C语言编写,并且需要注册到Linux内核中。
  • 4. 设备树配置: 在设备树(Device Tree)中配置LCD显示屏的信息,包括连接的接口、时序、分辨率等信息,以便Linux内核正确识别和初始化LCD设备。
  • 5. 软件集成与测试: 将编写的LCD驱动程序集成到Linux内核中,编译生成新的内核镜像,并在目标平台上进行测试验证,确保LCD显示功能正常。

像素(pixel)

像素(pixel)是图像的最小单位,是由数字、颜色和位置组成的基本元素。它是英文“picture element”的缩写,是数字图像的构成要素之一。在数字图像中,每个像素都有其特定的位置坐标和对应的颜色值,这些颜色值通常由红、绿、蓝三原色的不同组合来表示,也称为RGB值。

像素的特征
位置坐标: 每个像素都有其在图像中的位置坐标,通常用行号和列号表示,如(x,y)。

颜色值: 每个像素都有其对应的颜色值,用来表示在该位置显示的颜色,常见的颜色表示方式包括RGB、CMYK等。

大小: 像素的大小通常由图像的分辨率决定,分辨率越高,每英寸所包含的像素点就越多,像素点的大小就越小。

密度: 像素密度指的是在一定区域内像素的数量,通常以每英寸的像素数量(dpi,dots per inch)来衡量。

分辨率(imageResolution)

分辨率(image resolution)是指数字图像中每个单位长度包含的像素数量,通常以水平方向和垂直方向的像素数来表示。分辨率决定了图像的清晰度和细节程度,是评估图像质量的重要指标之一。

分辨率的表示方法
绝对分辨率: 绝对分辨率指的是图像的实际像素数量,通常以水平像素数和垂直像素数表示,如1920x1080。

相对分辨率: 相对分辨率指的是图像的像素数量与物理尺寸之间的关系,通常以每英寸的像素数量(dpi,dots per inch)来表示。

分辨率对图像质量的影响
清晰度: 分辨率越高,图像中包含的像素数量越多,图像显示得越清晰。

细节度: 高分辨率图像能够显示更多的细节和纹理,使图像更加逼真。

打印质量: 对于打印图像,分辨率越高,打印出的图像质量越好,细节更加清晰。

分辨率的选择
屏幕显示: 选择合适的分辨率可以提高屏幕显示的清晰度和细节度,但也会增加系统资源的消耗。

打印输出: 对于打印输出,要根据打印机的分辨率和输出尺寸选择合适的图像分辨率,以保证打印质量。

网络传输: 在网络传输图像时,可以根据传输带宽和目标显示设备的分辨率选择合适的图像分辨率,以节省传输时间和带宽。

色彩深度(BPP,bit per pixel)

色彩深度(BPP,bit per pixel)是指数字图像中每个像素用多少位来表示其颜色信息。它决定了图像能够显示的颜色数量和色彩范围,是评估图像质量的重要指标之一。常见的色彩深度包括1位(单色)、8位(256色)、24位(真彩色)等。

色彩深度 描述 能表示的颜色数量 色彩范围
1位 单色 2(黑白) 黑、白
8位 灰度 256 0~255个灰度级
16位 高彩色 65536 65536种颜色
24位 真彩色 16777216 256×256×256种颜色
32位 真彩色 + Alpha通道 16777216 256×256×256种颜色 + 透明度

驱动架构 Framebuffer

Framebuffer(帧缓冲)是计算机图形显示系统中用于存储图像数据的内存区域。在Linux系统中,Framebuffer驱动提供了一种通用的图形显示接口,允许应用程序直接访问图形硬件,而不必了解特定硬件设备的细节。

Framebuffer驱动在Linux系统中属于底层机制,抽象了各种显示设备的具体细节,提供了一个干净、抽象的编程接口。它将显卡硬件抽象成可直接操作的内存,并提供了封装好的各种操作和设置,大大提高了内核开发的效率。Framebuffer驱动将屏幕上的每个像素点映射成一段线性内存空间,应用程序可以直接修改这段内存空间的数据,从而改变屏幕上的像素颜色。

LCD屏在Linux系统下属于字符设备,需要通过Framebuffer驱动程序进行控制。Framebuffer驱动安装后会在 /dev 目录下生成名为 fbn(n = 0 ~ 31)的设备文件,如LCD屏的设备文件名通常为 /dev/fb0

在Linux系统中硬件设备主要分为两种:一种是字符设备(LCD、触摸屏、键盘......),另一种是块设备(硬盘、U盘......),这两种类型的硬件设备都需要由驱动程序(xxx.ko)控制,当驱动程序安装完成后会自动生成硬件的设备文件,用户才可以通过设备文件去访问硬件。

window系统的硬件驱动安装完成后会在设备管理器中生成设备文件,而Linux系统的硬件驱动安装完成后会自动在 /dev****目录下生成设备文件。

硬件参数

在Linux系统下是利用Framebuffer子系统来驱动显示设备的,所以Framebuffer子系统会读取LCD屏的硬件信息并存储在内核空间中,关于LCD的硬件参数都是定义在/usr/include/linux/fb.h头文件中。
** 三个重要的结构体**

// struct fb_fix_screeninfo
struct fb_fix_screeninfo {
    char id[16];				 // 设备id
    unsigned long smem_start;    // 显存起始地址(实际物理地址)
    __u32 smem_len;              // 显存大小
    __u32 type;                  // 像素构成
    __u32 type_aux;              // 交叉扫描方案
    __u32 visual;                // 色彩构成
    __u16 xpanstep;              // x轴平移步长(若支持)
    __u16 ypanstep;              // y轴平移步长(若支持)
    __u16 ywrapstep;             // y轴循环步长(若支持)
    __u32 line_length;           // 扫描线大小(字节)
    unsigned long mmio_start;    // 缺省映射内存地址(物理地址)
    __u32 mmio_len;              // 缺省映射内存大小
    __u32 accel;                 // 当前显示加速器芯片
    __u16 reserved[3];           // 保留
};

// struct fb_bitfield
struct fb_bitfield {
    __u32 offset;    // 色彩位域偏移量
    __u32 length;    // 色彩位域长度
    __u32 msb_right;
};

// struct fb_var_screeninfo
struct fb_var_screeninfo {
    __u32 xres;                      // 可见区的宽度分辨率
    __u32 yres;                      // 可见区的高度分辨率
    __u32 xres_virtual;              // 虚拟区的宽度分辨率
    __u32 yres_virtual;              // 虚拟区的高度分辨率
    __u32 xoffset;                   // 虚拟区到可见区的宽度偏移量
    __u32 yoffset;                   // 虚拟区到可见区的高度偏移量
    __u32 bits_per_pixel;            // 色彩深度
    __u32 grayscale;                 // 灰阶(若为非0)
    struct fb_bitfield red;          // 红色色彩位域构成
    struct fb_bitfield green;        // 绿色色彩位域构成
    struct fb_bitfield blue;         // 蓝色色彩位域构成
    struct fb_bitfield transp;       // 透明属性
    __u32 nonstd;                    // 非标准像素格式(若为非0)
    __u32 activate;                  // 设置参数合适生效
    __u32 height;                    // 图片高度(单位毫米)
    __u32 width;                     // 图片宽度(单位毫米)
    __u32 accel_flags;               // 显示卡选项
};

以上结构体在Linux系统的/usr/include/linux/fb.h中定义。struct fb_fix_screeninfo保存显示设备不能被修改的信息,struct fb_var_screeninfo保存显示设备可以被调整的信息,而struct fb_bitfield保存了色彩构成具体方案。

image-20240515014800394

xres_virtual和yres_virtual决定了虚拟区的大小,而xres和yres决定了屏幕上可见区域的大小,如果虚拟区比可见区大,我们还可以调整xoffset和yoffset来显示不同的 部分,比如,让yoffset逐渐变大,从显示效果上看来,就好像一张图片平滑地向上移动。

代码练习

利用系统IO接口函数显示纯色

练习:利用系统IO的相关接口实现在LCD屏幕上显示一种纯色(红色),注意LCD屏每个像素点都是4字节(ARGB),一般是把颜色以十六进制形式写入到LCD屏像素点中,进行程序设计。


//假设让LCD显示红色,这个程序需要在开发板中运行 需要交叉编译 arm-linux-gcc
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/mman.h>

int main(int argc, char const *argv[])
{
	//1.打开LCD  设备文件路径 "/dev/fb0"  O_RDWR
	int lcd_fd = open("/dev/fb0",O_RDWR);
	if (-1 == lcd_fd)
	{
		printf("open lcd error\n");
		return -1;
	}

	//2.对LCD进行内存映射  mmap函数 记得接收返回值
	int *lcd_mp = (int *)mmap(
								NULL,
								800*480*4,
								PROT_READ|PROT_WRITE,
								MAP_SHARED,
								lcd_fd,
								0
							 );

	if (MAP_FAILED == lcd_mp)
	{
		printf("mmap for lcd is error\n");
		return -1;
	}
	

	//3.把颜色分量写入到申请的映射内存空间中,通过地址偏移实现访问
	for (int i = 0;i < 800*480; ++i)
	{
		lcd_mp[i] = 0x00FF0000;  //红色的RGB为0XFF0000
	}

	
	//4.关闭LCD并解除内存映射
	munmap(lcd_mp,800*480*4);
	close(lcd_fd);

	return 0;
}

利用ioctl函数获取LCD的硬件参数

练习:设计程序,利用ioctl函数获取LCD的硬件参数,把LCD屏幕的宽和高以及色深的位数输出到屏幕,下载程序到开发板并进行验证。 提示:必须包含该头文件 <linux/fb.h> !!!!

#include <sys/ioctl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <linux/fb.h>


int main(int argc, char const *argv[])
{
	//1.打开LCD
	int lcd_fd = open("/dev/fb0",O_RDWR);


	//2.利用ioctl函数获取LCD硬件参数
	struct fb_var_screeninfo lcd_vinfo;
	ioctl(lcd_fd,FBIOGET_VSCREENINFO,&lcd_vinfo);

	//3.输出LCD的宽、高、色深
	printf("lcd height= %-5d\n", lcd_vinfo.yres); 		//480   
	printf("lcd width= %-5d\n", lcd_vinfo.xres);  		//800
	printf("lcd bpp=%-5d\n",lcd_vinfo.bits_per_pixel);	//32
	
	return 0;
}


检测LCD屏幕坏点刷新屏幕

练习:LCD每隔一秒显示一种单色,用来检测LCD屏幕有没有坏点。

posted @   sanjiudemiao  阅读(126)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 分享4款.NET开源、免费、实用的商城系统
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
· 上周热点回顾(2.24-3.2)
点击右上角即可分享
微信分享提示