• 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
    • 2
    • 3
    • 4
    • 5
    • 6

    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;
    	}
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    2.获取触摸屏数据

    使用ioctl获取LCD的一些参数信息,并将这些参数的信息放入var结构体中。

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

    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 */
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39

    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;
    	}
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    三、LCD操作函数解析

    1.描点函数

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

    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;
    		}
    	}
    }
    
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42

    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); /* 黑 */
    			}
    		}
    	}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24

    总结

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

  • 相关阅读:
    房屋租赁统一管理服务平台的研究与开发(JavaSSM)
    微服务性能分析|Pyroscope 在 Rainbond 上的实践分享
    house of storm+堆SROP+orw
    python批量读取nc气象数据并转为tif
    Unet语义分割训练和TensorRT部署
    手机怎么修改编辑PDF中的文字?两分钟教你学会编辑方法
    深度学习入门(三十)卷积神经网络——NiN
    信息安全、网络安全以及数据安全三者之间的区别
    python趣味编程-5分钟实现一个打字速度测试(含源码、步骤讲解)
    本地备份和还原 SQL Server 数据库
  • 原文地址:https://blog.csdn.net/m0_49476241/article/details/128004946