文章说明: Linux显示基于FrameBuffer帧缓冲
硬件平台: 树莓派4B
测试说明: 由于桌面系统会一直刷新屏幕,需要关闭桌面,进入单用户模式测试(init 3);


打开设备文件:

#include <linux/fb.h>
#include <sys/mman.h>
#include <sys/ioctl.h>

int fb;
fb = open("/dev/fb0", O_RDWR);
if (fd < 0)
{
    perror("can not open device");
    exit(1);
}
// 获取显示器可变参数
if (ioctl(fb, FBIOGET_VSCREENINFO, &vinfo))
{
  perror("get screen var info");
  exit(2);
}
printf("屏幕分辨率: %dx%d %dbit\r\n", vinfo.xres, vinfo.yres, vinfo.bits_per_pixel);

// 获取显示器固定参数
if (ioctl(fb, FBIOGET_FSCREENINFO, &finfo))
{
  perror("get screen fix info");
  exit(3);
}
// 每行字节数 = 行像素数*每个像素的字节数
printf("每行字节数: %d\r\n", finfo.line_length);

将FrameBuff映射至内存区:

int mem_size = vinfo.xres*vinfo.yres*vinfo.bits_per_pixel/8;
// 内存映射
pfb = (char*)mmap(0, mem_size, PROT_READ | PROT_WRITE, MAP_SHARED, fb, 0);
if(pfb == NULL)
{
  perror("mmap error");
}
int x, y;
int offset;
// 画一个300*200的蓝色矩形
for (y = 0; y < 200; y++)
{
  offset = y * finfo.line_length;
  for (x = 0; x < 300; x++)
  {
    // 计算内存位置(bpp=32bit)
    *(pfb + offset)     = 255; // B
    *(pfb + offset + 1) = 0;   // G
    *(pfb + offset + 2) = 0;   // R
    *(pfb + offset + 3) = 0;   // 透明度(没发现啥用)
    offset += 4;               // 下一个位置(vinfo.bits_per_pixel / 8)
  }
}

从文件读取24位图BMP文件并显示:
由于24位图文件仅存了RGB信息,与fb的32bit的不匹配,所以不能直接用cat命令显示,设置第4个字节的信息。

int fd;
int ret;
char buff[100];
char* p = pfb;

fd = open("./Tulips.bmp", O_RDONLY);
if(fd < 1)
{
  perror("can not open file");
}
// 跳过54字节的BMP文件头
ret= read(fd, buff, 54);         

while(cnt)
{
  ret = read(fd, buff, 3);
  *p++ = buff[0];     // 将前3个字节的RGB信息原样输出
  *p++ = buff[1];
  *p++ = buff[2];
  *p++ = 0;           // 设置第4字节的信息
}
close(fd);

显示的图倒立的,原因是BMP格式本身的问题,需要进行显示调整:

int *p = (int *)(pfb + mem_size) - 1;
while (read(fd, (char *)p--, 3))
{
  if (p < pfb)
  {
    break;
  }
}