显示输出设备学习(1)

2024-03-09 05:20
文章标签 学习 显示 输出设备

本文主要是介绍显示输出设备学习(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 的一般步骤如下:

    1. 首先打开/dev/fbX 设备文件。
    2. 使用 ioctl()函数获取到当前显示设备的参数信息,譬如屏幕的分辨率大小、像素格式,根据屏幕参数计算显示缓冲区的大小。
    3. 通过存储映射 I/O 方式将屏幕的显示缓冲区映射到用户空间(mmap)。
    4. 映射成功后就可以直接读写屏幕的显示缓冲区,进行绘图或图片显示等操作了。
    5. 完成显示后, 调用 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)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/789648

相关文章

HarmonyOS学习(七)——UI(五)常用布局总结

自适应布局 1.1、线性布局(LinearLayout) 通过线性容器Row和Column实现线性布局。Column容器内的子组件按照垂直方向排列,Row组件中的子组件按照水平方向排列。 属性说明space通过space参数设置主轴上子组件的间距,达到各子组件在排列上的等间距效果alignItems设置子组件在交叉轴上的对齐方式,且在各类尺寸屏幕上表现一致,其中交叉轴为垂直时,取值为Vert

Ilya-AI分享的他在OpenAI学习到的15个提示工程技巧

Ilya(不是本人,claude AI)在社交媒体上分享了他在OpenAI学习到的15个Prompt撰写技巧。 以下是详细的内容: 提示精确化:在编写提示时,力求表达清晰准确。清楚地阐述任务需求和概念定义至关重要。例:不用"分析文本",而用"判断这段话的情感倾向:积极、消极还是中性"。 快速迭代:善于快速连续调整提示。熟练的提示工程师能够灵活地进行多轮优化。例:从"总结文章"到"用

【前端学习】AntV G6-08 深入图形与图形分组、自定义节点、节点动画(下)

【课程链接】 AntV G6:深入图形与图形分组、自定义节点、节点动画(下)_哔哩哔哩_bilibili 本章十吾老师讲解了一个复杂的自定义节点中,应该怎样去计算和绘制图形,如何给一个图形制作不间断的动画,以及在鼠标事件之后产生动画。(有点难,需要好好理解) <!DOCTYPE html><html><head><meta charset="UTF-8"><title>06

学习hash总结

2014/1/29/   最近刚开始学hash,名字很陌生,但是hash的思想却很熟悉,以前早就做过此类的题,但是不知道这就是hash思想而已,说白了hash就是一个映射,往往灵活利用数组的下标来实现算法,hash的作用:1、判重;2、统计次数;

第10章 中断和动态时钟显示

第10章 中断和动态时钟显示 从本章开始,按照书籍的划分,第10章开始就进入保护模式(Protected Mode)部分了,感觉从这里开始难度突然就增加了。 书中介绍了为什么有中断(Interrupt)的设计,中断的几种方式:外部硬件中断、内部中断和软中断。通过中断做了一个会走的时钟和屏幕上输入字符的程序。 我自己理解中断的一些作用: 为了更好的利用处理器的性能。协同快速和慢速设备一起工作

安卓链接正常显示,ios#符被转义%23导致链接访问404

原因分析: url中含有特殊字符 中文未编码 都有可能导致URL转换失败,所以需要对url编码处理  如下: guard let allowUrl = webUrl.addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed) else {return} 后面发现当url中有#号时,会被误伤转义为%23,导致链接无法访问

C#实战|大乐透选号器[6]:实现实时显示已选择的红蓝球数量

哈喽,你好啊,我是雷工。 关于大乐透选号器在前面已经记录了5篇笔记,这是第6篇; 接下来实现实时显示当前选中红球数量,蓝球数量; 以下为练习笔记。 01 效果演示 当选择和取消选择红球或蓝球时,在对应的位置显示实时已选择的红球、蓝球的数量; 02 标签名称 分别设置Label标签名称为:lblRedCount、lblBlueCount

零基础学习Redis(10) -- zset类型命令使用

zset是有序集合,内部除了存储元素外,还会存储一个score,存储在zset中的元素会按照score的大小升序排列,不同元素的score可以重复,score相同的元素会按照元素的字典序排列。 1. zset常用命令 1.1 zadd  zadd key [NX | XX] [GT | LT]   [CH] [INCR] score member [score member ...]

【机器学习】高斯过程的基本概念和应用领域以及在python中的实例

引言 高斯过程(Gaussian Process,简称GP)是一种概率模型,用于描述一组随机变量的联合概率分布,其中任何一个有限维度的子集都具有高斯分布 文章目录 引言一、高斯过程1.1 基本定义1.1.1 随机过程1.1.2 高斯分布 1.2 高斯过程的特性1.2.1 联合高斯性1.2.2 均值函数1.2.3 协方差函数(或核函数) 1.3 核函数1.4 高斯过程回归(Gauss

【学习笔记】 陈强-机器学习-Python-Ch15 人工神经网络(1)sklearn

系列文章目录 监督学习:参数方法 【学习笔记】 陈强-机器学习-Python-Ch4 线性回归 【学习笔记】 陈强-机器学习-Python-Ch5 逻辑回归 【课后题练习】 陈强-机器学习-Python-Ch5 逻辑回归(SAheart.csv) 【学习笔记】 陈强-机器学习-Python-Ch6 多项逻辑回归 【学习笔记 及 课后题练习】 陈强-机器学习-Python-Ch7 判别分析 【学