Linux基础项目开发1:量产工具——显示系统

news2024/11/26 17:31:17

文章目录

  • 数据结构抽象
    • 使用场景
    • disp_mannger.h
  • Framebuffer编程
    • Framebuffer.c
  • 显示管理
    • 最终disp_manager.h
    • disp_manager.c
  • 测试单元
    • 测试代码

数据结构抽象

我们添加的显示管理器中有Framebufferweb输出,对于两个不同的设别我们需要抽象出同一个结构体类型!

使用场景

在这里插入图片描述

① 我们主要是将其分为了两层,上层要获得下层某个结构体,通过这个结构体中的函数来初始化、操作、回执、刷新上层的界面。
②所以我们需要定义一个统一的结构体DisOpr

disp_mannger.h

//定义一个结构体,用于表示显示操作的相关信息
typedef struct DispOpr {
	char *name;//操作区域的名称
	int*DeviceInit)(void);//指向函数的指针,用于初始化设备
	int*DeviceExit)(void);//指向函数的指针,用于退出设备
	int*GetBuffer)(PDispBuff ptDispBuff);//指向函数的指针,用于获取缓冲区信息
	int*FlushRegion)(PRegion ptRegion, PDispBuff ptDispBuff);//指向函数的指针,用刷新指定区域
	struct DispOpr *ptNext;//指向下一个结构体的指针,用于链表
}DispOpr, *PDispOpr;

这个结构体是一步一步通过补充的得到的,缺啥就补啥!
再定义一个结构体表示某快区域的信息(刷到硬件上去用到的):

//定义一个结构体,用于表示屏幕上的一块区域的信息
typedef struct Region {
	int iLeftUpX;//区域左上角的X坐标
	int iLeftUpY;//区域左上角的Y坐标
	int iWidth;//区域的宽度
	int iHeigh;//区域的高度
}Region, *PRegion;

Framebuffer编程

Framebuffer.c

#include <sys/mman.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <linux/fb.h>
#include <fcntl.h>
#include <stdio.h>
#include <string.h>
#include <sys/ioctl.h>

#include "disp_manager.h"

static int fd_fb; //Framebuffer描述符
static struct fb_var_screeninfo var; // 当前屏幕信息
static int screen_size; //Framebuffer长度
static unsigned char *fb_base; // Framebuffer地址
static unsigned int line_width; //行宽度
static unsigned int pixel_width; //像素宽度

//初始化设备函数
static int FbDeviceInit(void)
{
	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;
	}

	return 0;
}

//退出设备函数
static int FbDeviceExit(void)
{
	munmap(fb_base, screen_size); //取消内存映射
	close(fd_fb); //关闭文件描述符
	return 0;
}
/*
//定义一个结构体,缓存屏幕的信息
typedef struct DispBuff {
	int iXres; //行分辨率
	int iYres; //竖分标绿
	int iBpp; //Bpp
	char *buff; //保存mmap函数返回的映射区域地址
}DispBuff, *PDispBuff;
*/

//获取Framebuffer缓冲区信息
static int FbGetBuffer(PDispBuff ptDispBuff);//PDispBuff 结构体如上所述
{
	ptDispBuff->iXres = var.xres; //设置X分辨率
	ptDispBuff->iYres = var.yres; //设置Y分辨率
	ptDispBuff->iBpp  = var.bits_per_pixel; //设置每像素点位数
	ptDispBuff->buff  = fb_base; // 设置缓冲区的地址
	return 0;
}

//刷新指定区域到Framebuffer,具体功能没实现
static int FbFlushRegion(PRegion ptRegion, PDispBuff ptDispBuff)
{
	return 0;
}

//定义一个DispOpr 结构体,用于描述Framebuffer操作
static DispOpr g_tFramebufferOpr = {
	.name        = "fb", //操作名称
	.DeviceInit  = FbDeviceInit, //初始化函数指针
	.DeviceExit  = FbDeviceExit, //退出函数指针
	.GetBuffer   = FbGetBuffer, //获取缓冲区信息函数指针
	.FlushRegion = FbFlushRegion, //刷新区域函数指针
};

