1、什么是Framebuffer?
假设LCD屏幕分辨率是800x600,每个像素占4字节,那么framebuffer 大小就是:
800x600x4=960000字节
framebuffer 显示原理,如下图所示:
假设需要设置 LCD 中坐标(x,y)处像素的颜色,首要要找到这个像素对应的内存,然后根据它的 BPP 值设置颜色。
(相关资料图)
假设 fb_base 是 APP 执行 mmap 后得到的 Framebuffer 地址,如下图所示:
(x,y)像素起始地址=fb_base+(xres*bpp/8)y + xbpp/8
2、为什么要有Frambuffer?
思考一个问题,为什么要用Framebuffer?
上图为LCD 驱动框架图:
从软件层面分析:framebuffer 起着承上启下的作用,向上,为应用层提供通用系统调用(open(),ioctl(),mmap());向下,联接LCD控制器,之前对硬件进行操作。
从硬件层面分析:用户只需要将数据写到framebuffer,硬件会自动刷新到屏幕上。
3、常用接口和数据结构
3.1 常用接口
通过 man 2 查看如下:
函数说明:
函数原型:
intioctl(intfd,unsignedlongrequest,...);
函数说明:
3)mmap 系统调用:
函数说明:
3.2 相关数据结构
fb_var_screeninfo:包含xres, yres, bits_per_pixel等信息,在后续会经常用到。
4、如何在LCD 上描点?
4.1 LCD 显示原理
当我们需要显示一个字母‘A’时,是通过判断点阵的每一个位数值状态,来填充颜色,达到显示字符效果。其中‘1’表示一种颜色,‘0’表示填充另一种颜色。
如下图[1]8*16的点阵,只要有这个点阵,我们就可以在LCD上面描点,达到显示字符的效果。
4.2 Framebuffer 操作说明
framebuffer 操作如下流程:
intfd_fb;structfb_var_screeninfovar;/*Currentvar*/intscreen_size;unsignedchar*fbmem;unsignedintline_width;unsignedintpixel_width;intmain(intargc,char*argv[]){/*Step1:打开设备*/fd_fb=open("/dev/fb0",O_RDWR);if(fd_fb<0){printf("can"topen/dev/fb0\n");return-1;}/*Step2:获取设备参数信息* xres:x 方向总像素* yres:y 方向总像素* bits_per_pixel:每个像素占多少位*/if(ioctl(fd_fb,FBIOGET_VSCREENINFO,&var)){printf("can"tgetvar\n");return-1;}/*Step3:计算线宽,分配显存*//*line_width每行占的字节*/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=(unsignedchar*)mmap(NULL,screen_size,PROT_READ|PROT_WRITE,MAP_SHARED,fd_fb,0);if(fbmem==(unsignedchar*)-1){printf("can"tmmap\n");return-1;}/*Step4:清屏:全部设为黑色*/memset(fbmem,0,screen_size);/*Step5:描点*/lcd_put_ascii(var.xres/2,var.yres/2,"A");/*在屏幕中间显示8*16的字母A*//* Step6:释放资源*/munmap(fbmem,screen_size);/* Step7:关闭设备*/close(fd_fb);return0;}
4.3 描点实现
描点的关键是计算点(x,y)位置对应的地址,然后直接指向fbmem即可向frambuffer 写入数据。
/***********************************************************************函数名称:lcd_put_pixel*功能描述:在LCD指定位置上输出指定颜色(描点)*输入参数:x坐标,y坐标,颜色*输出参数:无*返回值:会***********************************************************************/voidlcd_put_pixel(intx,inty,unsignedintcolor){/**最主要的就是fbmem*计算(x,y)位置的偏移,然后指向fbmem,这块直接映射到framebuffer内存里*/unsignedchar*pen_8=fbmem+y*line_width+x*pixel_width;unsignedshort*pen_16;unsignedint*pen_32;unsignedintred,green,blue;pen_16=(unsignedshort*)pen_8;pen_32=(unsignedint*)pen_8;switch(var.bits_per_pixel){/*8bpp*/case8:{*pen_8=color;break;}/*16bpp*/case16:{/*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;}case32:{*pen_32=color;break;}default:{printf("can"tsurport%dbpp\n",var.bits_per_pixel);break;}}}
4.4 向 LCD 写入 英文
写入英文的前提:
/***********************************************************************函数名称:lcd_put_ascii*功能描述:在LCD指定位置上显示一个8*16的字符*输入参数:x坐标,y坐标,ascii码*输出参数:无*返回值:无***********************************************************************/voidlcd_put_ascii(intx,inty,unsignedcharc){/*fontdata_8x168x16英文点阵数据*/unsignedchar*dots=(unsignedchar*)&fontdata_8x16[c*16];inti,b;unsignedcharbyte;/*8x16的点阵,16行8列*/for(i=0;i<16;i++){byte=dots[i];for(b=7;b>=0;b--){if(byte&(1<
标签: