本文主要是介绍显示输出设备学习(1),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
FrameBuffer
- 含义:帧缓冲,即一块内存,其中保存内容为一帧的图像。
- FrameBuffer把显示设备(lcd屏)抽象为一块内存,用户只需向内存中输入数据即可,无需关心数据如何输入到硬件设备中。
- FrameBuffer对应Linux中的设备文件为/dev/fbX(X为0,1,2…,31)
lcd屏基本概念
-
像素
- 像素是屏幕显示颜色的最小单位,每个像素由R,G,B来控制颜色,一个图片由若干个像素点构成。
- 像素点由红绿蓝(R\G\B)构成,同过三者不同比列显示颜色
-
分辨率
- 分辨率=画面水平方向的像素值 * 画面垂直方向的像素值,指的是像素点的数目,我们平常说的1080p就是水平1920个像素点,竖直1080个像素点,分辨率越高需要的显存越大。
-
色深
- 用于表示每个像素点颜色的比特位数,位数越多颜色过渡就越平滑。一般的色深RGB888(3字节),RGB565(两字节),RGB888(带透明度,4字节)
LCD屏应用编程
-
理解:就是对显示设备文件进行写操作
-
在应用程序中,操作/dev/fbX 的一般步骤如下:
- 首先打开/dev/fbX 设备文件。
- 使用 ioctl()函数获取到当前显示设备的参数信息,譬如屏幕的分辨率大小、像素格式,根据屏幕参数计算显示缓冲区的大小。
- 通过存储映射 I/O 方式将屏幕的显示缓冲区映射到用户空间(mmap)。
- 映射成功后就可以直接读写屏幕的显示缓冲区,进行绘图或图片显示等操作了。
- 完成显示后, 调用 munmap()取消映射、并调用 close()关闭设备文件。
ioctl()函数获取硬件屏幕参数
ioctl()函数获取屏幕硬件信息,常用的包:FBIOGET_VSCREENINFO、 FBIOPUT_VSCREENINFO、FBIOGET_FSCREENINFO
- FBIOGET_VSCREENINFO(获取FrameBuffer设备可变参数信息),使用它时ioctl第三个参数需要一个struct fb_var_screeninfo 类型的指针,将可变参数信息保存在fb_var_screeninfo类型的变量中
- FBIOPUT_VSCREENINFO(设置FrameBuffer设备可变参数信息),使用它时ioctl第三个参数需要一个struct fb_var_screeninfo 类型的指针,将指向内容写入到硬件可变参数中。
- FBIOGET_FSCREENINFO(获取FrameBuffer设备固定参数信息),使用它时ioctl第三个参数需要一个struct fb_fix_screeninfo 类型的指针,将固定参数信息保存在fb_fix_screeninfo类型的变量中。
上述三个宏定义,以及两个结构体都在<linux/fb.h>头文件中。
-
struct fb_var_screeninfo 结构体
struct fb_var_screeninfo {__u32 xres; /* 可视区域,一行有多少个像素点, X 分辨率 */__u32 yres; /* 可视区域,一列有多少个像素点, Y 分辨率 */__u32 xres_virtual; /* 虚拟区域,一行有多少个像素点 */__u32 yres_virtual; /* 虚拟区域,一列有多少个像素点 */__u32 xoffset; /* 虚拟到可见屏幕之间的行偏移 */__u32 yoffset; /* 虚拟到可见屏幕之间的列偏移 */__u32 bits_per_pixel; /* 每个像素点使用多少个 bit 来描述,也就是像素深度 bpp */__u32 grayscale; /* =0 表示彩色, =1 表示灰度, >1 表示 FOURCC 颜色 *//* 用于描述 R、 G、 B 三种颜色分量分别用多少位来表示以及它们各自的偏移量 */struct fb_bitfield red; /* Red 颜色分量色域偏移 */struct fb_bitfield green; /* Green 颜色分量色域偏移 */struct fb_bitfield blue; /* Blue 颜色分量色域偏移 */struct fb_bitfield transp; /* 透明度分量色域偏移 */__u32 nonstd; /* nonstd 等于 0,表示标准像素格式;不等于 0 则表示非标准像素格式 */__u32 activate;__u32 height; /* 用来描述 LCD 屏显示图像的高度(以毫米为单位) */__u32 width; /* 用来描述 LCD 屏显示图像的宽度(以毫米为单位) */__u32 accel_flags;/* 以下这些变量表示时序参数 */__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 */ };
-
struct fb_fix_screeninfo 结构体
struct fb_fix_screeninfo {char id[16]; /* 字符串形式的标识符 */unsigned long smem_start; /* 显存的起始地址(物理地址) */__u32 smem_len; /* 显存的长度 */__u32 type;__u32 type_aux;__u32 visual;__u16 xpanstep;__u16 ypanstep;__u16 ywrapstep;__u32 line_length; /* 一行的字节数 */unsigned long mmio_start; /* Start of Memory Mapped I/O(physical address) */__u32 mmio_len; /* Length of Memory Mapped I/O */__u32 accel; /* Indicate to driver which specific chip/card we have */__u16 capabilities;__u16 reserved[2]; };
获取lcd屏幕设备信息:
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/mman.h>
#include <stdlib.h>
#include <sys/ioctl.h>
#include <linux/fb.h>
int main(int argc,char *argv[]){struct fb_var_screeninfo fvs;struct fb_fix_screeninfo ffs;// 1.打开lcd屏幕对应的文件int lcd = open("/dev/fb0",O_RDONLY);if(lcd == -1){perror("open error");}// 2.获取可变参数信息,存储在fb_var_screeninfo类型结构体中ioctl(lcd,FBIOGET_VSCREENINFO,&fvs);// 3.获取固定参数的信息,存储在fb_fix_screeninfo类型结构体中ioctl(lcd,FBIOGET_FSCREENINFO,&ffs);// 4.显示lcd信息printf("分辨率: %d*%d\n""像素深度 bpp: %d\n""一行的字节数: %d\n""像素格式: R<%d %d> G<%d %d> B<%d %d>\n",fvs.xres, fvs.yres, fvs.bits_per_pixel,ffs.line_length,fvs.red.offset, fvs.red.length,fvs.green.offset, fvs.green.length,fvs.blue.offset, fvs.blue.length);// 5.关闭打开文件close(lcd);
}/*输出结果:分辨率: 1024*600像素深度 bpp: 16一行的字节数: 2048像素格式: R<11 5> G<5 6> B<0 5> */
存储映射:
- 理解:将文件映射到内存中,用户只需对内存进行操作,无需关心内存数据如何进入到文件中,映射可以大大加快程序的运行。
-
mmap()函数
-
函数原型:
#include <sys/mmap.h> void *mmap(void *addr,size_t length,int port,int flags,int fd,off_t offset);
-
函数功能:对文件进行存储映射。
-
参数解析:
-
**addr:**文件映射到内存的首地址,通常为NULL由系统自动分配。
-
length:映射长度,即在内存中的大小
-
offset:文件的偏移量,通常为0。
-
fd:文件描述符,指定被映射的文件
-
prot:对映射取的保护机制,可取值如下:
-
- PROT_EXEC: 映射区可执行;
- PROT_READ: 映射区可读;
- PROT_WRITE: 映射区可写;
- PROT_NONE: 映射区不可访问。
-
-
flags: 可影响映射区的多种属性, 参数 flags 必须要指定以下两种标志之一:
- MAP_SHARED:此标志指定当对映射区写入数据时,数据会写入到文件中,也就是会将写入到映射区中的数据更新到文件中,并且允许其它进程共享。
- MAP_PRIVATE:此标志指定当对映射区写入数据时,会创建映射文件的一个私人副本(copy-onwrite),对映射区的任何操作都不会更新到文件中,仅仅只是对文件副本进行读写。
-
-
返回值:成功情况下,函数的返回值便是映射区的起始地址(即第一个参数的地址);发生错误时,返回(void *)-1, 通常使用MAP_FAILED 来表示, 并且会设置 errno 来指示错误原因。
-
-
munmap()函数
-
函数原型:
#include <sys/mman.h> int munmap(void *addr, size_t length);
-
每次存储映射使用完成后,需要用munmap解除映射。
-
在lcd上进行画点
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/mman.h>
#include <stdlib.h>
#include <sys/ioctl.h>
#include <linux/fb.h>
int main(int argc,char *argv[]){// 1.打开lcd对应文件int lcd = open("/dev/fb0",O_RDWR);// 2.进行内存映射,将文件信息映射到内存中方便操作addr = (unsigned short *)mmap(NULL,1024*600*2,PROT_READ|PROT_WRITE,MAP_SHARED,lcd,0);// 3.向内存映射中写入数据rbi(0,1024,0,600,0X0);rbi(0,100,0,150,0XFFFF);rbi(0,100,450,600,0XF800);// 4.关闭文件close(lcd);
}// 打点函数
void rbi(int starX,int endX,int starY,int endY,unsigned short color){unsigned long temp = starY*1024+starX;for(int y = 0;y<endY - starY;y++,temp+=1024){for(int x = 0;x<endX-starX;x++){addr[temp+x] = color;}}
}
结果显示:
BMP照片显示:
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/mman.h>
#include <stdlib.h>
#include <sys/ioctl.h>
#include <linux/fb.h>
unsigned short *addr = NULL;
int main(int argc,char *argv[]){
/*将图片绘制到lcd屏上面*/// 1.判断输入合法性if(argc < 2){printf("./pic <filename>\n");return 0;}// 2.打开bmp照片文件 int pic = open(argv[1],O_RDONLY); if(pic == -1){perror("open pic error");}// 3.设置图片信息偏移量lseek(pic,54,SEEK_SET);// 4.读取图片信息unsigned char pic_arr[1024*600*3] = {0};int n_read = read(pic,pic_arr,1024*600*3);if(n_read < 1024*600*3){perror("read error");return 0;}// 5.将rgb888类型数据转化为rgb565类型数据unsigned short pic_arr1[1024*600];unsigned short blue,green,red;for(int i = 0;i<1024*600;i++){blue = pic_arr[i*3+0] >> 3;green = pic_arr[i*3+1] >> 2;red = pic_arr[i*3+2] >> 3;pic_arr1[i] = blue << 11 | green << 5 | red; }// 6.打开lcd文件int lcd = open("/dev/fb0",O_RDWR);if(lcd == -1){perror("open lcd error");return 0;}// 7.将lcd文件映射到内存中unsigned short *m_addr = (unsigned short *)mmap(NULL,1024*600*2,PROT_WRITE|PROT_READ,MAP_SHARED,lcd,0);for(int y = 0;y<600;y++){for(int x=0;x<1024;x++){*(m_addr + y*1024 + x) = pic_arr1[(599 - y)*1024+x];}}// 8.关闭链接munmap(m_addr,1024*600*2);close(lcd);close(pic);return 0;
}
结果显示:
这篇关于显示输出设备学习(1)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!