//初始化Framebuffer
void FramebufferInit(void)
{
	RegisterDisplay(&g_tFramebufferOpr);
}


有些还没有定义的参数名称详细介绍在后面介绍,在disp_manager.c中!

显示管理

上面所写的是要选择哪个设备进行显示,需要中间加一个函数进行选择,起到承上启下的作用,用于管理显示管理,是操作Framebuffer还是web设备!
在这里插入图片描述

最终disp_manager.h

#ifndef _DISP_MANAGER_H
#define _DISP_MANAGER_H

//定义一个结构体,缓存屏幕的信息
typedef struct DispBuff {
	int iXres; //行分辨率
	int iYres; //竖分标绿
	int iBpp; //Bpp
	char *buff; //保存mmap函数返回的映射区域地址
}DispBuff, *PDispBuff;

//定义一个结构体,用于表示屏幕上的一块区域的信息
typedef struct Region {
	int iLeftUpX;//区域左上角的X坐标
	int iLeftUpY;//区域左上角的Y坐标
	int iWidth;//区域的宽度
	int iHeigh;//区域的高度
}Region, *PRegion;

//定义一个结构体,用于表示显示操作的相关信息
typedef struct DispOpr {
	char *name;//操作区域的名称
	int DeviceInit(void);//指向函数的指针,用于初始化设备
	int DeviceExit(void);//指向函数的指针,用于退出设备
	int GetBuffer(PDispBuff ptDispBuff);//指向函数的指针,用于获取缓冲区信息
	int FlushRegion(PRegion ptRegion, PDispBuff ptDispBuff);//指向函数的指针,用刷新指定区域
	struct DispOpr *ptNext;//指向下一个结构体的指针,用于链表
}DispOpr, *PDispOpr;

函数声明:

//注册一个显示操作到显示管理器
void RegisterDisplay(PDispOpr ptDispOpr);
//初始化显示管理器
void DisplayInit(void);
//选择一个默认的显示操作区域
int SelectDefaultDisplay(char *name);
//在屏幕上化一个像素点
int InitDefaultDisplay(void);
//刷新屏幕上的一个区域
int PutPixel(int x, int y, unsigned int dwColor);
//获取缓冲区的信息
int FlushDisplayRegion(PRegion ptRegion, PDispBuff ptDispBuff);


#endif

disp_manager.c

#include "disp_manager.h"

/* 管理底层的LCD、WEB */
static PDispOpr g_DispDevs = NULL; //指向第一个显示设备的指针
static PDispOpr g_DispDefault = NULL; //指向默认显示设备的指针
static DispBuff g_tDispBuff; //存储默认显示缓冲区的信息
static int line_width; //每行像素的宽度(字节数)
static int pixel_width; //每个像素的宽度(字节数)

//在屏幕上画一个点
int PutPixel(int x, int y, unsigned int dwColor)
{
    // 根据屏幕的映射地址极计算要画的点的地址
	unsigned char *pen_8 = g_tDispBuff.buff+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;

    //根究BPP的位数不同来选择表示颜色方式
	switch (g_tDispBuff.iBpp)
	{
		case 8: //8bpp
		{
			*pen_8 = dwColor;
			break;
		}
		case 16: //16bpp
		{
			/* 565 */
			red   = (dwColor >> 16) & 0xff;
			green = (dwColor >> 8) & 0xff;
			blue  = (dwColor >> 0) & 0xff;
			dwColor = ((red >> 3) << 11) | ((green >> 2) << 5) | (blue >> 3);
			*pen_16 = dwColor;
			break;
		}
		case 32: //32bpp
		{
			*pen_32 = dwColor;
			break;
		}
		default:
		{
			printf("can't surport %dbpp\n", g_tDispBuff.iBpp);
			break;
			return -1;
		}
	}
	return 0;
}


