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

news2024/11/19 13:16:17

前言:

前面我们已经对这个项目的基本框架有了一个初步的了解与认识,要实现显示管理器与输入管理器,有输入有输出基本就实现这个项目的大部分功能了,首先我们先来做显示系统,对于上层系统为了让程序更好扩展,我们得添加一个显示管理器,在下面有各种设备,就比如有Framebuflerweb输出。

一、数据结构抽象

        我们添加的一个显示管理器中有Framebuflerweb输出,对于俩个不同的设备我们需要抽象出同一个结构体类型。

1.使用场景

        在上图中我们可以将其分为两层,上层要获得下层某个结构体,通过这个结构体中的函数来操作、绘制、刷新上层的界面。

        所有我们需要定义一个统一的结构体DispOpr

 2.disp_manager.h

  1 #ifndef _DISP_MANAGER_H
  2 #define _DISP_MANAGER_H
  3
  4 typedef struct Region {
  5     int iLeftUpX;                //左上角x坐标
  6     int iLeftUpY;                //左上角y坐标
  7     int iWidth;                  //宽度
  8     int iHeigh;                  //高度
  9 }Region, *PRegion;
 10
 11 typedef struct DispOpr {
 12     char *name;                  //显示模块的名字 
 13     char *GetBuffer(int *pXres, int *pYres, int *pBpp);//分辨率(长和宽)每个像素占据多少位
 14     int FlushRegion(PRegion ptRegion, char *buffer);//刷出某个区域
 15     struct DispOpr *ptNext;      //链表
 16 };
 17
 18 #endif
 19

第1~2行:防止头文件在.c文件中多次定义

第4~9行:定义刷新区域结构体

第11~16行:定义统一管理的结构体

二、Framebuffer编程

1.disp_manager.h

  1 #ifndef _DISP_MANAGER_H
  2 #define _DISP_MANAGER_H
  3
  4 typedef struct Region {
  5     int iLeftUpX;
  6     int iLeftUpY;
  7     int iWidth;
  8     int iHeigh;
  9 }Region, *PRegion;
 10
 11 typedef struct DispOpr {
 12     char *name;
 13     int DeviceInit(void);
 14     int DeviceExit(void);
 15     char *GetBuffer(int *pXres, int *pYres, int *pBpp);
 16     int FlushRegion(PRegion ptRegion, char *buffer);
 17     struct DispOpr *ptNext;
 18 }DispOpr, *PDispOpr;
 19
 20 #endif

第13行:初始化函数定义

第14行:退出函数定义

2.framebuffer.c

  1 #include <sys/mman.h>
  2 #include <sys/types.h>
  3 #include <sys/stat.h>
  4 #include <unistd.h>
  5 #include <linux/fb.h>
  6 #include <fcntl.h>
  7 #include <stdio.h>
  8 #include <string.h>
  9 #include <sys/ioctl.h>
 10
 11 #include "disp_manager.h"
 12
 13 static int fd_fb;                       //framebuffer文件
 14 static struct fb_var_screeninfo var;    /* Current var */
 15 static int screen_size;                 //framebuffer长度
 16 static unsigned char *fb_base;          //framebuffer地址
 17 static unsigned int line_width;
 18 static unsigned int pixel_width;
 19
 20 static int DeviceInit(void)
 21 {
 22     fd_fb = open("/dev/fb0", O_RDWR);
 23     if (fd_fb < 0)
 24     {
 25         printf("can't open /dev/fb0\n");
 26         return -1;
 27     }
 28     if (ioctl(fd_fb, FBIOGET_VSCREENINFO, &var))
 29     {
 30         printf("can't get var\n");
 31         return -1;
 32     }
 33
 34     line_width  = var.xres * var.bits_per_pixel / 8;
 35     pixel_width = var.bits_per_pixel / 8;
 36     screen_size = var.xres * var.yres * var.bits_per_pixel / 8;
 37     fb_base = (unsigned char *)mmap(NULL , screen_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd_fb, 0);
 38     if (fb_base == (unsigned char *)-1)
 39     {
 40         printf("can't mmap\n");
 41         return -1;
 42     }
 43
 44     return 0;
 45 }
 46
 47 static int DeviceExit(void)
 48 {
 49     munmap(fb_base, screen_size);
 50     close(fd_fb);
 51     return 0;
 52 }
 53
 54
 55 /* 可以返回LCD的framebuffer, 以后上层APP可以直接操作LCD, 可以不用FbFlushRegion
 56  * 也可以malloc返回一块无关的buffer, 要使用FbFlushRegion刷到LCD上
 57  */
 58 static int FbGetBuffer(PDispBuff ptDispBuff);
 59
 60 {
 61     ptDispBuff->iXres = var.xres;
 62     ptDispBuff->iYres = var.yres;
 63     ptDispBuff->iBpp  = var.bits_per_pixel;
 64     ptDispBuff->buff  = (char *)fb_base;
 65     return 0;
 66 }
 67
 68 static int FbFlushRegion(PRegion ptRegion, PDispBuff ptDispBuff)
 69 {
 70     return 0;
 71 }
 72
 73
 74 static DispOpr g_tFramebufferOpr = {
 75     .name        = "fb",
 76     .DeviceInit  = FbDeviceInit,
 77     .DeviceExit  = FbDeviceExit,
 78     .GetBuffer   = FbGetBuffer,
 79     .FlushRegion = FbFlushRegion,
 80 };
 81
 82
 83 void FramebufferInit(void)
 84 {
 85     RegisterDisplay(&g_tFramebufferOpr);
 86 }
 87

 20 static int DeviceInit(void)

