Linux下的Framebuffer编程

简介: Linux下的Framebuffer编程

前言

本篇文章将会介绍Linux下的Framebuffer编程,这里将会引用到百问网韦东山老师讲的一些知识。


一、LCD操作原理

在Linux系统中通过Framebuffer驱动程序来控制LCD。Frame是帧的意思,buffer是缓冲的意思,这意味着Framebuffer就是一块内存,里面保存着一帧图像。Framebuffer中保存着一帧图像的每一个像素颜色值,假设LCD的分辨率是1024x768,每一个像素的颜色用32位来表示,那么Framebuffer的大小就是:1024x768x32/8=3145728字节。


二、代码解析及编写程序的步骤

0.定义各类参数

下面这些参数后面我们会一 一介绍。

int fd_fb;
struct fb_var_screeninfo var; /* Current var */
int screen_size;
unsigned char *fbmem;
unsigned int line_width;
unsigned int pixel_width;

1.打开LCD设备节点

这些的fd_fb就是打开LCD设备返回的文件句柄。

/dev/fb0 :LCD设备节点(根据自己板子上面的节点填写)

  fd_fb = open("/dev/fb0", O_RDWR);
  if (fd_fb < 0)
  {
    printf("can't open /dev/fb0\n");
    return -1;
  }


  if (ioctl(fd_fb, FBIOGET_VSCREENINFO, &var))
  {
    printf("can't get var\n");
    return -1;
  }

var结构体解析:

这个结构体里面保存了LCD的相关信息,比如xres和yres就是代表了x方向的分辨率和y方向的分辨率。

大家的手机都有分辨率,最常见的就是1080×1920了。对应到xres和yres就是xres=1080,yres=1920。

大家只需要知道var这个结构体是用来保存ioctl获取到的LCD的参数信息即可。

bits_per_pixel:每一个像素的颜色用多少位表示

struct fb_var_screeninfo {
  __u32 xres;     /* visible resolution   */
  __u32 yres;
  __u32 xres_virtual;   /* virtual resolution   */
  __u32 yres_virtual;
  __u32 xoffset;      /* offset from virtual to visible */
  __u32 yoffset;      /* resolution     */
  __u32 bits_per_pixel;   /* guess what     */
  __u32 grayscale;    /* 0 = color, 1 = grayscale,  */
          /* >1 = FOURCC      */
  struct fb_bitfield red;   /* bitfield in fb mem if true color, */
  struct fb_bitfield green; /* else only length is significant */
  struct fb_bitfield blue;
  struct fb_bitfield transp;  /* transparency     */  
  __u32 nonstd;     /* != 0 Non standard pixel format */
  __u32 activate;     /* see FB_ACTIVATE_*    */
  __u32 height;     /* height of picture in mm    */
  __u32 width;      /* width of picture in mm     */
  __u32 accel_flags;    /* (OBSOLETE) see fb_info.flags */
  /* Timing: All values in pixclocks, except pixclock (of course) */
  __u32 pixclock;     /* pixel clock in ps (pico seconds) */
  __u32 left_margin;    /* time from sync to picture  */
  __u32 right_margin;   /* time from picture to sync  */
  __u32 upper_margin;   /* time from sync to picture  */
  __u32 lower_margin;
  __u32 hsync_len;    /* length of horizontal sync  */
  __u32 vsync_len;    /* length of vertical sync  */
  __u32 sync;     /* see FB_SYNC_*    */
  __u32 vmode;      /* see FB_VMODE_*   */
  __u32 rotate;     /* angle we rotate counter clockwise */
  __u32 colorspace;   /* colorspace for FOURCC-based modes */
  __u32 reserved[4];    /* Reserved for future compatibility */
};

3.mmap映射Framebuffer,在Framebuffer中写入数据

line_width:var.xres * var.bits_per_pixel代表每一行有多少个像素

/8就代表了每一行有多少个字节

pixel_width :每一个像素多少个字节

screen_size :计算出整个屏幕所占字节的大小

fbmem :Framebuffer是存在于驱动程序当中的,在应用程序中不可直接使用,需要使用mmap将驱动程序的内存映射到应用程序中才可进行操作。

  line_width  = var.xres * var.bits_per_pixel / 8;
  pixel_width = var.bits_per_pixel / 8;
  screen_size = var.xres * var.yres * var.bits_per_pixel / 8;
  fbmem = (unsigned char *)mmap(NULL , screen_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd_fb, 0);
  if (fbmem == (unsigned char *)-1)
  {
    printf("can't mmap\n");
    return -1;
  }

三、LCD操作函数解析