//注册一个显示区域设备
void RegisterDisplay(PDispOpr ptDispOpr)
{
	ptDispOpr->ptNext = g_DispDevs;//将要注册的区域设备的next指向头
	g_DispDevs = ptDispOpr;//将头改为ptDispOpr,下一个的next就会指向它
}

//选择一个默认的显示区域设备
int SelectDefaultDisplay(char *name)
{
	PDispOpr pTmp = g_DispDevs;
	while (pTmp) 
	{
		if (strcmp(name, pTmp->name) == 0)
		{
			g_DispDefault = pTmp;
			return 0;
		}

		pTmp = pTmp->ptNext;
	}

	return -1;
}

//初始化默认的初始化设备
int InitDefaultDisplay(void)
{
	int ret;
	
	ret = g_DispDefault->DeviceInit();
	if (ret)
	{
		printf("DeviceInit err\n");
		return -1;
	}

	
	ret = g_DispDefault->GetBuffer(&g_tDispBuff);
	if (ret)
	{
		printf("GetBuffer err\n");
		return -1;
	}

	line_width  = g_tDispBuff.iXres * g_tDispBuff.iBpp/8;
	pixel_width = g_tDispBuff.iBpp/8;

	return 0;
}

//刷新屏幕上一个区域
int FlushDisplayRegion(PRegion ptRegion, PDispBuff ptDispBuff)
{
	return g_DispDefault->FlushRegion(ptRegion, ptDispBuff);
}


void DisplayInit(void)
{
	//FramebufferInit();
}


测试单元

测试代码

#include <sys/mman.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <linux/fb.h>
#include <fcntl.h>
#include <stdio.h>
#include <string.h>
#include <sys/ioctl.h>

#include <disp_manager.h>

#define FONTDATAMAX 4096

/**********************************************************************
 * 函数名称: lcd_put_ascii
 * 功能描述: 在LCD指定位置上显示一个8*16的字符
 * 输入参数: x坐标,y坐标,ascii码
 * 输出参数: 无
 * 返 回 值: 无
 * 修改日期        版本号     修改人	      修改内容
 * -----------------------------------------------
 * 2020/05/12	     V1.0	  zh(angenao)	      创建
 ***********************************************************************/ 
void lcd_put_ascii(int x, int y, unsigned char c)
{
	unsigned char *dots = (unsigned char *)&fontdata_8x16[c*16];
	int i, b;
	unsigned char byte;

	for (i = 0; i < 16; i++)
	{
		byte = dots[i];
		for (b = 7; b >= 0; b--)
		{
			if (byte & (1<<b))
			{
				/* show */
				PutPixel(x+7-b, y+i, 0xffffff); /* 白 */
			}
			else
			{
				/* hide */
				PutPixel(x+7-b, y+i, 0); /* 黑 */
			}
		}
	}
}

int main(int argc, char **argv)
{
	Region region; //定义刷新区域的大小
	PDispBuff ptBuffer;
		
	DisplayInit(); //初始化显示系统

	SelectDefaultDisplay("fb");//选择默认的显示设备

	InitDefaultDisplay();//初始化选定的显示设备

	lcd_put_ascii(100, 100, 'A');

	region.iLeftUpX = 100;
	region.iLeftUpY = 100;
	region.iWidth   = 8;
	region.iHeigh   = 16;

	ptBuffer = GetDisplayBuffer();//获取显示缓冲区
	FlushDisplayRegion(&region, ptBuffer);//刷新指定区域的显示内容
	
	return 0;	
}

测试代码分析:
在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2192987.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

市面上8款AI论文大纲一键生成文献的软件推荐

在当前的学术研究和写作领域&#xff0c;AI论文大纲自动生成软件已经成为提高写作效率和质量的重要工具。这些工具不仅能够帮助研究人员快速生成论文草稿&#xff0c;还能进行内容优化、查重和排版等操作。本文将分享市面上8款AI论文大纲一键生成文献的软件&#xff0c;并特别推…

YOLOv11改进 | 卷积模块 | 分布移位卷积DSConv替换Conv

