本篇文章将会介绍Linux下的Framebuffer编程,这里将会引用到百问网韦东山老师讲的一些知识。
在Linux系统中通过Framebuffer驱动程序来控制LCD。Frame是帧的意思,buffer是缓冲的意思,这意味着Framebuffer就是一块内存,里面保存着一帧图像。Framebuffer中保存着一帧图像的每一个像素颜色值,假设LCD的分辨率是1024x768,每一个像素的颜色用32位来表示,那么Framebuffer的大小就是:1024x768x32/8=3145728字节。
下面这些参数后面我们会一 一介绍。
int fd_fb;
struct fb_var_screeninfo var; /* Current var */
int screen_size;
unsigned char *fbmem;
unsigned int line_width;
unsigned int pixel_width;
这些的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;}
使用ioctl获取LCD的一些参数信息,并将这些参数的信息放入var结构体中。
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 */
};
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;}
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;}}
}
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</* show */lcd_put_pixel(x+7-b, y+i, color); /* 白 */}else{/* hide */lcd_put_pixel(x+7-b, y+i, 0); /* 黑 */}}}
}
本篇文章就介绍到这里,Framebuffer编程的编程其实并不算很难,大家只要理清楚这些参数即可。具体的代码请参考百问网,这里我只做重要部分介绍。