第20~45行:初始化函数

 47 static int DeviceExit(void)

第47~52行:退出函数

第58~66行的FbGetBuffer是已经封装好的,详细封装过程后续会讲

第61~62行:设置分辨率

第63行:设置bpp

74 static DispOpr g_tFramebufferOpr

第74~80行:上层代码可以根据这个结构体里的函数来初始化LCD来得到Buffer

        第78行:通过.GetBuffer   = FbGetBuffer来构建好图像和文字

        第79行:通过.FlushRegion = FbFlushRegion来刷新到LCD上

第83~86行:注册结构体g_tFramebufferOpr,详细介绍在三、显示管理

        

三、显示管理

        上层函数想要选择哪个设备进行显示,需要中间加一个函数进行选择,起到承上启下的作用,用来实现显示管理,是操作Framebuffer还是WEB设备,需要进行选择某个模块,好可以提供一些函数,描点等

1.disp_manager.h

  1 #ifndef _DISP_MANAGER_H
  2 #define _DISP_MANAGER_H
  3
  4 #ifndef NULL
  5 #define NULL (void *)0
  6 #endif
  7
  8 typedef struct DispBuff {
  9     int iXres;     //x坐标分辨率
 10     int iYres;     //y坐标分辨率
 11     int iBpp;      //bpp
 12     char *buff;    缓冲区地址
 13 }DispBuff, *PDispBuff;
 14
 15
 16 typedef struct Region {
 17     int iLeftUpX;
 18     int iLeftUpY;
 19     int iWidth;
 20     int iHeigh;
 21 }Region, *PRegion;
 22
 23 typedef struct DispOpr {
 24     char *name;
 25     int (*DeviceInit)(void);
 26     int (*DeviceExit)(void);
 27     int (*GetBuffer)(PDispBuff ptDispBuff);
 28     int (*FlushRegion)(PRegion ptRegion, PDispBuff ptDispBuff);
 29     struct DispOpr *ptNext;
 30 }DispOpr, *PDispOpr;
 31
 32 void RegisterDisplay(PDispOpr ptDispOpr);
 33
 34 void DisplayInit(void);
 35 int SelectDefaultDisplay(char *name);
 36 int InitDefaultDisplay(void);
 37 int PutPixel(int x, int y, unsigned int dwColor);
 38 int FlushDisplayRegion(PRegion ptRegion, PDispBuff ptDispBuff);
 39 PDispBuff GetDisplayBuffer(void);
 40
 41
 42 #endif

第8~13行:进一步封装GetBuffer(int *pXres, int *pYres, int *pBpp)

第27行:将4~9行的PDispBuff保存到GetBuffer

第32行:定义注册函数RegisterDisplay

第34行:调用底层提供的模块

第35行:定义选择模块函数

第36行:选择默认的SelectDefaultDisplay后,我们还需要定义初始化函数

第37行:提供绘制图像函数

第38行:将绘制好的图像刷新到硬件上

第39行:返回取址 

