嵌入式Linux—Framebuffer应用编程

Framebuffer 应用编程

Frame的意思是帧,buffer的意思是缓冲区。Framebuffer就是一块内存(硬件设备),里面保存着一帧图像。

ioctl()函数解析

ioctl()函数非常强大。不同的驱动程序内部会实现不同的 ioctl() ,可以使用各种 ioctl() 跟驱动程序交互:可以传数据给驱动程序,也可以从驱
动程序中读出数据。

头文件:

#include <sys/ioctl.h> 

函数原型:

int ioctl(int fd, unsigned long request, ...); 

函数说明:
① fd 表示文件描述符;
② request 表示与驱动程序交互的命令, 用不同的命令控制驱动程序输出我们需要的数据
③ … 表示可变参数 arg, 根据 request 命令,设备驱动程序返回输出的数据。
④ 返回值: 打开成功返回0,失败将返回-1

实现步骤

1.获取framebuffer描述符

fd_fb = open("/dev/fb0", O_RDWR);  //可读可写 	if(fd_fb == -1) { 		printf("can not open /dev/fb0n"); 		return -1; 	} 

2.获取屏幕可变参数

if(ioctl(fd_fb, FBIOGET_VSCREENINFO, &var)) { //结构体名不是地址,需要取地址。FBIOGET_VSCREENINFO是获取可变参数(fb.h) 		printf("can not get varn"); 		return -1; 	}  

3.计算framebuffer空间大小

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;  //单位:字节 	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 not mmapn"); 		return -1; 	} 

4.不同的RGB格式转换

switch(var.bits_per_pixel)  	{ 		case 8: 			{ 				/*代码*/ 				break; 			} 		case 16: 			{ 				/* 32位转换为RGB565 */ 				red = (color >> 16) & 0xff;   //保留17-24位 				green = (color >> 8) & 0xff;  //保留8-16位 				blue = (color >> 0) & 0xff;   //保留0-8位 				color = ((red >> 3) << 11) | ((green >> 2) << 5) | (blue >> 3);  //组合为16bit 				*add_16 = color;   //像素点对应的地址空间赋值 				break; 			} 		case 32: 			{ 				*add_32 = color; 				break; 			} 		default: 			printf("can't surport %dbppn", var.bits_per_pixel); 			break; 	} 

完整程序如下:

#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>  int fd_fb;    //文件描述符 int screen_size;  //屏幕总字节数(framebuffer的大小) struct fb_var_screeninfo var; unsigned char *fb_base; unsigned int line_width;   //行字节 unsigned int pixel_width;  //像素字节  void lcd_put_pixel(int x, int y, unsigned int color) { 	unsigned char *add_8 = fb_base + y*line_width + x*pixel_width; //像素点对应的内存地址 	unsigned short *add_16; 	unsigned int *add_32;  	unsigned int red, green, blue;  	add_16 = (unsigned short*)add_8;  //8位转换为16位 	add_32 = (unsigned int*) add_8;  	switch(var.bits_per_pixel)  	{ 		case 8: 			{ 				/*代码*/ 				break; 			} 		case 16: 			{ 				/* 32位转换为RGB565 */ 				red = (color >> 16) & 0xff;   //保留17-24位 				green = (color >> 8) & 0xff;  //保留8-16位 				blue = (color >> 0) & 0xff;   //保留0-8位 				color = ((red >> 3) << 11) | ((green >> 2) << 5) | (blue >> 3);  //组合为16bit 				*add_16 = color;   //像素点对应的地址空间赋值 				break; 			} 		case 32: 			{ 				*add_32 = color; 				break; 			} 		default: 			printf("can't surport %dbppn", var.bits_per_pixel); 			break; 	}  }  int main(int argc, char **argv) { 	int i;  	/* 1.获取framebuffer描述符 */ 	fd_fb = open("/dev/fb0", O_RDWR);  //可读可写 	if(fd_fb == -1) { 		printf("can not open /dev/fb0n"); 		return -1; 	}  	/* 2.获取屏幕可变参数 */ 	if(ioctl(fd_fb, FBIOGET_VSCREENINFO, &var)) { //结构体名不是地址,需要取地址 		printf("can not get varn"); 		return -1; 	}   	/* 3.计算framebuffer空间大小 **/ 	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;  //单位:字节 	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 not mmapn"); 		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, 0x0000FF); 	 	munmap(fb_base , screen_size); 	close(fd_fb);  	return 0; }  

发表评论

评论已关闭。

相关文章