Framebuffer编程总结,希望人人都能学会

34 篇文章 2 订阅
19 篇文章 1 订阅

🌹0.FrameBuffer的引入

FrameBuffer是出现在 2.2.xx 内核当中的一种驱动程序接口。在Linux系统中通过Framebuffer驱动程序来控制LCD。Frame是帧的意思,buffer是缓冲的意思,这意味着Framebuffer就是一块内存,里面保存着一帧图像。我们可以理解位每一个点就是一个像素,这个像素的单位可以是24位,16位,32位,假设这块lcd屏幕分辨率大小为55100,每一个像素用32位表示,那么一共有55100*32个字节。

☕1.LCD如何显示的原理

在内存中有一块专门的地址位framebuffer使用,我们只需要往这块地址写入数据就可以了,所以我们要先获取到这块内存的基础地址,比如说,一个像素有5个字节,那么我们只需要修改这五个字节的值就可以往LCD里面写入数据了,用韦东山老师画的图表示更清晰一些。
在这里插入图片描述

⌛2.如何修改LCD指定的像素呢

比如说,我们要修改第(x,y)个像素的值,有以下几个步骤

  • 获取framebuffer的基地址
  • 得到这个像素的绝对地址。

♐3.获取framebuffer基地址

使用mmap磁盘映射函数就可以获取基地址了,

fb_base = (unsigned char *)mmap(NULL , screen_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd_fb, 0);

🚀4.像素绝对地址的计算

在基地址的基础上先算出有多少行,在算出偏离x轴多少个,bpp是像素的意思,一个像素可以理解位一个点
公式总结:(x,y)像素起始地址=fb_base+(xres*bpp/8)y + xbpp/8

🌸5.像素的颜色的表示

像素是由RGB三原色(红、绿、蓝)来表示的,在不同的BPP格式中,用不同的位来分别表示R、G、B,
在这里插入图片描述

  • 对于32BPP,一般只设置其中的低24位,高8位表示透明度,一般的LCD都不支持
  • 对于24BPP,硬件上为了方便处理,在Framebuffer中也是用32位来表示,效果跟32BPP是一样的。
  • 对于16BPP,常用的是RGB565;很少的场合会用到RGB555,这可以通过ioctl读取驱动程序中的RGB位偏移来确定使用哪一种格式。

💯6,LCD参数的获取

LCD在每一块开发板上都含有一个LCD驱动程序,我们主要是通过人家提供的驱动程序进行代码编写,主要有两类。可变的参数fb_var_screeninfo、固定的参数fb_fix_screeninfo。编写应用程序时主要关心可变参数。
我们可以调用ioctl这个函数来获取lcd的参数,并把它放入你指定的结构体里,如下代码所示

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

👑7.设备的打开

在linux系统上,有一个特有的设备结点,他是负责写入framebuffer数据的,我们需要调用open函数打开该设备结点

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

🐟8.framebuffer完整代码演示

功能:在LCD屏幕中间画一条红线
里面加了很多注释,应该不难理解

#include <sys/mman.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <linux/fb.h>
#include <fcntl.h>
#include <stdio.h>
#include <string.h>
#include <sys/ioctl.h>
//LCD驱动程序给APP提供2类参数:可变的参数fb_var_screeninfo、固定的参数fb_fix_screeninfo。

static int fd_fb;
static struct fb_var_screeninfo var;	/* Current var */
static int screen_size;//屏幕大小
static unsigned char *fb_base;//显存的及地址
static unsigned int line_width;
static unsigned int pixel_width;//像素

void lcd_put_pixel(int x, int y, unsigned int color)
{
    //要选择哪一个点
    unsigned char *pen_8 = fb_base+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;

    //在不同的BPP格式中,用不同的位来分别表示R、G、B,由8位,16位,32位,在这里选择十六位
    switch (var.bits_per_pixel)
	{
		case 8:
		{
		//8bpp,color就不再表示RBG三原色了,这涉及调色板的概念,color是调色板的值。
			*pen_8 = color;
			break;
		}
		case 16:
		{
			/* RGB888转RGB565 把red、green、blue这三种8位颜色值,根据RGB565的格式,只保留red中的高5位、green中的高6位、blue中的高5位,组合成一个新的16位颜色值。*/
			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;
		}
	}
}

int main()
{
    int i;
	fd_fb = open("/dev/fb0", O_RDWR);
	if (fd_fb < 0)
	{
		printf("can't open /dev/fb0\n");
		return -1;
	}
    //获取可变的参数fb_var_screeninfo的值
       if (ioctl(fd_fb, FBIOGET_VSCREENINFO, &var))
	{
		printf("can't get var\n");
		return -1;
	}
    //计算行,每个点多少字节
    line_width  = var.xres * var.bits_per_pixel / 8;
	pixel_width = var.bits_per_pixel / 8;
    //lcd的大小计算公式为x轴*y轴 var.bits_per_pixeld代表像素,除8是因为像素是以位位单位
	screen_size = var.xres * var.yres * var.bits_per_pixel / 8;
    //通过mmap获取显存地址
    fb_base = (unsigned char *)mmap(NULL , screen_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd_fb, 0);
    	if (fb_base == (unsigned char *)-1)
	{
		printf("can't mmap\n");
		return -1;
	}
    /* 清屏: 全部设为白色 */
	memset(fb_base, 0xff, screen_size);

    
	/* 随便设置出100个为红色 */
	for (i = 0; i < 100; i++)
	lcd_put_pixel(var.xres/2+i, var.yres/2, 0xFF0000);//写入像素
    //释放磁盘映射
    munmap(fb_base , screen_size);
	close(fd_fb);
	
	return 0;	
}





  • 3
    点赞
  • 29
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 5
    评论
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

魔动山霸

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值