1.描点函数

pen_8 ,pen_16,pen_32参数代表的是起笔点,因为我使用的LCD每个像素是8位的,所以我这里只需要计算pen_8 即可,其他两个只需要进行一次转换即可。

pen_8 的计算

0bdf3f4457604ee9bb4eb0a1ef057695.png

void lcd_put_pixel(int x, int y, unsigned int color)
{
  unsigned char *pen_8 = fbmem+y*line_width+x*pixel_width;
  unsigned short *pen_16; 
  unsigned int *pen_32; 
  unsigned int red, green, blue;  
  pen_16 = (unsigned short *)pen_8;
  pen_32 = (unsigned int *)pen_8;
  switch (var.bits_per_pixel)
  {
    case 8:
    {
      *pen_8 = color;
      break;
    }
    case 16:
    {
      /* 565 */
      red   = (color >> 16) & 0xff;
      green = (color >> 8) & 0xff;
      blue  = (color >> 0) & 0xff;
      color = ((red >> 3) << 11) | ((green >> 2) << 5) | (blue >> 3);
      *pen_16 = color;
      break;
    }
    case 32:
    {
      *pen_32 = color;
      break;
    }
    default:
    {
      printf("can't surport %dbpp\n", var.bits_per_pixel);
      break;
    }
  }
}

2.显示字符函数

void lcd_put_ascii(int x, int y, unsigned char c, unsigned int color)
{
  unsigned char *dots = (unsigned char *)&fontdata_8x16[c*16];
  int i, b;
  unsigned char byte;
  for (i = 0; i < 16; i++)
  {
    byte = dots[i];
    for (b = 7; b >= 0; b--)
    {
      if (byte & (1<<b))
      {
        /* show */
        lcd_put_pixel(x+7-b, y+i, color); /* 白 */
      }
      else
      {
        /* hide */
        lcd_put_pixel(x+7-b, y+i, 0); /* 黑 */
      }
    }
  }
}

总结

本篇文章就介绍到这里,Framebuffer编程的编程其实并不算很难,大家只要理清楚这些参数即可。具体的代码请参考百问网,这里我只做重要部分介绍。

相关文章
|
1月前
|
消息中间件 存储 缓存
【嵌入式软件工程师面经】Linux系统编程(线程进程)
【嵌入式软件工程师面经】Linux系统编程(线程进程)
57 1
|
10天前
|
Linux 网络安全 开发工具
linux 常用命令【编程必备】
linux 常用命令【编程必备】
23 4
|
10天前
|
小程序 Linux
【编程小实验】利用Linux fork()与文件I/O:父进程与子进程协同实现高效cp命令(前半文件与后半文件并行复制)
这个小程序是在文件IO的基础上去结合父子进程的一个使用,利用父子进程相互独立的特点实现对数据不同的操作
|
10天前
|
缓存 网络协议 算法
【Linux系统编程】深入剖析:四大IO模型机制与应用(阻塞、非阻塞、多路复用、信号驱动IO 全解读)
在Linux环境下,主要存在四种IO模型,它们分别是阻塞IO(Blocking IO)、非阻塞IO(Non-blocking IO)、IO多路复用(I/O Multiplexing)和异步IO(Asynchronous IO)。下面我将逐一介绍这些模型的定义:
|
1月前
|
算法 Linux 测试技术
Linux编程:测试-高效内存复制与随机数生成的性能
该文探讨了软件工程中的性能优化,重点关注内存复制和随机数生成。文章通过测试指出,`g_memmove`在内存复制中表现出显著优势,比简单for循环快约32倍。在随机数生成方面,`GRand`库在1000万次循环中的效率超过传统`rand()`。文中提供了测试代码和Makefile,建议在性能关键场景中使用`memcpy`、`g_memmove`以及高效的随机数生成库。
|
17天前
|
机器学习/深度学习 Unix Java
技术笔记:Linux之Shell脚本编程(一)
技术笔记:Linux之Shell脚本编程(一)
21 0
|
1月前
|
Linux Perl
编程入门(七)之【Linux进阶操作AWK】
编程入门(七)之【Linux进阶操作AWK】
35 0
|
1月前
|
Linux Shell Perl
编程入门(六)【Linux系统基础操作四】
编程入门(六)【Linux系统基础操作四】
25 0
|
1月前
|
Linux Shell
编程入门(六)【Linux系统基础操作三】
编程入门(六)【Linux系统基础操作三】
25 0
|
1月前
|
Linux Shell 数据库
编程入门(六)【Linux系统基础操作二】
编程入门(六)【Linux系统基础操作二】
33 0