2.disp_manager.c

  1 #include <disp_manager.h>
  2 #include <stdio.h>
  2 #include <string.h>
  2
  3 /* 管理底层的LCD、WEB */
  4 static PDispOpr g_DispDevs = NULL;
  5 static PDispOpr g_DispDefault = NULL;
  6 static DispBuff g_tDispBuff;
  7 static int line_width;
  8 static int pixel_width;
  9
 10 int PutPixel(int x, int y, unsigned int dwColor)
 11 {
 12     unsigned char *pen_8 = (*unsigned char*)(g_tDispBuff.buff+y*line_width+x*pixel_width);
 13     unsigned short *pen_16;
 14     unsigned int *pen_32;
 15
 16     unsigned int red, green, blue;
 17
 18     pen_16 = (unsigned short *)pen_8;
 19     pen_32 = (unsigned int *)pen_8;
 20
 21     switch (g_tDispBuff.iBpp)
 22     {
 23         case 8:
 24         {
 25             *pen_8 = dwColor;
 26             break;
 27         }
 28         case 16:
 29         {
 30             /* 565 */
 31             red   = (dwColor >> 16) & 0xff;
 32             green = (dwColor >> 8) & 0xff;
 33             blue  = (dwColor >> 0) & 0xff;
 34             dwColor = ((red >> 3) << 11) | ((green >> 2) << 5) | (blue >> 3);
 35             *pen_16 = dwColor;
 36             break;
 37         }
 38         case 32:
 39         {
 40             *pen_32 = dwColor;
 41             break;
 42         }
 43         default:
 44         {
 45             printf("can't surport %dbpp\n", g_tDispBuff.iBpp);
 45             return -1;
 46             break;
 47         }
 48     }
 48      return 0;
 49 }
 50
 51
 52
 53 void RegisterDisplay(PDispOpr ptDispOpr)
 54 {
 55     ptDispOpr->ptNext = g_DispDevs;
 56     g_DispDevs = ptDispOpr;
 57 }
 58
 59
 60 int SelectDefaultDisplay(char *name)
 61 {
 62     PDispOpr pTmp = g_DispDevs;
 63     while (pTmp)
 64     {
 65         if (strcmp(name, pTmp->name) == 0)
 66         {
 67             g_DispDefault = pTmp;
 68             return 0;
 69         }
 70
 71         pTmp = pTmp->ptNext;
 72     }
 73
 74     return -1;
 75 }
 76
 77 int InitDefaultDisplay(void)
 78 {
 79     int ret;
 80
 81     ret = g_DispDefault->DeviceInit();
 82     if (ret)
 83     {
 84         printf("DeviceInit err\n");
 85         return -1;
 86     }
 87
 88
 89     ret = g_DispDefault->GetBuffer(&g_tDispBuff);
 90     if (ret)
 91     {
 92         printf("GetBuffer err\n");
 93         return -1;
 94     }
 95
 96     line_width  = g_tDispBuff.iXres * g_tDispBuff.iBpp/8;
 97     pixel_width = g_tDispBuff.iBpp/8;
 98
 99     return 0;
100 }
101
102
103 int FlushDisplayRegion(PRegion ptRegion, PDispBuff ptDispBuff)
104 {
105     return g_DispDefault->FlushRegion(ptRegion, ptDispBuff);
106 }
107
108
109 void DisplayInit(void)
110 {
111     void FramebufferInit(void);
112     FramebufferInit();
113 }
114
115 PDispBuff GetDisplayBuffer(void)
116 {
117    return &g_tDispBuff;
118 }

 第4行:将底层的LCD、WEB所实现的结构体放入到链表(指针)中,所以我们需要提供一个函数。void RegisterDisplay(PDispOpr ptDispOpr)

 第5行:存放找到名字的新链表

 第6行:定义一个全局变量 g_tDispBuff之后用来放第89行中GetBuffer中的(int* pxres, int * pYres, int * pBpp)

53 void RegisterDisplay(PDispOpr ptDispOpr)

  第53~57行:构造注册函数,将typedef struct DispOpr这个结构体注册到g_DispDevs链表中

        第55行:传入底层结构体指针ptDispOpr指向链表头g_DispDevs

        第56行:链表头g_DispDevs指向ptDispOpr

109 void DisplayInit(void)

第109~112行:调用底层提供的 FramebufferInit();目前我们只需要调用FramebufferInit()即可,还没有实现WEB的功能

        如果g_DispDevs链表中有好几个模块,那我们应该如何选择呢,现在我们就要设计一个模块选择函数进行模块的选择 