秋招面试专栏推荐 &#xff1a;深度学习算法工程师面试问题总结【百面算法工程师】——点击即可跳转 &#x1f4a1;&#x1f4a1;&#x1f4a1;本专栏所有程序均经过测试&#xff0c;可成功执行&#x1f4a1;&#x1f4a1;&#x1f4a1; 本文介绍DSConv&#xff0c; DSConv 将…

算法1:双指针思想的运用(2)--C++

1.盛水最多的容器 题目链接&#xff1a;11. 盛最多水的容器 - 力扣&#xff08;LeetCode&#xff09; 题目解析&#xff1a; 在解析题目时&#xff0c;我们可以把最直接的方法先列举出来&#xff0c;然后再根据相应的算法原理&#xff0c;来进行优化 思路一&#xff1a;暴力…

Docker 启动 Neo4j:详细配置指南和浏览器访问

Docker 启动 Neo4j&#xff1a;详细配置指南和浏览器访问 文章目录 Docker 启动 Neo4j&#xff1a;详细配置指南和浏览器访问一 Neo4j compose 得 yml 配置二 配置描述三 浏览器访问 这篇文章详细介绍了如何使用 Docker Compose 启动 Neo4j 数据库&#xff0c;包括 docker-com…

菜鸟笔记003 获取目标对象的颜色值

在illustrator中,我们时常要获取一些对象的颜色值,但是一时不知道如何获取,下面我就来讲讲如何获取目标对象的颜色值。 下面以选择对象的最上层对象为例,我们通过查阅javascript编程手册,可以很容易获取下面代码: var sel=app.activeDocument.selection[0]; //获取最上…

【S32K3 RTD MCAL 篇1】 K344 KEY 控制 EMIOS PWM

【S32K3 RTD MCAL 篇1】 K344 KEY 控制 EMIOS PWM 一&#xff0c;文档简介二&#xff0c; 功能实现2.1 软硬件平台2.2 软件控制流程2.3 资源分配概览2.4 EB 配置2.4.1 Dio module2.4.2 Icu module2.4.4 Mcu module2.4.5 Platform module2.4.6 Port module2.4.7 Pwm module 2.5 …

SCTF2024(复现)

SCTF2024&#xff08;复现&#xff09; web SycServer2.0 开题&#xff1a; 需要登录&#xff0c;进行目录扫描&#xff0c;得到/config&#xff0c;/hello&#xff0c;/robots.txt 等&#xff0c;访问/hello 显示需要 token&#xff0c;查看源码发现存在 sqlwaf 可以通过抓…

基于ucontext库实现协程类

文章目录 前言协程基础知识协程上下文对称协程与⾮对称协程有栈协程与⽆栈协程 ucontext库接口熟悉一个简单的函数切换自动调用 协程类的实现接口全局变量线程局部变量malloc封装协程切换构造函数协程执行的方法 测试协程切换手动切换复用 前言 协程&#xff08;Coroutine&…

Maven安装使用

说明&#xff1a;Maven是Apache旗下的一个开源项目&#xff0c;是一款用于管理和构建java项目的工具。一般来说&#xff0c;它帮助我们管理依赖、构建项目。本文介绍在Windows系统下安装Maven。 下载&安装&验证 下载 首先&#xff0c;在Maven官网&#xff08;https:…

【第十五周】PyTorch深度学习实践2

目录 摘要Abstract1.多分类问题1.1.Softmax1.2.维度问题1.3.NLLLoss v.s. CrossEntropy1.4.代码实践1.4.1.导入相应的包1.4.2.准备数据集1.4.3.模型设计1.4.4.构造损失和优化器1.4.5.模型训练 2.卷积神经网络基础篇2.1.代码实践2.1.1.导入相应的包&#xff1a;2.1.2.准备数据集…

我谈巴特沃斯滤波器

目录 写在前面的内容我谈巴特沃斯滤波器巴特沃斯滤波器的幅频响应频率变换巴特沃斯各种滤波器例子 写在前面的内容 先看看冈萨雷斯对巴特沃斯滤波器的介绍。 低通 高通 带阻 带通 第一个问题&#xff0c;截止频率处的增益。 0.5的增益是不是陡度小了&#xff1f;巴特沃…

