Linux应用开发基础知识——Framebuffer 应用编程(四)
前言:
在 Linux 系统中通过 Framebuffer 驱动程序来控制 LCD。Frame 是帧的意 思,buffer 是缓冲的意思,这意味着 Framebuffer 就是一块内存,里面保存着 一帧图像。Framebuffer 中保存着一帧图像的每一个像素颜色值,假设 LCD 的 分辨率是 1024x768,每一个像素的颜色用 32 位来表示,那么 Framebuffer 的 大小就是:1024x768x32/8=3145728 字节。
目录
一、LCD 操作原理
二、涉及的 API 函数
1.open 函数
2.ioctl 函数
3.mmap 函数
三、Framebuffer 程序分析
1.Framebuffer源码如下:
2. 打开设备:
3.获取 LCD 参数
4.映射 Framebuffer
5.描点函数
6.随便画几个点
四、上机实验测试
一、LCD 操作原理
1.驱动程序设置好 LCD 控制器:
根据 LCD 的参数设置 LCD 控制器的时序、信号极性;
根据 LCD 分辨率、BPP 分配 Framebuffer。
2.APP 使用 ioctl 获得 LCD 分辨率、BPP
3.APP 通过 mmap 映射 Framebuffer,在 Framebuffer 中写入数据
假设需要设置 LCD 中坐标(x,y)处像素的颜色,首要要找到这个像素对应的 内存,然后根据它的 BPP 值设置颜色。假设 fb_base 是 APP 执行 mmap 后得到 的 Framebuffer 地址,如图
可以用以下公式算出(x,y)坐标处像素对应的 Framebuffer 地址:
(x,y)像素起始地址=fb_base+(xres*bpp/8)*y + x*bpp/8
最后一个要解决的问题就是像素的颜色怎么表示?它是用 RGB 三原色(红、绿、 蓝)来表示的,在不同的 BPP 格式中,用不同的位来分别表示 R、G、B
对于 32BPP,一般只设置其中的低 24 位,高 8 位表示透明度,一般的 LCD 都不支持。
对于 24BPP,硬件上为了方便处理,在 Framebuffer 中也是用 32 位来表 示,效果跟 32BPP 是一样的。
对于 16BPP,常用的是 RGB565;很少的场合会用到 RGB555,这可以通过 ioctl 读取驱动程序中的 RGB 位偏移来确定使用哪一种格式。
二、涉及的 API 函数
目的是:打开 LCD 设备节点,获取分辨率等参数,映射 Framebuffer,最后实现描点函数。
1.open 函数
在 Ubuntu 中执行“man 2 open”,可以看到 open 函数的说明:
头文件:
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
函数原型:
int open(const char *pathname, int flags);
int open(const char *pathname, int flags, mode_t mode);
函数说明:
1.pathname 表示打开文件的路径;
2.Flags 表示打开文件的方式,常用的有以下 6 种,
◼ O_RDWR 表示可读可写方式打开;
◼ O_RDONLY 表示只读方式打开;
◼ O_WRONLY 表示只写方式打开;
◼ O_APPEND 表示如果这个文件中本来是有内容的,则新写入的内容会接续到原来内容的后面;
◼ O_TRUNC 表示如果这个文件中本来是有内容的,则原来的内容会被丢弃,截断; ◼ O_CREAT 表示当前打开文件不存在,我们创建它并打开它,通常与 O_EXCL 结合使用,当没有文件时创建文件,有这个文件时会报错提醒我们;
3.Mode 表示创建文件的权限,只有在 flags 中使用了 O_CREAT 时才有效, 否则忽略。
4.返回值:打开成功返回文件描述符,失败将返回-1。
2.ioctl 函数
在 Ubuntu 中执行“man ioctl”,可以看到 ioctl 函数的说明:
头文件:
#include <sys/ioctl.h>
函数原型:
int ioctl(int fd, unsigned long request, ...);
1. fd 表示文件描述符;
2. request 表示与驱动程序交互的命令,用不同的命令控制驱动程序输出我们 需要的数据; 3. … 表示可变参数 arg,根据 request 命令,设备驱动程序返回输出的数据。
4.返回值:打开成功返回文件描述符,失败将返回-1。
ioctl 的作用非常强大、灵活。不同的驱动程序内部会实现不同的 ioctl, APP 可以使用各种 ioctl 跟驱动程序交互:可以传数据给驱动程序,也可以从驱动程序中读出数据。
3.mmap 函数
在 Ubuntu 中执行“man mmap”,可以看到 mmap 函数的说明:
头文件:
#include <sys/mman.h>
函数原型:
void *mmap(void *addr, size_t length, int prot, int flags,int fd, off_t offset);
1.addr 表示指定映射的內存起始地址,通常设为 NULL 表示让系统自动选定 地址,并在成功映射后返回该地址;
2.length 表示将文件中多大的内容映射到内存中;
3.prot 表示映射区域的保护方式,可以为以下 4 种方式的组合
◼ PROT_EXEC 映射区域可被执行
◼ PROT_READ 映射区域可被读出
◼ PROT_WRITE 映射区域可被写入
◼ PROT_NONE 映射区域不能存取 Flags 表示影响映射区域的不同特性,常用的有以下两种
◼ MAP_SHARED 表示对映射区域写入的数据会复制回文件内,原来的文件会改变。 ◼ MAP_PRIVATE 表示对映射区域的操作会产生一个映射文件的复制,对此区域的任何修改都不会写回原来的文件内容中。
5.返回值:若成功映射,将返回指向映射的区域的指针,失败将返回-1。
三、Framebuffer 程序分析
1.Framebuffer源码如下:
/*********************************************************************** 函数名称: lcd_put_pixel* 功能描述: 在LCD指定位置上输出指定颜色(描点)* 输入参数: x坐标,y坐标,颜色* 输出参数: 无* 返 回 值: 会***********************************************************************/
void lcd_put_pixel(int x, int y, unsigned int color)
{unsigned char *pen_8 = fb_base+y*line_width+x*pixel_width;unsigned short *pen_16;unsigned int *pen_32;unsigned int red, green, blue;pen_16 = (unsigned short *)pen_8;pen_32 = (unsigned int *)pen_8;switch (var.bits_per_pixel){case 8:{*pen_8 = color;break;}case 16:{/* 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;}case 32:{*pen_32 = color;break;}default:{printf("can't surport %dbpp\n", var.bits_per_pixel);break;}}
}int main(int argc, char **argv)
{int i;fd_fb = open("/dev/fb0", O_RDWR);if (fd_fb < 0){printf("can't open /dev/fb0\n");return -1;}if (ioctl(fd_fb, FBIOGET_VSCREENINFO, &var)){printf("can't get var\n");return -1;}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;fb_base = (unsigned char *)mmap(NULL , screen_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd_fb, 0);if (fb_base == (unsigned char *)-1){printf("can't mmap\n");return -1;}/* 清屏: 全部设为白色 */memset(fb_base, 0xff, screen_size);/* 随便设置出100个为红色 */for (i = 0; i < 100; i++)lcd_put_pixel(var.xres/2+i, var.yres/2, 0xFF0000);munmap(fb_base , screen_size);close(fd_fb);return 0;
}
2. 打开设备:
首先打开设备节点:
fd_fb = open("/dev/fb0", O_RDWR);if (fd_fb < 0){printf("can't open /dev/fb0\n");return -1;}
3.获取 LCD 参数
LCD 驱动程序给 APP 提供 2 类参数:
可变的参数 fb_var_screeninfo
固 定的参数 fb_fix_screeninfo
编写应用程序时主要关心可变参数,它的结构 体定义如下(#include <Linux/fd.h>):
可以使用以下代码获取 fb_var_screeninfo:
static struct fb_var_screeninfo var; /* Current var */......if (ioctl(fd_fb, FBIOGET_VSCREENINFO, &var))
{printf("can't get var\n");return -1;
}
注意到 ioctl 里用的参数是:FBIOGET_VSCREENINFO,它表示 get var screen info,获得屏幕的可变信息;当然也可以使用 FBIOPUT_VSCREENINFO 来调整这 些参数,但是很少用到。
对于固定的参数 fb_fix_screeninfo,在应用编程中很少用到。它的结构 体定义如下:
可以使用 ioctl FBIOGET_FSCREENINFO 来读出这些信息,但是很少用到。
4.映射 Framebuffer
要映射一块内存,需要知道它的地址──这由驱动程序来设置,需要知道它 的大小──这由应用程序决定。代码如下:
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;
fb_base = (unsigned char *)mmap(NULL , screen_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd_fb, 0);
if (fb_base == (unsigned char *)-1)
{printf("can't mmap\n");return -1;
}
screen_size 是整个 Framebuffer 的大小;PROT_READ | PROT_WRITE 表示该区域可读、可写;MAP_SHARED 表示该区域是共享的,APP 写 入数据时,会直达驱动程序。
5.描点函数
能够在 LCD 上描绘指定像素后,就可以写字、画图,描点函数是基础。代码如下:
void lcd_put_pixel(int x, int y, unsigned int color)
{unsigned char *pen_8 = fb_base+y*line_width+x*pixel_width;unsigned short *pen_16;unsigned int *pen_32;unsigned int red, green, blue;pen_16 = (unsigned short *)pen_8;pen_32 = (unsigned int *)pen_8;switch (var.bits_per_pixel){case 8:{*pen_8 = color;break;}case 16:{/* 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;}case 32:{*pen_32 = color;break;}default:{printf("can't surport %dbpp\n", var.bits_per_pixel);break;}}
}
1.void lcd_put_pixel(int x, int y, unsigned int color)
传入的 color 表示颜色,它的格式永远是 0x00RRGGBB,即 RGB888。 当 LCD 是16bpp 时,要把 color 变量中的 R、G、B 抽出来再合并成 RGB565 格式。
2.unsigned char *pen_8 = fb_base+y*line_width+x*pixel_width;
计算(x,y)坐标上像素对应的 Framebuffer 地址。
3.*pen_8 = color;
对于 8bpp,color 就不再表示 RBG 三原色了,这涉及调色板的概念,color 是调色板的值。 第 49~51 行,先从 color 变量中把 R、G、B 抽出来。
4. red = (color >> 16) & 0xff;
green = (color >> 8) & 0xff;
blue = (color >> 0) & 0xff;
把 red、green、blue 这三种 8 位颜色值,根据 RGB565 的格式, 只保留 red 中的高 5 位、green 中的高 6 位、blue 中的高 5 位,组合成一个新 的 16 位颜色值。
5.color = ((red >> 3) > 2) > 3);
把新的 16 位颜色值写入 Framebuffer。
6.*pen_32 = color;
对于 32bpp,颜色格式跟 color 参数一致,可以直接写入 Framebuffer。
6.随便画几个点
本程序的 main 函数,在最后只是简单地画了几个点:
/* 清屏: 全部设为白色 */memset(fb_base, 0xff, screen_size);/* 随便设置出100个为红色 */for (i = 0; i < 100; i++)lcd_put_pixel(var.xres/2+i, var.yres/2, 0xFF0000);
四、上机实验测试
在 Ubuntu 中编译程序,先设置交叉编译工具链,再执行以下命令:
book@100ask:~/source/07_framebuffer$ arm-buildroot-linux-gnueabihf-gcc -o show_pixel show_pixel.c
book@100ask:~/source/07_framebuffer$ cp show_pixel ~/nfs_rootfs/
在开发板上挂载网络文件系统
运行程序
[root@100ask:~]# mount -t nfs -o nolock,vers=3 192.168.5.11:/home/book/nfs_rootfs /mnt
[root@100ask:~]# /mnt/show_pixel
运行效果:
相关文章:

Linux应用开发基础知识——Framebuffer 应用编程(四)
前言: 在 Linux 系统中通过 Framebuffer 驱动程序来控制 LCD。Frame 是帧的意 思,buffer 是缓冲的意思,这意味着 Framebuffer 就是一块内存,里面保存着 一帧图像。Framebuffer 中保存着一帧图像的每一个像素颜色值,假设…...

智安网络|数据库入门秘籍:通俗易懂,轻松掌握与实践
在现代信息化时代,数据库已成为我们日常生活和工作中不可或缺的一部分。然而,对于非专业人士来说,数据库这个概念可能很抽象,难以理解。 一、什么是数据库? 简单来说,数据库是一个存储和管理数据的系统。它…...
EXCEL中安装多个vsto插件,插件之间互相影响功能,怎么解决
在 Excel 中安装多个 VSTO 插件,并且这些插件之间存在互相影响的情况下,可以采取以下措施来解决问题: 1. **隔离插件功能:** - 确保每个 VSTO 插件都有清晰的功能和责任范围,避免不同插件之间的功能重叠。这可以通…...
Java枚举
枚举类 概念 Java中的枚举(Enumeration)是一种特殊的数据类型,它是一种包含固定常量的类型。枚举是一种更加类型安全和更易维护的方式来定义常量,它包含了一组命名的值。 enum Weekday {MONDAY, TUESDAY, WEDNESDAY, THURSDAY,…...

基于MATLAB的关节型六轴机械臂轨迹规划仿真
笛卡尔空间下的轨迹规划,分为直线轨迹规划和圆弧轨迹规划,本文为笛卡尔空间下圆弧插值法的matlab仿真分析 目录 1 实验目的 2 实验内容 2.1标准D-H参数法 2.2实验中使用的Matlab函数 3 全部代码 4 仿真结果 1 实验目的 基于机器人学理论知识&…...

双11狂欢最后一天
大家好,本年度双11即将到来,为了答谢大家多年来的支持及更广泛的推广VBA的应用,“VBA语言専功”在此期间推出巨大优惠:此期间打包购买VBA技术资料实行半价优惠。 1:面向对象:学员及非学员 2:打…...

YOLOX: Exceeding YOLO Series in 2021(2021.8)
文章目录 AbstractIntroduction介绍前人的工作提出问题解决 YOLOXYOLOX-DarkNet53Implementation detailsYOLOv3 baselineDecoupled headStrong data augmentationAnchor-freeMulti positivesSimOTAEnd-to-end YOLOOther BackbonesModified CSPNet in YOLOv5Tiny and Nano dete…...

HBuilderX 运行Android App项目至雷电模拟器
一、下载安装HBuilderX HBuildeX官网 安装最新的正式版,或者点击历史版本查看更多版本;【ps:Alpha版本为开发版,功能更多,但是也不稳定,属于测试版本】 直接将压缩包解压,运行HBuildeX即可。 二…...

Java进阶(JVM调优)——阿里云的Arthas的使用 安装和使用 死锁查找案例,重新加载案例,慢调用分析
前言 JVM作为Java进阶的知识,是需要Java程序员不断深度和理解的。 本篇博客介绍JVM调优的工具阿里云的Arthas的使用,安装和使用,命令的使用案例;死锁查询的案例;重新加载一个类信息的案例;调用慢的分析案…...

续:将基于Nasm汇编的打字小游戏,移植到DOSBox
续:将基于Nasm汇编的打字小游戏,移植到DOSBox 文章目录 续:将基于Nasm汇编的打字小游戏,移植到DOSBox前情提要细说1 编译2 程序入口3 定位段 运行体验 前情提要 上一篇:【编程实践】黑框框里的打字小游戏,但…...

外部访问K8S集群内部的kafka集群服务
不许转载 kafka 部署 把 kafka 部署到 k8s 后,我们肯定是通过 service 从 k8s 外部访问 kafaka。这里的 service 要么是 NodePort, 要么是 LoadBalancer 类型。我们使用的方式是 LoadBalancer。 我们先看下面这张图,这是 kafka 在集群中的网…...
AttributeError: module ‘tensorflow‘ has no attribute ‘contrib‘解决办法
在TensorFlow2环境下执行1.X版本的代码时报错: AttributeError: module ‘tensorflow‘ has no attribute ‘contrib‘ 当然第一时间想到的是利用 如下代码 来解决问题(大部分情况都是这样), tf.compat.v1但是又出现以下报错 Att…...
物奇平台耳机恢复出厂设置功能实现
是否需要申请加入数字音频系统研究开发交流答疑群(课题组)?可加我微信hezkz17, 本群提供音频技术答疑服务,+群赠送语音信号处理降噪算法,蓝牙音频,DSP音频项目核心开发资料, 物奇平台耳机恢复出厂设置功能实现 一 需求 1 耳机接收到充电盒长按12S指令后触发, 2 接收到…...

RFID携手制造业升级,为锂电池生产带来前所未有的可靠性
应用背景 随着科技的发展和全球化的推进,产品的生产过程越来越复杂,且对品质的要求也越来越高。在锂电池生产领域,由于其高能量密度、长寿命和环保特性,已被广泛应用于电动汽车、储能系统等领域。然而,锂电池的安全性和…...
【星海出品】flask (四) 三方工具使用
学习的灵魂是公社,学习的目标是人民自治.学习是非暴力革命方式的社会改革.学习是人民对抗资本剥夺的文明方式.学习失败了,就如同巴黎公社失败了一样.但是它为今后进行成功的社会改革指明了正确的方向.学习的逻辑并不复杂,一句话,必须让知识数量与知识价值基本吻合.管理学习也不…...
MongoDB 索引
类似关系型数据库,mongodb也建立自己的一套索引机制和查询优化方法。本文简单介绍mongodb的索引。后续文章讲详细介绍索引的操作,监控和查询优化方法等。 索引 索引,是一组按照特殊结构排列的,方便检索的数据。索引中保存了集合…...

[Hive] INSERT OVERWRITE DIRECTORY要注意的问题
在使用Hive的INSERT OVERWRITE语句时,需要注意以下问题: 数据覆盖:INSERT OVERWRITE语句会覆盖目标目录中的数据。因此,在执行该语句之前,请确保目标目录为空或者你希望覆盖的数据已经不再需要。数据格式:…...

刚柔相济铸伟业 ——访湖南顺新金属制品科技有限公司董事长张顺新
时代在变,唯初心不改。 精致、谦虚、谨慎、儒雅、温和——他就是张顺新,湖南顺新金属制品科技有限公司、湖南顺新供应链管理有限公司董事长,民建长沙市委常委,民建湖南省环资委副主任,省、市民建企联会常务副会长&…...

DHorse(K8S的CICD平台)的实现原理
综述 首先,本篇文章所介绍的内容,已经有完整的实现,可以参考这里。 在微服务、DevOps和云平台流行的当下,使用一个高效的持续集成工具也是一个非常重要的事情。虽然市面上目前已经存在了比较成熟的自动化构建工具,比如…...

类图复习:类图简单介绍
入职新公司在看新项目的代码,所以借助类图梳理各个类之间的关系,奈何知识已经还给了老师,不得不重新学习下类图的相关知识,此处将相关内容记录下方便后续使用。 文章目录 类图语法类与类的关系画类图 类图语法 语法描述public-pr…...
RestClient
什么是RestClient RestClient 是 Elasticsearch 官方提供的 Java 低级 REST 客户端,它允许HTTP与Elasticsearch 集群通信,而无需处理 JSON 序列化/反序列化等底层细节。它是 Elasticsearch Java API 客户端的基础。 RestClient 主要特点 轻量级ÿ…...

XML Group端口详解
在XML数据映射过程中,经常需要对数据进行分组聚合操作。例如,当处理包含多个物料明细的XML文件时,可能需要将相同物料号的明细归为一组,或对相同物料号的数量进行求和计算。传统实现方式通常需要编写脚本代码,增加了开…...
Java 语言特性(面试系列1)
一、面向对象编程 1. 封装(Encapsulation) 定义:将数据(属性)和操作数据的方法绑定在一起,通过访问控制符(private、protected、public)隐藏内部实现细节。示例: public …...
golang循环变量捕获问题
在 Go 语言中,当在循环中启动协程(goroutine)时,如果在协程闭包中直接引用循环变量,可能会遇到一个常见的陷阱 - 循环变量捕获问题。让我详细解释一下: 问题背景 看这个代码片段: fo…...

工业安全零事故的智能守护者:一体化AI智能安防平台
前言: 通过AI视觉技术,为船厂提供全面的安全监控解决方案,涵盖交通违规检测、起重机轨道安全、非法入侵检测、盗窃防范、安全规范执行监控等多个方面,能够实现对应负责人反馈机制,并最终实现数据的统计报表。提升船厂…...

【快手拥抱开源】通过快手团队开源的 KwaiCoder-AutoThink-preview 解锁大语言模型的潜力
引言: 在人工智能快速发展的浪潮中,快手Kwaipilot团队推出的 KwaiCoder-AutoThink-preview 具有里程碑意义——这是首个公开的AutoThink大语言模型(LLM)。该模型代表着该领域的重大突破,通过独特方式融合思考与非思考…...
【算法训练营Day07】字符串part1
文章目录 反转字符串反转字符串II替换数字 反转字符串 题目链接:344. 反转字符串 双指针法,两个指针的元素直接调转即可 class Solution {public void reverseString(char[] s) {int head 0;int end s.length - 1;while(head < end) {char temp …...
在Ubuntu中设置开机自动运行(sudo)指令的指南
在Ubuntu系统中,有时需要在系统启动时自动执行某些命令,特别是需要 sudo权限的指令。为了实现这一功能,可以使用多种方法,包括编写Systemd服务、配置 rc.local文件或使用 cron任务计划。本文将详细介绍这些方法,并提供…...

微信小程序云开发平台MySQL的连接方式
注:微信小程序云开发平台指的是腾讯云开发 先给结论:微信小程序云开发平台的MySQL,无法通过获取数据库连接信息的方式进行连接,连接只能通过云开发的SDK连接,具体要参考官方文档: 为什么? 因为…...
3403. 从盒子中找出字典序最大的字符串 I
3403. 从盒子中找出字典序最大的字符串 I 题目链接:3403. 从盒子中找出字典序最大的字符串 I 代码如下: class Solution { public:string answerString(string word, int numFriends) {if (numFriends 1) {return word;}string res;for (int i 0;i &…...