60 int SelectDefaultDisplay(char *name)

第60~75行:模块选择函数

        定义一个临时指针pTmp存放链表头

        while循环里根据名字name找到那一项

        找到的名字放到新链表g_DispDefault中,在第五行中有定义

        第71行,如果这个不对,这找寻下一个是否正确     

        因为上层需要通过中间的显示管理来绘制图像,坐标反馈给底层进行反应,所有需要在中间层加入绘制函数

10 int PutPixel(int x, int y, unsigned int dwColor)

第7~8行:每个像素占据多长多少像素可以先定义好,事先计算好,每一行多少字节,每个像素多少宽度,这个在InitDefaultDisplay()中已经计算好了

第10~49行:设置绘制图像函数

        函数内表示绘制的x、y坐标和绘制图像的颜色       

        第12行:g_tDispBuff.buff是写存的基地址

        第21行:g_tDispBuff.iBpp是每个像素的宽度

   

       想要在上层显示一个像素,首先需要得到一块内存,内存可以调用到底层提供的结构体,里面的g_tDispBuff这个函数,在上层得到一个新的buf,在这块buf里面绘制图像,但是g_tDispBuff不可以放到PutPixel,我们需要再定义一个函数: InitDefaultDisplay(void)

选择默认的SelectDefaultDisplay后,我们还需要初始化

 77 int InitDefaultDisplay(void)

第77~100行:

           第81行: 调用 g_DispDefault 中的DeviceInit()

           第89行: 调用 g_DispDefault  中的GetBuffer(&g_tDispBuff)

           这里我们需要定义一个新的GetBuffer结构体,把它的(int* pxres, int * pYres, int * pBpp)再次进行封装,封装结构体在disp_manager.h中的DispBuff

           第89行:将GetBuffer中的(int* pxres, int * pYres, int * pBpp)放到全局变量 g_tDispBuff

           第96行:line_width表示每一行占据多少个字节

           第97行:pixel_width表示每个像素的宽度

        当我们上层已经通过 PutPixel 已经绘制好图像,那我们就需要把它刷到硬件上,我们需要再提供一个函数FlushDisplayRegion

103 int FlushDisplayRegion(PRegion ptRegion, PDispBuff ptDispBuff)

        第105行:调用底层设备提供的FlushRegion函数

        返回取址 

114 PDispBuff GetDisplayBuffer(void)

献上韦东山老师对以上代码流程的梳理过程:

电子产品量产工具显示系统代码流程

四、测试单元

book@100ask:~/04_disp_unittest/display$ vi Makefile

1.通用Makefile

  1
  2 CROSS_COMPILE ?=
  3 AS      = $(CROSS_COMPILE)as
  4 LD      = $(CROSS_COMPILE)ld
  5 CC      = $(CROSS_COMPILE)gcc
  6 CPP     = $(CC) -E
  7 AR      = $(CROSS_COMPILE)ar
  8 NM      = $(CROSS_COMPILE)nm
  9
 10 STRIP       = $(CROSS_COMPILE)strip
 11 OBJCOPY     = $(CROSS_COMPILE)objcopy
 12 OBJDUMP     = $(CROSS_COMPILE)objdump
 13
 14 export AS LD CC CPP AR NM
 15 export STRIP OBJCOPY OBJDUMP
 16
 17 CFLAGS := -Wall -O2 -g
 18 CFLAGS += -I $(shell pwd)/include
 19
 20 LDFLAGS :=
 21
 22 export CFLAGS LDFLAGS
 23
 24 TOPDIR := $(shell pwd)
 25 export TOPDIR
 26
 27 TARGET := test
 28
 29
 30 obj-y += display/
 31 obj-y += unittest/
 32
 33 all : start_recursive_build $(TARGET)
 34     @echo $(TARGET) has been built!
 35
 36 start_recursive_build:
 37     make -C ./ -f $(TOPDIR)/Makefile.build
 38
 39 $(TARGET) : built-in.o
 40     $(CC) -o $(TARGET) built-in.o $(LDFLAGS)
 41
 42 clean:
 43     rm -f $(shell find -name "*.o")
 44     rm -f $(TARGET)
 45
 46 distclean:
 47     rm -f $(shell find -name "*.o")
 48     rm -f $(shell find -name "*.d")
 49     rm -f $(TARGET)
 50

第27行:编译出test的应用程序

第30行:指定display下的目录