ai智能论文生成系统有用吗?分享5款ai文献综述自动生成器

近年来&#xff0c;人工智能&#xff08;AI&#xff09;技术在学术写作领域的应用越来越广泛&#xff0c;尤其是在文献综述的自动生成方面。AI智能论文生成系统通过深度学习和自然语言处理技术&#xff0c;能够帮助研究人员快速生成高质量的文献综述&#xff0c;从而提高写作效…

深度扩展AntSK,让.NET Aspire助力您的AI项目

引言 在现今飞速发展的技术世界中&#xff0c;引用最新的工具和框架来提升项目的性能和可管理性至关重要。作为一名开发者&#xff0c;我最近在自己的AI知识库项目AntSK中集成了.NET Aspire&#xff0c;这为我的项目注入了新的活力。如果你还不清楚什么是.NET Aspire&#xff0…

[单master节点k8s部署]32.ceph分布式存储(三)

基于ceph rbd生成pv 在集群中认证ceph 用下面代码生成ceph的secret .创建 ceph 的 secret&#xff0c;在 k8s 的控制节点操作&#xff1a; 回到 ceph 管理节点创建 pool 池&#xff1a; [rootmaster1-admin ~]# ceph osd pool create k8stest 56 pool k8stest created [rootm…

BERT论文解读及情感分类实战(论文复现)

BERT论文解读及情感分类实战&#xff08;论文复现&#xff09; 本文所涉及所有资源均在传知代码平台可获取 文章目录 BERT论文解读及情感分类实战&#xff08;论文复现&#xff09;简介BERT文章主要贡献BERT模型架构技术细节任务1 Masked LM&#xff08;MLM&#xff09;任务2 N…

【web安全】——常见框架漏洞

1.ThinkPHP框架漏洞 thinkphp是一个国内轻量级的开发框架&#xff0c;采用phpapache&#xff0c;在更新迭代中&#xff0c;thinkphp也经常爆出各种漏洞&#xff0c;thinkphp一般有thinkphp2、thinkphp3、thinkphp5、thinkphp6版本&#xff0c;前两个版本已经停止更新&#xff…

【详细教程】如何使用YOLOv11进行图像与视频的目标检测

《博主简介》 小伙伴们好&#xff0c;我是阿旭。专注于人工智能、AIGC、python、计算机视觉相关分享研究。 ✌更多学习资源&#xff0c;可关注公-仲-hao:【阿旭算法与机器学习】&#xff0c;共同学习交流~ &#x1f44d;感谢小伙伴们点赞、关注&#xff01; 《------往期经典推…

m4a怎么转换成mp3?音频转换MP3只需要这6个小工具!

m4a怎么转换成mp3&#xff1f;M4A和MP3是两种常见的音频格式&#xff0c;M4A通常使用AAC&#xff08;高级音频编码&#xff09;进行压缩&#xff0c;提供更高的音质和更小的文件体积&#xff0c;特别适合在Apple设备上使用。而MP3则以其高压缩比和广泛的兼容性著称&#xff0c;…

TM1618数码管控制芯片使用共阳极数码管过程中的问题和解决办法

控制芯片的基本了解 相比于不用控制芯片的电路&#xff1a;这里带2根电源线和3个信号线&#xff0c;共使用了5根线&#xff0c;但可以控制4个8段数码管显示。若是电路直接控制4个8段数码管需要84113个接口&#xff0c;这对于MCU的珍贵引脚简直是浪费。 这里不会出现余晖效应也…

大花蔷薇T2T基因组-60

Multi-omics analyzes of Rosa gigantea illuminate tea scent biosynthesis and release mechanisms 多组学分析揭示了大花蔷薇茶香合成及释放机制 摘要 玫瑰是一种全球广泛栽培的重要观赏作物&#xff0c;用于香水生产。然而&#xff0c;由于缺乏茶玫瑰的参考基因组&#x…