framebuffer的入门介绍-实现程序分析【转】
本文转载自:http://blog.csdn.net/liuzijiang1123/article/details/46972723
如想想对lcd屏进行操作(例如在lcd屏幕上画线,或者显示视频数据),我们就必须得了framebuffer(帧缓冲),网上各种百度,大多都说的很官方,至少很难找到那些让人觉得很生动的描述,让我们这些出入门的菜鸟能好好了解一下。 下面就是我结合老师的指点和论坛上的解释再加上自己的理解写的一些东西。
很多人都会说操纵lcd显示就是操纵framebuffer,表面上来看是这样的。实际上是frambuffer就是Linux内核驱动申请的一片内存空间,然后lcd内有一片sram,cpu内部有个lcd控制器,它有个单独的dma用来将frambuffer中的数据拷贝到lcd的sram中去 拷贝到lcd的sram中的数据就会显示在lcd上,
LCD驱动和framebuffer驱动没有必然的联系,它只是驱动LCD正常工作的,比如有信号传过来,那么LCD驱动负责把信号转成显示屏上的内容,至于什么内容,怎么显示,它根本不关心也不知道。
- #include <stdlib.h>
- #include <unistd.h>
- #include <stdio.h>
- #include <fcntl.h>
- #include <linux/fb.h>
- #include <linux/kd.h>
- #include <sys/mman.h>
- #include <sys/ioctl.h>
- #include <sys/time.h>
- #include <string.h>
- #include <errno.h>
- struct fb_var_screeninfo vinfo;
- struct fb_fix_screeninfo finfo;
- char *frameBuffer = 0;
- //打印fb驱动中fix结构信息,注:在fb驱动加载后,fix结构不可被修改。
- void printFixedInfo ()
- {
- printf ("Fixed screen info:\n"
- "\tid: %s\n"
- "\tsmem_start:0x%lx\n"
- "\tsmem_len:%d\n"
- "\ttype:%d\n"
- "\ttype_aux:%d\n"
- "\tvisual:%d\n"
- "\txpanstep:%d\n"
- "\typanstep:%d\n"
- "\tywrapstep:%d\n"
- "\tline_length: %d\n"
- "\tmmio_start:0x%lx\n"
- "\tmmio_len:%d\n"
- "\taccel:%d\n"
- "\n",
- finfo.id, finfo.smem_start, finfo.smem_len, finfo.type,
- finfo.type_aux, finfo.visual, finfo.xpanstep, finfo.ypanstep,
- finfo.ywrapstep, finfo.line_length, finfo.mmio_start,
- finfo.mmio_len, finfo.accel);
- }
- //打印fb驱动中var结构信息,注:fb驱动加载后,var结构可根据实际需要被重置
- void printVariableInfo ()
- {
- printf ("Variable screen info:\n"
- "\txres:%d\n"
- "\tyres:%d\n"
- "\txres_virtual:%d\n"
- "\tyres_virtual:%d\n"
- "\tyoffset:%d\n"
- "\txoffset:%d\n"
- "\tbits_per_pixel:%d\n"
- "\tgrayscale:%d\n"
- "\tred: offset:%2d, length: %2d, msb_right: %2d\n"
- "\tgreen: offset:%2d, length: %2d, msb_right: %2d\n"
- "\tblue: offset:%2d, length: %2d, msb_right: %2d\n"
- "\ttransp: offset:%2d, length: %2d, msb_right: %2d\n"
- "\tnonstd:%d\n"
- "\tactivate:%d\n"
- "\theight:%d\n"
- "\twidth:%d\n"
- "\taccel_flags:0x%x\n"
- "\tpixclock:%d\n"
- "\tleft_margin:%d\n"
- "\tright_margin: %d\n"
- "\tupper_margin:%d\n"
- "\tlower_margin:%d\n"
- "\thsync_len:%d\n"
- "\tvsync_len:%d\n"
- "\tsync:%d\n"
- "\tvmode:%d\n"
- "\n",
- vinfo.xres, vinfo.yres, vinfo.xres_virtual, vinfo.yres_virtual,
- vinfo.xoffset, vinfo.yoffset, vinfo.bits_per_pixel,
- vinfo.grayscale, vinfo.red.offset, vinfo.red.length,
- vinfo.red.msb_right,vinfo.green.offset, vinfo.green.length,
- vinfo.green.msb_right, vinfo.blue.offset, vinfo.blue.length,
- vinfo.blue.msb_right, vinfo.transp.offset, vinfo.transp.length,
- vinfo.transp.msb_right, vinfo.nonstd, vinfo.activate,
- vinfo.height, vinfo.width, vinfo.accel_flags, vinfo.pixclock,
- vinfo.left_margin, vinfo.right_margin, vinfo.upper_margin,
- vinfo.lower_margin, vinfo.hsync_len, vinfo.vsync_len,
- vinfo.sync, vinfo.vmode);
- }
下面才是我们的重点,这个代码是我自己参考别人画矩形的代码改过来的
- //画一条直线
- void drawline_rgb16 (int x0,int y0, int width,int height, int color,int flag0)
- {
- const int bytesPerPixel = 2;//因为是rgb16,用16位来描述色深,所以2个字节
- const int stride = finfo.line_length / bytesPerPixel;,一行有多少个点
- const int red = (color & 0xff0000) >> (16 + 3);//下面是颜色的操作,我目前还没弄明白
- const int green = (color & 0xff00) >> (8 + 2);
- const int blue = (color & 0xff) >> 3;
- const short color16 = blue | (green << 5) | (red << (5 +6));
- int flag=flag0;//这里我为了图个方便就用一个flag来区分是画横线还是竖线,0表示横线,1表示竖线。
- short *dest = (short *) (frameBuffer)+ (y0 + vinfo.yoffset) * stride + (x0 +vinfo.xoffset);//这个就是我们画点的起始位置,其+stride就是换行(这个是我个人通过代码测试得出来的结论)
- int x=0,y=0;
- if(flag==0)
- {
- for (x = 0; x < width; ++x)//width就是我们x方向的终点
- {
- dest[x] = color16;
- }
- }
- else if(flag==1)
- {
- for(y=0;y<height;y++)//height就是我们y方向的终点
- {
- dest[x]=color16;//这里x始终为0,和下面一句结合起来就是每一行就画一个点,一共画height行,不就是一条竖线了么,这里我还思考了很久。
- dest +=stride;
- }
- }
- }
- short *dest = (short *) (frameBuffer)+ (y0 + vinfo.yoffset) * stride + (x0 +vinfo.xoffset);
上面这一行代码的具体意思就是定位到(x0,y0)这个坐标,也就是我们要画的其实位置
- //画大小为width*height的同色矩阵,5reds+6greens+5blues
- void drawRect_rgb16 (int x0, int y0, int width,int height, int color)
- {
- const int bytesPerPixel = 2;
- const int stride = finfo.line_length / bytesPerPixel;
- const int red = (color & 0xff0000) >> (16 + 3);
- const int green = (color & 0xff00) >> (8 + 2);
- const int blue = (color & 0xff) >> 3;
- const short color16 = blue | (green << 5) | (red << (5 +6));
- short *dest = (short *) (frameBuffer)+ (y0 + vinfo.yoffset) * stride + (x0 +vinfo.xoffset);
- int x, y;
- for (y = 0; y < height; ++y)
- {
- for (x = 0; x < width; ++x)
- {
- dest[x] = color16;
- }
- dest += stride;
- }
- }
- int main (int argc, char **argv)
- {
- const char *devfile = "/dev/fb0";
- long int screensize = 0;
- int fbFd = 0;
- /* Open the file for reading and writing */
- fbFd = open (devfile, O_RDWR);
- if (fbFd == -1)
- {
- perror ("Error: cannot open framebuffer device");
- exit (1);
- }
- //获取finfo信息并显示
- if (ioctl (fbFd, FBIOGET_FSCREENINFO, &finfo) == -1)
- {
- perror ("Error reading fixed information");
- exit (2);
- }
- printFixedInfo ();
- //获取vinfo信息并显示
- if (ioctl (fbFd, FBIOGET_VSCREENINFO, &vinfo) == -1)
- {
- perror ("Error reading variable information");
- exit (3);
- }
- printVariableInfo ();
- /* Figure out the size of the screen in bytes */
- screensize = finfo.smem_len;//fb的缓存长度
- /* Map the device to memory */
- frameBuffer =(char *) mmap (0, screensize, PROT_READ | PROT_WRITE, MAP_SHARED,fbFd, 0);
- if (frameBuffer == MAP_FAILED)
- {
- perror ("Error: Failed to map framebuffer device to memory");
- exit (4);
- }
- //drawRect_rgb16 (vinfo.xres *3 / 8, vinfo.yres * 3 / 8,vinfo.xres / 4, vinfo.yres / 4,0xff00ff00);//实现画矩形
- drawline_rgb16(50,80,260,0,0xffff0000,0);
- drawline_rgb16(160,10,0,180,0xff00ff00,1);//可以画出一个交叉的十字,坐标都是自己设的。
- sleep (2);
- printf (" Done.\n");
- munmap (frameBuffer, screensize); //解除内存映射,与mmap对应
- close (fbFd);
- return 0;
- }
用一个流程图还说明一下mian函数吧
prot参数指定共享内存的访问权限。可取如下几个值的或:PROT_READ(可读),PROT_WRITE(可写),PROT_EXEC(可执行),PROT_NONE(不可访问)。
flags由以下几个常值指定:MAP_SHARED, MAP_PRIVATE, MAP_FIXED。其中,MAP_SHARED,MAP_PRIVATE必选其一,而MAP_FIXED则不推荐使用。
如果指定为MAP_SHARED,则对映射的内存所做的修改同样影响到文件。如果是MAP_PRIVATE,则对映射的内存所做的修改仅对该进程可见,对文件没有影响。
offset参数一般设为0,表示从文件头开始映射。
前面我们不是说了frambuffer就是linux内核驱动申请的一片内存空间,lcd驱动将frambuffer的地址通过mmap()将这片内存映射到应用程序空间,这样我们写入到fb的数据就写入到内核驱动里的frambuffer中去了,而lcd 的dma就将这些数据写入到lcd的sram中,从而显示在lcd上.
framebuffer的入门介绍-实现程序分析【转】的更多相关文章
- C# BackgroundWorker组件学习入门介绍
C# BackgroundWorker组件学习入门介绍 一个程序中需要进行大量的运算,并且需要在运算过程中支持用户一定的交互,为了获得更好的用户体验,使用BackgroundWorker来完成这一功能 ...
- 为什么要学习微信小程序直播开发?最新的小程序直播介绍和优势分析!
小程序直播的介绍 “小程序直播”是微信提供给开发者的实时视频直播工具,包括直播管理端.主播端和观众端等模块,支持提供常用的用户互动和营销促销工具. 开发者只需在小程序中引入相关代码并在管理后台完成配置 ...
- 初识Hadoop入门介绍
初识hadoop入门介绍 Hadoop一直是我想学习的技术,正巧最近项目组要做电子商城,我就开始研究Hadoop,虽然最后鉴定Hadoop不适用我们的项目,但是我会继续研究下去,技多不压身. < ...
- [Python爬虫] 在Windows下安装PhantomJS和CasperJS及入门介绍(上)
最近在使用Python爬取网页内容时,总是遇到JS临时加载.动态获取网页信息的困难.例如爬取CSDN下载资源评论.搜狐图片中的“原图”等,此时尝试学习Phantomjs和CasperJS来解决这个问题 ...
- [Python爬虫] scrapy爬虫系列 <一>.安装及入门介绍
前面介绍了很多Selenium基于自动测试的Python爬虫程序,主要利用它的xpath语句,通过分析网页DOM树结构进行爬取内容,同时可以结合Phantomjs模拟浏览器进行鼠标或键盘操作.但是,更 ...
- .NET 4 并行(多核)编程系列之一入门介绍
.NET 4 并行(多核)编程系列之一入门介绍 本系列文章将会对.NET 4中的并行编程技术(也称之为多核编程技术)以及应用作全面的介绍. 本篇文章的议题如下: 1. 并行编程和多线程编程的区别. ...
- 介绍Python程序员常用的IDE和其它开发工具
概述 “工欲善其事,必先利其器”,如果说编程是程序员的手艺,那么IDE就是程序员的吃饭家伙了. IDE 的全称是Integration Development Environment(集成开发环境), ...
- 零基础入门微信小程序开发
注:本文来源于:<零基础入门微信小程序开发> 课程介绍 本达人课是一个系列入门教程,目标是从 0 开始带领读者上手实战,课程以微信小程序的核心概念作为主线,介绍配置文件.页面样式文件.Ja ...
- Python入门介绍
Python入门介绍(人生苦短,我用 Python) Python简介 python的创始人为吉多·范罗苏姆(Guido van Rossum).1989年的圣诞节期间,吉多·范罗苏姆为了在阿姆斯特丹 ...
随机推荐
- 通过yum命令搭建lamp环境(centos6.5)
centos 6.5 1.yum安装和源代码编译在使用的时候没啥区别,但是安装的过程就大相径庭了,yum只需要3个命令就可以完成,源代码需要13个包,还得加压编译,步骤很麻烦,而且当做有时候会出错,源 ...
- Android RecyclerView notifyDataSetChanged不起作用
一般listview设置完data后调用notifyDataSetChanged便可刷新布局界面,然而recycleview调用这个方法却没有任何反应.对于很多不熟悉recycleview的话很容易躺 ...
- Linux 信息查询
CPU信息查看 #查看CPU型号: $>grep 'model name' /proc/cpuinfo |uniq model name : Intel(R) Xeon(R) CPU ...
- 基于TensorFlow的车牌号识别系统
简介 过去几周我一直在涉足深度学习领域,尤其是卷积神经网络模型.最近,谷歌围绕街景多位数字识别技术发布了一篇不错的paper.该文章描述了一个用于提取街景门牌号的单个端到端神经网络系统.然后,作者阐述 ...
- 解决Sql Server 日志满了,设置收缩
解决Sql Server 日志满了,设置收缩: --查看文件占用空间 . '文件大小(MB)',* from sysfiles; ALTER DATABASE SpyData SET RECOVERY ...
- JS——indexOf replace search
indexOf() 方法可返回某个指定的字符串值在字符串中首次出现的位置 注释:indexOf() 方法对大小写敏感!如果要检索的字符串值没有出现,则该方法返回 -1. 语法:searchvalue, ...
- Linux基础之网络协议
互联网通信原理 从物理层面来说,每台计算机在一开始都是彼此孤立的,为了实现信息的交流与共享,计算机之间必须要建立通信网络.例如人与人之间的交流,他们必须要共用一套语言系统,才能交流成功.计算机之间也是 ...
- 注解是建立在class文件基础上的东西,同C语言的宏有异曲同工的效果
注解是建立在class文件基础上的东西,同C语言的宏有异曲同工的效果 https://www.cnblogs.com/deman/p/5519901.html @是java注解,即annotation ...
- 贴一段自动编译java,并混淆编译的代码
刚写的一个自动编译.混淆.打包jar的代码,做个记录 用到的NuGet: <?xml version="1.0" encoding="utf-8"?> ...
- 16.1 foreach 循环中捕获变量的变化
在 foreach 循环内的匿名函数(通常为Lambda表达式)中捕获循环 变量时要格外小心.代码清单16-1就展示了这样一个简单的示例,它看上去似乎会输出 x . y . z . string[] ...