2026/08/10 使用linux文件系统直接控制lcd屏(1)
一、LCD屏的原理与应用
基本概念
LCD (Liquid Crystal Display)的中文称为液晶显示器,构造原理就是在两片平行的玻璃基板当中放置液晶盒,下基板玻璃上设置TFT(薄膜晶体管),上基板玻璃上设置彩色滤光片(CF),彩色滤光片是由红、绿、蓝三种颜色构成的滤片,有规律地制作在一块大玻璃基板上。

结构分析
彩色滤光片是LCD液晶屏彩色化的关键部件,彩色滤光片通过滤光的方式可以产生RGB三原色,然后再将三原色以不同的强弱比例进行混合,从而呈现各种颜色,这样LCD才可以显示全彩色。

显示单位
屏幕上显示颜色的最小单位叫做像素,像素英文叫 pixel。位图(比如jpg、bmp等格式的常见图片)也是由一个个的像素点构成的,跟屏幕的像素点的概念一样。原理上讲,将一张位图显示到屏幕上,就是将图片上的像素点一个个复制到屏幕像素点上。

像素数量
图片或者屏幕的宽、高两个维度上的像素点数量被称为分辨率,分辨率决定了位图图像细节的精细程度。通常情况下,图像的分辨率越高则所包含的像素就越多,那么图像就越清晰,印刷的质量也就越好。当然,它也会增加文件占用的存储空间,也就是分辨率越高,则占用内存越大。

像素色深
每个像素点所占的bit位数被称为色深,色深的单位是bit。简单理解:色深就是指一个像素点的大小,一般有8位、16位、24位或32位,比如32位,也就是一个像素点由4字节组成。分别是ARGB,其中A指的是透明度,一般的LCD都不支持。RGB指的是三原色,每种颜色占1字节,也就是每种颜色的范围是0 ~ 255。

32位色深的LCD屏一般被称为真彩屏。色深决定了一个像素点所能表达的颜色的丰富程度,色深越大,色彩表现力越强。
驱动架构
LCD属于硬件设备,所以需要通过驱动程序才能控制,而在Linux系统中是通过 Framebuffer驱动子系统来控制LCD的。Frame是帧的意思,buffer是缓冲的意思,所以Framebuffer也被称为帧缓冲。Linux系统下面有多个子系统,其中 Framebuffer子系统就是Linux系统为显示设备提供的一个驱动程序接口,用于驱动显示设备。
Framebuffer驱动子系统会从内存中申请一块空间用于保存一帧图像的颜色数据,这块内存会被映射到进程的地址空间,这样进程就可以直接进行对帧缓冲进行读写操作,并且写操作可以立即刷新到屏幕上。
可以理解为Framebuffer驱动子系统把屏幕上的每个像素点映射成一段线性内存空间,应用程序直接修改这段内存空间的数据就相当于改变屏幕上某一像素点的颜色。
设备文件
在Linux系统中硬件设备主要分为两种:一种是字符设备(LCD、触摸屏、键盘......),另一种是块设备(硬盘、U盘......),这两种类型的硬件设备都需要由驱动程序(xxx.ko)控制,当驱动程序安装完成后会自动生成硬件的设备文件,用户才可以通过设备文件去访问硬件。
比如window系统的硬件驱动安装完成后会在设备管理器中生成设备文件,而Linux系统的硬件驱动安装完成后会自动在 /dev目录下生成设备文件。

LCD屏在Linux系统下属于字符设备,需要通过Framebuffer驱动程序进行控制,而Framebuffer驱动安装之后会在 /dev目录下生成名字叫做fbn(n = 0 ~ 31)的设备文件,比如当前LCD屏的设备文件的名称就是/dev/fb0。
例1.在linux开发板的LCD上画一个圆
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
int main(int argc, char const *argv[])
{
int lcd_fd = open("/dev/fb0",O_RDWR);
if (-1 == lcd_fd)
{
printf("open lcd failed\n");
exit(1);
}
int colorbuf[800*480] = {0};
for (int i = 0; i < 800*480;++i)
{
colorbuf[i] = 0x00ff0000;
}
for (int y = 240-100; y < 240+100; ++y)
{
for (int x = 400-100; x < 400+100; ++x)
{
if((x-400)*(x-400)+(y-240)*(y-240) <= 100*100)
{
colorbuf[800*y+x] = 0x0000ff00;
}
}
}
write(lcd_fd,colorbuf,800*480*4);
close(lcd_fd);
return 0;
}
验证现象:

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


通过fb.h可以看到头文件中存在三个比较重要的结构体,分别是struct fb_fix_screeninfo以及struct fb_var_screeninfo以及struct fb_bitfield,除了这三个结构体之外,可以发现头文件中存在大量的宏定义,用户可以通过这些宏定义来指定读取LCD的部分信息。
(1)struct fb_fix_screeninfo结构体
struct fb_fix_screeninfo结构体主要用于获取FrameBuffer的固定参数,用户无法在应用层修改这些参数,只能通过系统调用ioctl函数使用宏定义FBIOGET_FSCREENINFO去获取这些参数。


(2)struct fb_var_screeninfo结构体
struct fb_var_screeninfo结构体主要用于获取和设置FrameBuffer的可变屏幕参数,包括分辨率、像素位深、像素格式等。这些信息可以通过ioctl函数使用宏定义FBIOGET_VSCREENINFO获取,也可以通过宏定义FBIOPUT_VSCREENINFO修改。



文件控制
Linux系统提供了一个ioctl(input/output control)函数,该函数是一个专用于设备输入输出操作的系统调用,该调用传入一个跟设备有关的请求码,系统调用的功能完全取决于请求码。


请求码是通过宏定义的方式写入到硬件的驱动程序中,当驱动安装成功后,用户就可以通过头文件中的请求码向内核中的驱动程序发出请求,然后内核通过请求码去访问硬件,再把访问结果返回给用户。
例2:设计程序,利用ioctl函数获取LCD的硬件参数,把LCD屏幕的宽和高以及色深的位数输出到屏幕,下载程序到开发板并进行验证。
#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;
}

作者:bbzhu04@gmail.com ,多有不妥之处,望批评指正
本文原创,欢迎转载;转载请在文章显著位置标明原文链接: href="https://www.cnblogs.com/zhubb/p/22381740"
保留所有权限,未经许可禁止篡改、商用发布。

浙公网安备 33010602011771号