当前位置: 首页 > news >正文

im6ull学习总结(二)Framebuffer 应用编程

1 LCD操作原理

linux中通过framebuffer驱动程序来控制LCD。framebuffer中包含LCD的参数,大小为LCD分辨率xbpp。framebuffer 是一块内存 内存中保存了一帧图像。
关于图像的帧指的是在图像处理中,一帧(Frame)是指图像序列中的单个静止图像。当连续的图像以每秒多帧的速度播放时,就可以产生动画、视频或电影。每一帧都是由像素组成的二维网格,每个像素都包含颜色和亮度信息。通过在连续的帧之间进行快速切换,人眼会感知到连续的动态效果。因此,一帧是构成动画和视频的基本单元。
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)像素起始地址=fb_base+(xres*bpp/8)y + xbpp/8
xres:x方向分辨率bpp每个像素的位数
/8:将位数换算成字节
y y坐标这里从第0行开始所以不用减1
x x坐标
bpp :每个像素的位数bits per pixel
有RGB888 565 555格式
在这里插入图片描述
对于 32BPP,一般只设置其中的低 24 位,高 8 位表示透明度,一般的 LCD都不支持。
对于 24BPP,硬件上为了方便处理,在 Framebuffer 中也是用 32 位来表示,效果跟 32BPP 是一样的。
对于 16BPP,常用的是 RGB565;很少的场合会用到 RGB555,这可以通过ioctl 读取驱动程序中的 RGB 位偏移来确定使用哪一种格式
这里补充一下寻址方式一般为字节寻址也就是说一个地址对应的一个储存单元能储存8位数据。

实验一 并画一条直线

#include <fcntl.h>
#include <stdint.h>
#include <stdio.h>
#include <sys/ioctl.h>
#include <linux/fb.h>
#include <sys/mman.h>
#include <sys/types.h>
#include <string.h>
#include <unistd.h>
static struct fb_var_screeninfo var;
static int  fd_fb;
static unsigned int screen_size;
static unsigned int line_width;
static unsigned int pixel_width;
static unsigned char *fb_base;
static void  lcd_put_pixel(int x, int y,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;//printf("*pen_8= %d\n",*pen_8);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;// printf("*pen_16= %d\n",*pen_16);break;}case 32:{*pen_32 = color;// printf("*pen_32= %d\n",*pen_32);break;}default:{printf("can't surport %dbpp\n", var.bits_per_pixel);break;}}
}
int main(char argc, char **argv)
{int i;//这里我先提个问题如何确定设备驱动文件的/* 以只读方式打开驱动设备文件 */fd_fb = open("/dev/fb0", O_RDWR);if(fd_fb<0){printf("cannot open /dev/fb0 \n");return -1;}/* fd_fb:是一个打开的 Framebuffer 设备文件的文件描述符。
FBIOGET_VSCREENINFO:是一个常量宏,表示获取可见屏幕信息的操作。
&var:是一个指向 vscreeninfo 结构体的指针,用于接收获取到的可见屏幕信息。 */// ioctl成功返回 失败-1if (ioctl(fd_fb, FBIOGET_VSCREENINFO,&var)){printf("can not get var \n");return -1;}/* 一行的字节数 */line_width = var.xres *var.bits_per_pixel/8;/* bpp转换成字节 */pixel_width =  var.bits_per_pixel/8;screen_size = var.xres*var.yres*var.bits_per_pixel/8;printf("var.bits_per_pixel= %d\n",var.bits_per_pixel);/* MAP_SHARED 表示映射区域与其他进程共享。0:表示映射区域在文件中的偏移量,此处为从文件开头开始映射。*/fb_base=(unsigned char *)mmap(NULL  ,screen_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd_fb, 0);/* mmap 调用失败,它会返回 MAP_FAILED(通常定义为 (void *)-1) */if(fb_base == (unsigned char *) -1){printf("can not mmap \n");return -1;}memset(fb_base, 0xff, screen_size);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;
}

实验效果
在屏幕中间从左至右画了一条横线
终端打印出:var.bits_per_pixel= 32
这里我有几个问题
1、mmap返回值转换成uchar*类型: 这时注意地址并没有变地址这个指针操作系统是多少位他就永远是多少位,他指向的内容也不会变,只是寻址方式发生变化
在这里插入图片描述
就比如我们看datasheet stm32 的一个寄存器偏移地址为0x00而下一个为0x04 他就是以四个字节递增的。
再比如我们从flash中读取一段数据 要区分半字读还是字读。

2、这引入了第二个问题
在这里插入图片描述
x++后地址偏移的字节数是根据pixel_width决定的 pixel_width = var.bits_per_pixel/8; var.bits_per_pixel 为32位那么一次偏移4个字节刚好32位存储32位数据
在这里插入图片描述
也就是说2进制编码中一个地址存放1位数据0/1 0x1000 到0x1004 则跨了四个字节32位能存储32位数据。

http://www.lryc.cn/news/268807.html

相关文章:

  • 数据仓库 基本信息
  • 仓储革新:AR技术引领物流进入智慧时代
  • 软件仓库部署及应用
  • ASUS华硕ROG幻16笔记本电脑2023款GU604VI VZ VY原装出厂Windows11系统22H2
  • 可视化云监控/安防监控系统EasyCVR视频管理平台播流失败的原因(端口篇)
  • 边缘检测——PidiNet网络训练自己数据集并优化推理测试(详细图文教程)
  • SpringBoot整合Mybatis遇到的常见问题及解决方案
  • 【10】ES6:Promise 对象
  • Hive和Spark生产集群搭建(spark on doris)
  • VuePress、VuePress-theme-hope 搭建个人博客 1【快速上手】 —— 防止踩坑篇
  • 【PostgreSQL】从零开始:(三十一)数据类型-复合类型
  • 基于鸿蒙OS开发一个前端应用
  • PIC单片机项目(7)——基于PIC16F877A的智能灯光设计
  • Mysql For Navicate (老韩)
  • 设计模式之-建造者模式通俗易懂理解,以及建造者模式的使用场景和示列代码
  • Redis分布式锁进阶源码分析
  • lag-llama源码解读(Lag-Llama: Towards Foundation Models for Time Series Forecasting)
  • Three.js基础入门介绍——Three.js学习三【借助控制器操作相机】
  • 【日志系列】什么是分布式日志系统?
  • [卷积神经网络]FCOS--仅使用卷积的Anchor Free目标检测
  • Ubuntu fcitx Install
  • 【Makefile/GNU Make】知识总结
  • 腾讯云轻量服务器和云服务器CVM该怎么选?区别一览
  • MySQL定时备份实现
  • Nginx 不同源Https请求Http 报strict-origin-when-cross-origin
  • openGauss学习笔记-175 openGauss 数据库运维-备份与恢复-导入数据-管理并发写入操作示例
  • pnpm、npm、yarn是什么?怎么选择?
  • MySQL8 一键部署
  • 12 UVM Driver
  • “暂存”校验逻辑探讨