第31行:指定unittest下的目录 

 2.display下的Makefile


  1 EXTRA_CFLAGS  :=
  2 CFLAGS_file.o :=
  3
  4 obj-y += disp_manager.o
  5 obj-y += framebuffer.o

3. unittest下的Makefile

  1 EXTRA_CFLAGS  :=
  2 CFLAGS_file.o :=
  3
  4 obj-y += disp_test.o

4.

#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

static const unsigned char fontdata_8x16[FONTDATAMAX] = {
    //字符编码,由于太多就不展示了
    .........
}

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();                 //调用DisplayInit()

	SelectDefaultDisplay("fb");    //选择默认的设备,传入一个名字为fd的设备

	InitDefaultDisplay();          //初始化这个默认的设备

	lcd_put_ascii(100, 100, 'A');  //在屏幕100,100的位置显示一个字母A

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

	ptBuffer = GetDisplayBuffer();
	FlushDisplayRegion(&region, ptBuffer);//将这块区域刷到这个硬件中
	
	return 0;	
}


五、上板测试:

将原有的qt程序停止

[root@100ask:~]# systemctl stop myir

最终效果:在开发板上打印出字符A

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

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

相关文章

MySQL--日志

日志 错误日志 错误日志是MySQL中最重要的日志之一&#xff0c;它记录了当mysqld启动和停止时&#xff0c;以及服务器在运行过程中发生任何严重错误时的相关信息 当数据库出现任何故障导致无法正常使用时&#xff0c;建议首先查看此日志。 该日志是默认开启的&#xff0c;默认…

Mysql 高级日志binlog、undoLog、redoLog 详解

数据更新流程与日志记录&#xff1a; undoLog&#xff1a; binLog&#xff1a; redoLog&#xff1a;

计算机毕业设计php+bootstrap小区物业管理系统

意义&#xff1a;随着我国经济的发展和人们生活水平的提高&#xff0c;住宅小区已经成为人们居住的主流&#xff0c;人们生活质量提高的同时&#xff0c;对小区物业管理的要求也越来越高&#xff0c;诸如对小区的维修维护&#xff0c;甚至对各项投诉都要求小区管理者做得好&…

INFINI Gateway 与华为鲲鹏完成产品兼容互认证

何为华为鲲鹏认证 华为鲲鹏认证是华为云围绕鲲鹏云服务&#xff08;含公有云、私有云、混合云、桌面云&#xff09;推出的一项合作伙伴计划&#xff0c;旨在为构建持续发展、合作共赢的鲲鹏生态圈&#xff0c;通过整合华为的技术、品牌资源&#xff0c;与合作伙伴共享商机和利…

SpringBoot——模板引擎及原理

优质博文&#xff1a;IT-BLOG-CN 一、模板引擎的思想 模板是为了将显示与数据分离&#xff0c;模板技术多种多样&#xff0c;但其本质都是将模板文件和数据通过模板引擎生成最终的HTML代码。 二、SpringBoot模板引擎 SpringBoot推荐的模板引擎是Thymeleaf语法简单&#xff0…

堆排序(详解)

在上篇文章中&#xff0c;我们说利用堆的插入和删除也可以排序数据&#xff0c;但排序的只是堆里面的数组&#xff1b;同时每次排序数据都要单独写一个堆的实现&#xff0c;很不方便&#xff0c;这次就来着重讲讲如何使用堆排序。 1.建堆 给了你数据&#xff0c;要利用堆对数据…

MIGO收货报替代“ZF002“, 步骤““ 中存在语法错误消息号 GB032错误

MIGO收货报替代"ZF002", 步骤"" 中存在语法错误消息号 GB032错误。替代"ZF002", 步骤"" 中存在语法错误消息号 GB032诊断 在 ABAP 代码生成过程中&#xff0c;在替代ZF002中发现了语法错误。 系统响应 未为该布尔陈述生成 ABAP 代码&…

nodejs之express学习(1)

安装 npm i express使用 // 导入 const express require(express) // 创建应用 const app express() // 创建路由 app.get(/home,(req,res)>{res.end("hello express") }) app.listen(3000,()>{console.log("服务已启动~") })路由的介绍 什么是…

P9231 [蓝桥杯 2023 省 A] 平方差(拆分问题)

分析&#xff1a;x(yz)*(y-z); yz 与 y-z 同奇偶性&#xff08;x要么为奇数&#xff0c;要么为偶数&#xff09; 奇数&#xff1a;1 与 其本身 乘积 偶数&#xff1a;2 与 x/2 乘积(为4的倍数) #include<bit…

