2026/08/11 使用linux文件系统直接控制lcd屏(2)

一、提高LCD显示效率

内存映射

可以发现通过系统IO直接操作LCD的时候LCD屏的部分像素点会显示“黑线”,过段时间或者重新再次运行程序之后“黑线”会慢慢消失。其实这种现象并不是由于硬件原因导致的,而是系统调用的过程中数据传输效率较低导致的。
image

int buf[800*480] -->用户缓冲区-->循环放入颜色分量-->调用write()写入LCD --> 把用户缓冲区的数据拷贝到内核缓冲区--->内核把缓冲区中的颜色分量依次写入LCD的驱动程序-->LCD看到显示效果。

由于write函数是系统调用,所以数据需要先从用户态进入到内核态,将用户态中的缓冲区数据拷贝到操作系统的内核缓冲区当中,此时已经完成了第一次数据拷贝,然后再将内核缓冲区中的数据再次拷贝到磁盘当中,此时完成了第二次拷贝。在这个过程当中我们进行了两次拷贝,数据传输的效率是比较低的。
image

为了提高数据的传输效率,那就需要减少拷贝次数,可以通过Linux系统的一个叫做mmap()的函数接口实现。mmap的全称是memory map,翻译为中文也就是内存映射,其实是一种内存映射文件的方法。

通过内存映射,用户可以将一个文件或者其它对象映射到进程的地址空间,从而实现磁盘的一段物理地址和进程的一段虚拟地址建立对应关系。

image
通过mmap()这个系统调用函数,用户可以让多个进程之间通过映射到同一个普通文件实现共享内存,普通文件被映射到进程地址空间之后,进程可以向访问普通内存一样对文件进行一系列操作,就不需要调用read/write函数,比如为LCD屏进行内存映射,用户把颜色数据写入到内存中,则LCD屏的像素点也会进行刷新。

使用mmap可以减少一次拷贝,并且采用内存操作比read和write要简单一些,用户不需要在用户空间定义缓冲区来保存从内核缓冲区读上来的数据,从而节约了内存的消耗。

image

例:设计程序,利用系统IO函数实现让开发板的LCD屏填充为德国国旗,要求使用内存映射的方式实现,程序设计完成后下载到开发板进行验证并观察效果。(仅作例子,无任何不良引导)

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <linux/fb.h>
#include <sys/ioctl.h>
#include <sys/types.h>
#include <sys/stat.h>
 
#define FB_DEV "/dev/fb0"

int main()
{
    int lcd_fd = open(FB_DEV, O_RDWR);
    if (lcd_fd < 0) 
    {
        perror("open /dev/fb0 failed");
        return -1;
    }

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

    int WIDTH = lcd_vinfo.xres;
    int HEIGHT = lcd_vinfo.yres;
    // 内存映射:32位屏,每个像素4字节
    unsigned int *lcd_mp = mmap(NULL, 
                                WIDTH*HEIGHT*4, 
                                PROT_READ | PROT_WRITE, 
                                MAP_SHARED, 
                                lcd_fd, 
                                0);
    if (lcd_mp == MAP_FAILED)
    {
        perror("mmap error");
        close(lcd_fd);  
        return -1;
    }

    // 32位 ARGB8888 颜色
    unsigned int color_black  = 0x00000000;   // 黑
    unsigned int color_red    = 0x00FF0000;   // 红
    unsigned int color_gold   = 0x00FFCC00;   // 金黄

    // 上1/3 黑色 0~159行
    for (int y = 0; y < HEIGHT/3; y++)
    {
        for (int x = 0; x < WIDTH; x++)
        {
            lcd_mp[y * WIDTH + x] = color_black; // 修正指针名 + 索引公式
        }
    }
    // 中间1/3 红色 160~319行
    for (int y = HEIGHT/3; y < HEIGHT*2/3; y++)
    {
        for (int x = 0; x < WIDTH; x++)
        {
            lcd_mp[y * WIDTH + x] = color_red;
        }
    }
    // 底部1/3 金黄色 320~479行
    for (int y = HEIGHT*2/3; y < HEIGHT; y++)
    {
        for (int x = 0; x < WIDTH; x++)
        {
            lcd_mp[y * WIDTH + x] = color_gold;
        }
    }

    munmap(lcd_mp, WIDTH*HEIGHT*4);
    close(lcd_fd);
    return 0;
}

验证现象:
image
image

posted @ 2026-08-11 22:40  !城北徐公.!  阅读(7)  评论(0)    收藏  举报