首先来说,FrameBuffer能做什么?
答:FrameBuffer可以在没有起动图形介面的系统上向屏幕上输出东西(自己的理解),最简单的例子就是,我们在字符介面上,也可以通过FrameBuffer在屏幕上显示美丽的图片、工整的文字。
一、原理
官方的意思我也不太懂,以下是我在开发过程中,自己对FrameBuffer的理解,有不到之处,请大家多多指教。
FrameBuffer 就像一张画布,使用什么样子的画笔,如何画画,还需要你自己动手完成。
在我看来FrameBuffer其实就是一个设备文件,他一般存在/dev/这个目录下,第一个frambBuffer设备的文件名是fb0,即所在位置为:/dev/fb0,但是有人就问了,我的dev目录下怎么没有这个文件呢,别着急,下面会提到环境搭建,等环境搭起来之后,就有了。
在编程人员眼里看来,FrameBuffer就是一块内存,而且是一块线性的内存,我们有个指针指向这块内存,想往哪个地放写数据就往哪个地方写数据。当我们打开FrameBuffer这个设备之后,得到的是一个整型的一维数组,每一个元素对应着屏幕上的一个象素点,如果我们的屏幕是1024*768的,那么我们应该得到一个长度为1024*768=786432的一维数组,在这个数组中,前1024个元素对应着屏幕上的第一行象素,接下来的1024个元素对应着屏幕上的第二行象素,以此类推....好了,如果上面的原理你理解了,那么不用说,你应该知道FrameBuffer怎么用了,我想让屏幕上的那个象素显示,就让哪个象素显示,这样,我们想显示汉字、图片也就没什么问题了,基本原理说白了,跟大街上的LED发光字,没有什么区别。
二、环境搭建
在这里只需要四步,通过网上查资料自己总结了,具体每一步是什么含义,在这里就不多说了,正常情况下,只要照着做,就不会出问题!(ubuntu环境下)
1、打开/etc/initramfs-tools/modules文件,在末尾加上:fbconvesafb
2、.打开/etc/modprobe.d/blacklist-framebuffer.conf,找到“blacklist vesafb”一行,在这一行前面加上“#”把它注释掉。
3、打开/boot/grub/menu.lst,找到相应的kernel一行,加上 vga参数。
例如我把分辨率设置为1024x768,对应的vga数值就是0x317。在我的机子上没有这个文件,是在/boot/grub /grub.cfg文件中修改的linux /boot/vmlinuz-2.6.22-14-generic root=UUID=3c51a0d7-d373-473b-830e-225b6d7aafdf ro quiet splash vga=0x317
4、最后执行:sudo update-initramfs -u更新,重启一下。如果你禁用了图形界面登陆,应该就能看到漂亮一些的字符界面了;如果没有禁用,可以在桌面环境中按Ctrl+Alt+F1 ~ F6看看效果,按Ctrl+Alt+F7返回桌面环境,这个时候,你的/dev目录下应该有了fb0这个设备,说明配置成功!
关于vga参数的设置,可以参照下表:
4bit 8bit 15bit 16bit 24bit 32bit
640x400 x 0x300 x x x x
640x480 x 0x301 0x310 0x311 0x312 x
800x600 0x302 0x303 0x313 0x314 0x315 x
1024x768 x 0x305 0x316 0x317 0x318 x
1280x1024 x 0x307 0x319 0x31A 0x31B x
1600x1200 x 0x31C 0x31D 0x31E 0x31F x
三、例子
以下是一个利用FrameBuffer显示汉字的程序,不是我写的,经过测试可以运行
hz.c文件:
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <string.h>
#include <linux/fb.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/mman.h>
#include "ziku.h"
#define FB_DEV "/dev/fb0"
int fb_open(char *fb_device);
int fb_close(int fd);
void *fb_mmap(int fd,unsigned int screensize);
int fb_munmap(void *start,size_t length);
int fb_16pixel(unsigned char *fbmem,int width,int height,int x,int y,unsigned short color);
void char_hz(char ch,unsigned char *fbmem,unsigned int width,unsigned int height,unsigned int x1,unsigned y1);
int main(int argc,char *argv[])
{
int fbdev;
char *fb_device;
unsigned char *fbmem;
unsigned int screensize;
unsigned int fb_width;
unsigned int fb_height;
unsigned int fb_depth;
unsigned int x;
unsigned int y;
unsigned int ii;
if((fb_device = getenv("FRAMEBUFFER")) == NULL)
{
fb_device = FB_DEV;
fbdev = fb_open(fb_device);
}else
printf("%s",fb_device);
fb_width = 1024;
fb_height = 768;
fb_depth = 16;
screensize = fb_width * fb_height *(fb_depth / 8);//
fbmem = fb_mmap(fbdev,screensize);//
memset (fbmem, 0, screensize);//
for(ii=0;ii<7;ii++)//
{
char_hz(ii,fbmem,fb_width,fb_height,30+ii*16,30);
}
fb_munmap(fbmem,screensize);
fb_close(fbdev);
return (0);
}
void char_hz(char ch,unsigned char *fbmem,unsigned int width,unsigned int height,unsigned int x1,unsigned int y1)
{
int i,j,k,n;
unsigned char list;
n = ch * 32;
for(i = 0;i < 16;i++,n++)
{
list = fontdata_16x16[n];
for(j=0;j<8;j++)
{
if(list&(1<<(7-j)))
{
fb_16pixel(fbmem,width,height,y1+j,x1+i, 0x1C3B);
}
}
n++;
list = fontdata_16x16[n];
for(j=0;j<8;j++)
{
if(list&(1<<(7-j)))
{
fb_16pixel(fbmem,width,height,y1+8+j,x1+i,0x1C3B);
}
}
}
}
int fb_open(char *fb_device)
{
int fd;
if((fd = open(fb_device,O_RDWR)) < 0)
{
perror(__func__);
return (-1);
}
return (fd);
}
void *fb_mmap(int fd,unsigned int screensize)
{
void* fbmem;
if((fbmem = mmap(0,screensize,PROT_READ|PROT_WRITE,MAP_SHARED,fd,0)) == MAP_FAILED)
{
perror(__func__);
return (void *)(-1);
}
return (fbmem);
}
int fb_munmap(void *start,size_t length)
{
return (munmap(start,length));
}
int fb_close(int fd)
{
return (close(fd));
}
//
int fb_16pixel(unsigned char *fbmem, int width,int height,int x,int y,unsigned short color)
{
if((x > width)||(y > height))
return (-1);
unsigned short *dst = ((unsigned short *)fbmem + y * width + x);
*dst = color;
return (0);
}
ziku.h文件:
#define FONTDATAMAX 224
const unsigned char fontdata_16x16[FONTDATAMAX] =
{/*我*/
0x04,0x80,0x0E,0xA0,0x78,0x90,0x08,
0x90,0x08,0x84,0xFF,0xFE,0x08,0x80,
0x08,0x90,0x0A,0x90,0x0C,0x60,0x18,
0x40,0x68,0xA0,0x09,0x20,0x0A,0x14,
0x28,0x14,0x10,0x0C,
/*是*/
0x0F,0xE0,0x08,0x20,0x08,0x20,0x0F,
0xE0,0x08,0x20,0x08,0x20,0x0F,0xE0,
0x00,0x04,0xFF,0xFE,0x01,0x00,0x09,
0x20,0x09,0xF0,0x09,0x00,0x15,0x00,
0x23,0x06,0x40,0xFC,
/*大*/
0x01,0x00,0x01,0x00,0x01,0x00,0x01,
0x00,0x01,0x04,0xFF,0xFE,0x01,0x00,
0x02,0x80,0x02,0x80,0x02,0x40,0x04,
0x40,0x04,0x20,0x08,0x10,0x10,0x0E,
0x60,0x04,0x00,0x00,
/*聪*/
0x05,0x04,0xFE,0xCC,0x24,0x50,0x24,
0x04,0x3D,0xFE,0x25,0x04,0x25,0x04,
0x25,0x04,0x3D,0xFC,0x25,0x44,0x24,
0x20,0x24,0xA4,0xFD,0x8A,0x06,0x8A,
0x04,0x78,0x04,0x00,
//中
0x01,0x00,0x01,0x00,0x01,0x04,0x7F,
0xFE,0x41,0x04,0x41,0x04,0x41,0x04,
0x41,0x04,0x7F,0xFC,0x41,0x04,0x01,
0x00,0x01,0x00,0x01,0x00,0x01,0x00,
0x01,0x00,0x01,0x00,
//国
0x00,0x04,0x7F,0xFE,0x40,0x24,0x5F,
0xF4,0x41,0x04,0x41,0x04,0x41,0x44,
0x4F,0xE4,0x41,0x04,0x41,0x44,0x41,
0x24,0x41,0x04,0x5F,0xF4,0x40,0x04,
0x7F,0xFC,0x40,0x04,
//人
0x01,0x00,0x01,0x00,0x01,0x00,0x01,
0x00,0x01,0x00,0x01,0x00,0x01,0x00,
0x02,0x80,0x02,0x80,0x02,0x80,0x04,
0x40,0x04,0x40,0x08,0x20,0x10,0x10,
0x20,0x0E,0x40,0x04
};
运行上面程序,会在屏幕上显示 “我是大聪中国人” 字样
好啦,到此FrameBuffer已经总结完毕,敲了这么大半天,希望对正在研究FrameBuffer的新手带来帮助,呵呵~~~,还有什么不懂的可以留言,大家共同讨论,共同进步~~