【shell】多行重定向与免交互expect与ssh、scp的结合使用

目录 一、多行重定向 举例1&#xff1a;使用read命令接收用户的输入值会有交互过程 举例2&#xff1a;设置变量的值 举例3&#xff1a;创建用户密码 举例4&#xff1a;使用多行重定向写入文件中&#xff08;以repo文件举例&#xff09; 举例5&#xff1a;变量设定 二、免…

C/C++ 发送与接收HTTP/S请求

HTTP&#xff08;Hypertext Transfer Protocol&#xff09;是一种用于传输超文本的协议。它是一种无状态的、应用层的协议&#xff0c;用于在计算机之间传输超文本文档&#xff0c;通常在 Web 浏览器和 Web 服务器之间进行数据通信。HTTP 是由互联网工程任务组&#xff08;IETF…

java编程强化练习(一)

1. 素数因子数字和 【问题描述】从键盘终端输入一个正的整数&#xff0c;求其所有素数因子各位上数字之和。例如&#xff1a;442*2*11&#xff0c;素数因子为2&#xff0c;2&#xff0c;11&#xff0c;和为22114 【输入形式】一个正的整数 【输出形式】整数的所有素数因子各位…

用通俗的方式讲解Transformer:从Word2Vec、Seq2Seq逐步理解到GPT、BERT

直到今天早上&#xff0c;刷到CSDN一篇讲BERT的文章&#xff0c;号称一文读懂&#xff0c;我读下来之后&#xff0c;假定我是初学者&#xff0c;读不懂。 关于BERT的笔记&#xff0c;其实一两年前就想写了&#xff0c;迟迟没动笔的原因是国内外已经有很多不错的资料&#xff0…

C语言基础程序设计题

1.个人所得税计算 应纳税款的计算公式如下&#xff1a;收入<&#xff1d;1000元部分税率为0&#xff05;&#xff0c;2000元>&#xff1d;收入>1000元的部分税率为5&#xff05;&#xff0c;3000元>&#xff1d;收入>2000元的部分税率为10&#xff05;&#xf…

【C语言加油站】函数栈帧的创建与销毁 #保姆级讲解

函数栈帧的创建与销毁 导言一、计算机硬件1.冯•诺依曼机基本思想2.冯•诺依曼机的特点&#xff1a;3.存储器3.1 分类3.2 内存的工作方式3.3 内存的组成 4.寄存器4.1 基本含义4.2 寄存器的功能4.3 工作原理4.4 分类4.4.1 通用寄存器组AX(AH、AL)&#xff1a;累加器BX(BH、BL)&a…

Opencv-C++笔记 (19) : 分水岭图像分割

文章目录 一、基于距离变换与分水岭的图像分割1、图像分割2、距离和变换与分水岭距离变换常见算法有两种分水岭变换常见的算法 3、距离变换API函数接口4、watershed 分水岭函数API接口步骤 5、代码 一、基于距离变换与分水岭的图像分割 1、图像分割 图像分割(Image Segmentat…

大坝安全监测的内容及作用

大坝安全监测是指对大坝水雨情沉降、倾斜、渗压以及大坝形状特征有效地进行监测&#xff0c;及时发现潜在的安全隐患和异常情况&#xff0c;以便大坝管理人员能够做出科学决策&#xff0c;以确保大坝安全稳定运行。 大坝安全监测的主要内容 1.表面位移监测&#xff1a;监测大坝…

Python基础:推导式(Comprehensions)详解

1. 推导式概念 Python推导式&#xff08;comprehensions&#xff09;是一种简洁而强大的语法&#xff0c;用于从已存在的数据&#xff08;列表、元组、集合、字典等&#xff09;中创建新的数据结构。推导式包括&#xff1a; 列表推导式元组推导式字典推导式集合推导式 2. 列表…

鸿蒙原生应用/元服务开发-AGC分发如何生成密钥和和证书请求文件

HarmonyOS通过数字证书&#xff08;.cer文件&#xff09;和Profile文件&#xff08;.p7b文件&#xff09;等签名信息来保证应用的完整性&#xff0c;应用如需上架到华为应用市场必须通过签名校验。因此&#xff0c;开发者需要使用发布证书和Profile文件对应用进行签名后才能发布…