IMX6ULL开发板基础实验:Framebuffer驱动程序的简单应用实例代码详细分析

news2024/12/16 15:38:32

前言

这个代码之所以可以写得这么短,写得这么方便,原因在于LCD的驱动程序已经写好了,并且这个驱动程序符号Framebuffer的标准,这才使得我们在实现上层应用时变得很方便。

源代码:

#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>

static int fd_fb;
static struct fb_var_screeninfo var;	/* Current var */
static int screen_size;
static unsigned char *fb_base;
static unsigned int line_width;
static unsigned int pixel_width;

/**********************************************************************
 * 函数名称: lcd_put_pixel
 * 功能描述: 在LCD指定位置上输出指定颜色(描点)
 * 输入参数: x坐标,y坐标,颜色
 * 输出参数: 无
 * 返 回 值: 会
 * 修改日期        版本号     修改人	      修改内容
 * -----------------------------------------------
 * 2020/05/12	     V1.0	  zh(angenao)	      创建
 ***********************************************************************/ 
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;	
}

需要的一堆头文件

问:能不能介绍下基于IMUX6LL的Linux开发中用到的以下头文件各自的作用?

#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>

在基于 i.MX6ULL 的 Linux 开发中,上述头文件的作用如下。它们涵盖了文件操作、内存映射、硬件控制等功能,是嵌入式开发中的常见组合。


1. <sys/mman.h>

  • 作用:提供内存映射相关的接口。
  • 主要功能
    • 文件或设备映射到内存(mmap)。
    • 解除映射(munmap)。
    • 修改映射区域的权限(mprotect)。
    • 用于文件 I/O 优化和硬件寄存器的直接操作。
  • 典型用法
    • /dev/fb0(Frame Buffer)映射到用户空间内存以直接操作显示设备。
    • 操作内存共享或匿名内存。

在本实验的代码中,下面这句代码要用到这个头文件:

fb_base = (unsigned char *)mmap(NULL , screen_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd_fb, 0);

2. <sys/types.h>

  • 作用:定义常用的系统数据类型。
  • 主要功能
    • 包含了基本的类型定义,比如 size_t, pid_t, off_t, ssize_t
    • 提供类型支持给许多标准函数接口,例如文件操作和进程管理。

3. <sys/stat.h>

  • 作用:用于获取文件的属性信息。
  • 主要功能
    • 提供函数 statfstat,获取文件的元信息(文件大小、权限、类型等)。
    • 定义了文件权限和类型的宏(如 S_IFREG, S_IFDIR)。
  • 典型用法
    • 检测文件是否存在。
    • 获取文件的大小以用于内存映射或文件操作。

4. <unistd.h>

  • 作用:定义 POSIX 系统调用接口。
  • 主要功能
    • 文件操作函数:read, write, close, lseek
    • 文件描述符操作:dup, dup2
    • 进程控制:fork, _exit, exec 系列函数。
    • 获取系统信息:getpid, getppid, getuid
  • 典型用法
    • 用于标准输入输出操作,例如从设备文件中读取数据。
    • 控制子进程的执行流程。

5. <linux/fb.h>

  • 作用:用于操作 Frame Buffer(帧缓冲设备)的接口定义。
  • 主要功能
    • 提供帧缓冲设备的结构体和常量定义,例如 struct fb_var_screeninfo, struct fb_fix_screeninfo
    • 定义 IOCTL 命令,如 FBIOGET_VSCREENINFOFBIOPUT_VSCREENINFO,用于获取或设置屏幕参数。
  • 典型用法
    • 获取屏幕分辨率、颜色深度等信息。
    • 直接操作屏幕的帧缓冲数据以绘制图形。

6. <fcntl.h>

  • 作用:定义文件控制相关接口。
  • 主要功能
    • 提供 openfcntl 函数,用于打开文件和控制文件描述符。
    • 定义文件访问模式和标志,如 O_RDONLY, O_WRONLY, O_RDWR, O_CREAT, O_TRUNC
  • 典型用法
    • 打开设备文件(如 /dev/fb0, /dev/mem)。
    • 控制文件的非阻塞操作或文件锁。

后面的代码中,代码:

fd_fb = open("/dev/fb0", O_RDWR);

就会用到这个头文件的声明。


7. <stdio.h>

  • 作用:提供标准输入输出功能。
  • 主要功能
    • 格式化输入输出:printf, scanf, fgets, sprintf
    • 文件流操作:fopen, fclose, fwrite, fread
    • 错误处理:perror
  • 典型用法
    • 打印调试信息。
    • 从标准输入读取配置数据。

8. <string.h>

  • 作用:提供字符串和内存操作函数。
  • 主要功能
    • 字符串操作:strlen, strcmp, strcpy, strcat
    • 内存操作:memset, memcpy, memcmp, memmove
  • 典型用法
    • 初始化或比较内存数据块。
    • 操作字符串,用于解析命令行参数或处理文件名。

9. <sys/ioctl.h>

  • 作用:提供设备 I/O 控制接口。
  • 主要功能
    • 定义 ioctl 函数,用于通过文件描述符控制设备。
    • linux/fb.h 搭配使用,通过 IOCTL 命令对帧缓冲设备进行控制。
  • 典型用法
    • 调用 ioctl(fd, FBIOGET_VSCREENINFO, &var_info) 获取帧缓冲设备信息。
    • 用于控制串口、网络设备、音频设备等硬件。

综合示例:Frame Buffer 操作

以下示例展示了如何使用这些头文件进行基本的帧缓冲操作:

#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>

int main() {
    int fb_fd = open("/dev/fb0", O_RDWR);
    if (fb_fd == -1) {
        perror("Error opening framebuffer device");
        return 1;
    }

    // 获取固定屏幕信息
    struct fb_fix_screeninfo fix_info;
    if (ioctl(fb_fd, FBIOGET_FSCREENINFO, &fix_info) == -1) {
        perror("Error reading fixed information");
        close(fb_fd);
        return 1;
    }

    // 获取可变屏幕信息
    struct fb_var_screeninfo var_info;
    if (ioctl(fb_fd, FBIOGET_VSCREENINFO, &var_info) == -1) {
        perror("Error reading variable information");
        close(fb_fd);
        return 1;
    }

    printf("Resolution: %dx%d, Bits Per Pixel: %d\n",
           var_info.xres, var_info.yres, var_info.bits_per_pixel);

    // 映射帧缓冲到内存
    size_t screensize = var_info.yres_virtual * fix_info.line_length;
    char *fb_data = mmap(NULL, screensize, PROT_READ | PROT_WRITE, MAP_SHARED, fb_fd, 0);
    if (fb_data == MAP_FAILED) {
        perror("Error mapping framebuffer device to memory");
        close(fb_fd);
        return 1;
    }

    // 简单绘制:清屏为黑色
    memset(fb_data, 0, screensize);

    // 解除映射并关闭设备
    munmap(fb_data, screensize);
    close(fb_fd);

    return 0;
}

运行流程

  1. 打开 /dev/fb0
  2. 通过 ioctl 获取帧缓冲信息。
  3. 使用 mmap 将帧缓冲设备映射到内存。
  4. 清屏操作后解除映射并关闭文件。

这些头文件组合使用,为嵌入式开发提供强大的接口支持,适用于设备文件操作、内存映射、硬件交互等场景。

main函数的第一个参数 argc的作用

问:基于IMUX6LL的Linux开发中的main函数的输入参数的代码如下:

int main(int argc, char **argv)

请问第一个参数argc有什么作用?
答:
在 Linux 开发中,main 函数的第一个参数 argc 的作用是 表示传递给程序的命令行参数的个数


详细解释

  1. 参数含义

    • argc 是 “Argument Count” 的缩写。
    • 它的值为程序执行时传递的命令行参数的数量,包括程序本身的名字。
  2. 值的范围

    • argc 的值至少为 1,因为程序的名称(argv[0])始终会作为第一个参数被传递。
  3. 典型的命令行输入

    • 如果执行以下命令:
      ./my_program arg1 arg2 arg3
      
      • argc 的值为 4。
      • 对应的 argv 内容:
        • argv[0] = "./my_program" (程序名)。
        • argv[1] = "arg1"
        • argv[2] = "arg2"
        • argv[3] = "arg3"

代码fd_fb = open("/dev/fb0", O_RDWR);的作用

问:
基于IMUX6LL的Linux开发中下面这句代码请详细解释一下:

fd_fb = open("/dev/fb0", O_RDWR);

要想理解这句代码,首先要理解文件操作基本函数中的open函数,关于open函数的详细介绍,见我的另一篇博文 https://blog.csdn.net/wenhao_ir/article/details/144488241

open函数理解后,我们再来理解参数"/dev/fb0"

  • 在Linux 系统中,所有硬件设备都被抽象为文件,通常存放在 /dev 目录下。
    /dev/fb0:表示帧缓冲(Framebuffer)设备的第一个实例(0)。
  • 帧缓冲设备用于直接访问显存,支持直接绘图或更新显示内容。
  • 在 i.MX6ULL 中的含义: 该设备文件通常由 Linux 内核的 Framebuffer 驱动程序提供。 对应显卡或 LCD 控制器的帧缓冲区。

问:
在实际的程序编写中,我们怎么知道我们要打开的设备是fb0还是fb1或是fb2呢?即我们怎么知道我们要操作的帧缓冲设备是第几个实例呢?
详细的答案见我的另一篇博文 https://blog.csdn.net/wenhao_ir/article/details/144488919

代码ioctl(fd_fb, FBIOGET_VSCREENINFO, &var

解释下面这段代码的作用:

	if (ioctl(fd_fb, FBIOGET_VSCREENINFO, &var))
	{
		printf("can't get var\n");
		return -1;
	}

这段代码涉及到的是与Linux帧缓冲(framebuffer)设备交互的操作,尤其是在嵌入式系统中通过/dev/fb0设备与显示屏进行通信。让我们逐行解释这段代码:

if (ioctl(fd_fb, FBIOGET_VSCREENINFO, &var))
{
    printf("can't get var\n");
    return -1;
}

ioctl 函数

ioctl 是一个系统调用,用于向设备发送控制命令或请求设备特定的操作。ioctl 是 “Input/Output Control” 的缩写,它可以与各种设备进行交互,比如网络设备、文件系统、显卡等。

函数的原型是:

int ioctl(int fd, unsigned long request, ...);
  • fd 是文件描述符,通常由 open() 系统调用返回,表示一个打开的设备。
  • request 是设备特定的命令,告诉驱动程序要执行什么操作。
  • ... 是传递给设备控制命令的参数,具体依赖于设备。

参数解释

  1. fd_fb

    • fd_fb 是通过 open("/dev/fb0", O_RDWR) 打开的帧缓冲设备文件的文件描述符。它代表了与 /dev/fb0 设备的连接,允许程序对设备进行读写操作。
  2. FBIOGET_VSCREENINFO

    • 这是一个控制命令,通常用于获取显示屏的基本信息,如屏幕的分辨率、颜色深度、显示模式等。
    • FBIOGET_VSCREENINFO 是一个宏定义,表示查询显示设备的详细信息。它会填充一个 fb_var_screeninfo 结构体(通常是 var 变量)来描述显示屏的各种参数。
  3. &var

    • 这是 fb_var_screeninfo 结构体的指针,ioctl 调用会通过此结构体返回获取到的显示设备信息。
    • var 结构体包含屏幕的具体设置,比如分辨率、颜色深度、刷新的频率等。

解释 if 语句

if (ioctl(fd_fb, FBIOGET_VSCREENINFO, &var))
{
    printf("can't get var\n");
    return -1;
}
  • ioctl(fd_fb, FBIOGET_VSCREENINFO, &var) 调用返回一个整数值。若返回值非零,则表示执行失败。
  • ioctl 失败的原因可能是设备不可用、权限不足,或者其他硬件相关问题。
  • 如果 ioctl 返回非零值,程序会打印 “can’t get var” 的错误信息,并返回 -1 表示出错。

总结

这段代码的目的是通过 ioctl 获取 /dev/fb0 帧缓冲设备的显示信息。如果获取失败,程序会输出错误信息并终止执行。

代码line_width = var.xres * var.bits_per_pixel / 8;

这行代码的目的是计算 每一行的字节宽度(line width),即每行显示所需要的内存空间。

让我们逐行详细解释它:

line_width  = var.xres * var.bits_per_pixel / 8;

解释各个变量

  • var.xres:这是一个存储屏幕水平分辨率的变量。xres 表示显示设备的水平像素数(即屏幕宽度上的像素数)。

    例如,假设屏幕的分辨率是 1920x1080,那么 var.xres 的值就是 1920。

  • var.bits_per_pixel:这是一个存储每个像素占用的比特数的变量。bits_per_pixel 表示屏幕上每个像素的色彩深度,通常为 16、24 或 32 位。

    • 如果屏幕的颜色深度是 24 位(即每个像素由 3 字节组成),那么 var.bits_per_pixel 的值为 24。
    • 如果屏幕的颜色深度是 32 位(即每个像素由 4 字节组成),那么 var.bits_per_pixel 的值为 32。
  • / 8:这表示将比特(bit)转换为字节(byte)。因为每个字节是 8 位(bit),所以在计算像素的宽度时,必须将每个像素的比特数除以 8 来得到它的字节数。

代码的功能

line_width  = var.xres * var.bits_per_pixel / 8;

这行代码的目的是计算 每一行的字节宽度(line width),即每行显示所需要的内存空间。

计算步骤:
  1. var.xres 给出了每行的像素数。
  2. var.bits_per_pixel 给出了每个像素的比特数,表示一个像素所占的内存大小。
  3. 通过将每个像素的比特数除以 8,转换为字节单位。
  4. 将每行的像素数乘以每个像素占用的字节数,得到一行所需的内存大小(以字节为单位)。
例子:

假设:

  • var.xres = 1920(即屏幕的分辨率是 1920 像素宽)
  • var.bits_per_pixel = 32(每个像素占 32 比特,即 4 字节)

那么,每一行的字节宽度

line_width  = 1920 * 32 / 8 = 1920 * 4 = 7680 字节。

这意味着每一行的像素数据占用 7680 字节的内存空间。

总结

这行代码计算了每一行屏幕图像数据的内存占用大小,以字节为单位。它是处理图像数据时非常重要的一个参数,通常用于确定如何在内存中访问和处理每行的像素数据。

代码pixel_width = var.bits_per_pixel / 8;

代码 pixel_width = var.bits_per_pixel / 8; 的作用是计算 每个像素的字节宽度,即每个像素占用的内存空间,单位是字节(byte)。具体的解释如下:

变量解释:

  • var.bits_per_pixel:每个像素的比特数。它表示显示屏上每个像素的颜色深度,通常是 16 位、24 位、32 位等。例如,如果每个像素使用 32 位表示,则 var.bits_per_pixel 为 32。

计算:

  • / 8:这个操作将比特转换为字节,因为 1 字节(byte) = 8 比特(bit)。所以通过除以 8,var.bits_per_pixel 就从比特转换为字节,表示每个像素所占的内存字节数。

示例:

假设:

  • var.bits_per_pixel = 32(每个像素使用 32 位来表示,即 4 字节)

那么:

pixel_width = var.bits_per_pixel / 8 = 32 / 8 = 4 字节

这意味着每个像素需要 4 字节的内存空间。

作用:

pixel_width 变量保存了每个像素的字节数,它可以用于后续的内存操作,如计算图像的内存总大小、访问特定像素的位置等。每个像素占用的字节数在图像数据处理中是一个非常重要的参数,尤其是在涉及像素数据的读写、图像处理和缓冲区管理时。

代码fb_base = (unsigned char *)mmap(NULL , screen_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd_fb, 0);

这行代码的作用是将 /dev/fb0 设备的内存映射到进程的虚拟内存空间。通过这种方式,你可以直接访问Framebuffer的内存,并对其进行操作(例如清屏、绘制像素等),而不需要显式的读写操作。接下来,你可以通过 fb_base 指针来访问和修改Framebuffer内容。
详细介绍见:
https://blog.csdn.net/wenhao_ir/article/details/144489705

代码if (fb_base == (unsigned char *)-1)

	if (fb_base == (unsigned char *)-1)
	{
		printf("can't mmap\n");
		return -1;
	}

这段代码:

if (fb_base == (unsigned char *)-1)
{
    printf("can't mmap\n");
    return -1;
}

是用于检查 mmap() 调用是否成功的错误处理代码。

解释过程:

  1. mmap() 函数调用:
    之前的代码段中,调用了 mmap() 来将 framebuffer 设备(即 /dev/fb0)映射到进程的虚拟内存中:

    fb_base = (unsigned char *)mmap(NULL , screen_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd_fb, 0);
    

    mmap() 的返回值是映射的内存区域的起始地址。如果映射成功,它会返回映射区域的地址(一个指针)。如果映射失败,它会返回 (void *)-1,表示映射失败。

  2. fb_base == (unsigned char *)-1

    • mmap() 如果失败,返回值为 (void *)-1。但是,在 C 语言中,(void *)-1 会被强制转换为 (unsigned char *) 类型,因此判断条件是 fb_base == (unsigned char *)-1
    • 这是在检查 mmap() 是否失败。如果 fb_base 的值等于 (unsigned char *)-1,则说明映射失败。
  3. 错误处理:

    • 如果 mmap() 返回 (void *)-1,代码进入这个 if 语句块,打印错误信息 "can't mmap",表示内存映射失败。
    • 然后,return -1; 会结束 main() 函数并返回 -1,表示程序执行失败,无法继续进行后续操作。

总结:

这段代码的作用是检查 mmap() 是否成功。如果返回值是 (void *)-1,说明内存映射失败,那么程序会打印错误信息并返回错误代码 -1,表示程序无法继续执行。如果 mmap() 成功,fb_base 将包含映射的内存区域的地址,程序可以继续执行后续操作。

代码unsigned char *pen_8 = fb_base+y*line_width+x*pixel_width;

这句代码是算出某个像素点的内存偏移量,(x, y)这个坐标显然是从0开始的,而不是从1开始的。

代码pen_16 = (unsigned short *)pen_8;

这行代码:

pen_16 = (unsigned short *)pen_8;

的作用是将指针 pen_8 转换为 unsigned short * 类型的指针,并将其赋值给 pen_16。为了更好地理解其含义,我们需要分析以下几点:

  1. pen_8 是一个 unsigned char * 类型的指针
    在函数 lcd_put_pixel 中,pen_8 是指向某个像素位置的指针,类型为 unsigned char *。它表示的是一个字节大小的内存地址,也就是 1 个字节的地址。

    unsigned char *pen_8 = fb_base + y * line_width + x * pixel_width;
    

    其中,fb_base 是指向显存的基地址(内存映射的起始地址),y * line_width 是该行的偏移量,x * pixel_width 是该列的偏移量。通过加和计算,pen_8 指向了 (x, y) 坐标对应的像素位置。

  2. pen_16 是一个 unsigned short * 类型的指针
    pen_16 是一个指向 unsigned short 类型的指针,也就是说每次操作时,它会以 2 字节为单位访问内存(unsigned short 占 2 个字节)。在这个上下文中,unsigned short 通常用来表示 16 位颜色信息(比如 RGB565 格式,其中每个像素用 2 字节表示)。

    unsigned short *pen_16;
    
  3. 类型转换:
    通过这行代码,将 pen_8unsigned char *)转换为 unsigned short *pen_16)。这种转换的意义在于,你希望以 unsigned short 类型访问内存,并对内存进行 16 位(2 字节)操作。

    为什么要做这个转换呢?因为显示屏上不同的颜色模式会使用不同的位深度。如果当前的屏幕颜色深度是 16 位(即每个像素使用 2 个字节),则你需要以 2 字节为单位来访问该位置的内存,而不是 1 字节。因此,pen_16 是为访问 16 位颜色(通常是 RGB565 格式)而存在的。

  4. 为什么需要转换:
    pen_8 指向的是一个字节(8 位)的内存地址,如果直接操作它,会按字节进行处理。但对于 16 位的显示模式,你需要按 16 位(2 字节)来存储颜色值。通过将 pen_8 转换成 pen_16,你可以以 16 位为单位来读写内存,从而确保 16 位颜色值能够正确存储。

总结一下,这行代码的作用是将一个字节指针 pen_8 转换为一个短整型指针 pen_16,以便后续能够按 16 位操作内存。这在处理不同位深度的显示模式时是必要的,因为每个像素所占的内存大小不同。

上机实验

首先交叉编译源码,按照博文 Ubuntu中安装配置交叉编译工具并进行测试 中第04部分的方法进行交叉编译。

在 /home/book/mycode 目录中建立目录C0002_show_pixel,并进入:

cd /home/book/mycode
mkdir C0002_show_pixel
cd /home/book/mycode/C0002_show_pixel

然后把文件:show_pixel.c 复制到目录mycode中,这个代码的百度网盘下载地址:
https://pan.baidu.com/s/1Oq5FpAs1RMdVxoyvSZ1olg?pwd=wugb
执行下面的命令生成可执行文件:

arm-buildroot-linux-gnueabihf-gcc -o show_pixel show_pixel.c

在这里插入图片描述
然后再参考博文 IMX6ULL开发板挂载 Ubuntu 的 NFS 目录,并以交叉编译得到的hello程序进行测试 把生成的程序在开发板上进行测试

在这里插入图片描述

cd mycode
cp /mnt/show_pixel ./show_pixel

添加执行权限

chmod +x show_pixel

执行程序:

./show_pixel

执行程序前的屏幕:
在这里插入图片描述
执行程序后的屏幕:
在这里插入图片描述
可见中间划了一道红线。

总结

这个代码之所以可以写得这么短,写得这么方便,原因在于LCD的驱动程序已经写好了,并且这个驱动程序符号Framebuffer的标准,这才使得我们在实现上层应用时变得很方便。

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

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

相关文章

Jenkins:持续集成与持续部署的利器

&#x1f407;明明跟你说过&#xff1a;个人主页 &#x1f3c5;个人专栏&#xff1a;《未来已来&#xff1a;云原生之旅》&#x1f3c5; &#x1f516;行路有良友&#xff0c;便是天堂&#x1f516; 目录 一、引言 1、什么是Jenkins 2、Jenkins的起源 二、Jenkins的核心…

C语言基础14(动态内存控制后续)

文章目录 野指针、空指针、空悬指针野指针空指针空悬指针 void与void*的区别内存操作常用内存操作函数内存填充内存拷贝内存比较内存查找 野指针、空指针、空悬指针 野指针 定义&#xff1a;指向一块未知区域(已经销毁或者访问受限的内存区域外的已存在或不存在的内存区域)&a…

CSS在线格式化 - 加菲工具

CSS在线格式化 打开网站 加菲工具 选择“CSS在线格式化” 或者直接访问 https://www.orcc.online/tools/css 输入CSS代码&#xff0c;点击左上角的“格式化”按钮 得到格式化后的结果

分布式事物XA、BASE、TCC、SAGA、AT

分布式事务——Seata 一、Seata的架构&#xff1a; 1、什么是Seata&#xff1a; 它是一款分布式事务解决方案。官网查看&#xff1a;Seata 2.执行过程 在分布式事务中&#xff0c;会有一个入口方法去调用各个微服务&#xff0c;每一个微服务都有一个分支事务&#xff0c;因…

Serdes技术与Xilinx GT概览

目录 一、前言 二、Serdes技术 2.1 芯片间信号传输 2.2 Serdes技术 三、 Xilinx GT 3.1 7系列器件GT 3.2 Ultrascale GT 3.3 Ultrascale GT 四、参考资料 一、前言 对于芯片间高速信号传输技术&#xff0c;不得不提serdes以及在Xilinx在此基础上的高速收发器GT系列&…

HarmonyOS Next 元服务新建到上架全流程

HarmonyOS Next 元服务新建到上架全流程 接上篇 这篇文章的主要目的是介绍元服务从新建到上家的完整流程 在AGC平台上新建一个项目 链接 一个项目可以多个应用 AGC新建一个元服务应用 新建一个本地元服务项目 如果成功在AGC平台上新建过元服务&#xff0c;那么这里会自动显…

【Spark】Spark的两种核心Shuffle工作原理详解

如果觉得这篇文章对您有帮助&#xff0c;别忘了点赞、分享或关注哦&#xff01;您的一点小小支持&#xff0c;不仅能帮助更多人找到有价值的内容&#xff0c;还能鼓励我持续分享更多精彩的技术文章。感谢您的支持&#xff0c;让我们一起在技术的世界中不断进步&#xff01; Sp…

【CSS in Depth 2 精译_079】第 13 章:渐变、阴影与混合模式概述 + 13.1:CSS 渐变效果(一)——使用多个颜色节点

当前内容所在位置&#xff08;可进入专栏查看其他译好的章节内容&#xff09; 第四部分 视觉增强技术 ✔️【第 13 章 渐变、阴影与混合模式】 ✔️ 13.1 渐变 ✔️ 13.1.1 使用多个颜色节点&#xff08;一&#xff09; ✔️13.1.2 颜色插值13.1.3 径向渐变13.1.4 锥形渐变 文…

Linux 中的 mkdir 命令:深入解析

在 Linux 系统中&#xff0c;mkdir 命令用于创建目录。它是文件系统管理中最基础的命令之一&#xff0c;广泛应用于日常操作和系统管理中。本文将深入探讨 mkdir 命令的功能、使用场景、高级技巧&#xff0c;并结合 GNU Coreutils 的源码进行详细分析。 1. mkdir 命令的基本用法…

mp4影像和m4a音频无损合成视频方法

第一步&#xff1a;复制高清视频地址 url 第二步:打开网址粘贴复制的视频url视频下载 第三步&#xff1a;下载-影像.mp4和-音频.m4a 第四步&#xff1a;合并视频&#xff1b; 使用ffmpeg进行无损合成&#xff08;如果没有安装ffmpeg请自行下载安装下载 FFmpeg (p2hp.com)&…

Leonardo.Ai丨一键生成图片(AI绘图)

随着人工智能技术的迅速发展,AI在各个领域的应用越来越广泛,特别是在图像生成方面。AI艺术创作的崛起,不仅让艺术创作变得更加便捷和创新,也为设计师、艺术家及普通用户提供了全新的工具。Leonardo.Ai作为一款基于人工智能的图像生成工具,通过简洁的操作和强大的功能,成功…

简单的Java小项目

学生选课系统 在控制台输入输出信息&#xff1a; 在eclipse上面的超级简单文件结构&#xff1a; Main.java package experiment_4;import java.util.*; import java.io.*;public class Main {public static List<Course> courseList new ArrayList<>();publi…

Android实现RecyclerView边缘渐变效果

Android实现RecyclerView边缘渐变效果 1.前言&#xff1a; 是指在RecyclerView中实现淡入淡出效果的边缘效果。通过这种效果&#xff0c;可以使RecyclerView的边缘在滚动时逐渐淡出或淡入&#xff0c;以提升用户体验。 2.Recyclerview属性&#xff1a; 2.1、requiresFading…

Avalonia的Ribbon

将以前Avalonia项目中的Ribbon单独隔离&#xff0c;提交到了github,方便大家查看修改。 Ribbon做成了组件&#xff0c;但是想要界面效果&#xff0c;还得结合窗体功能开发。 项目地址&#xff1a; jinyuttt/AvaloniaRibbonUI: AvaloniaRibbon component

Vue04

目录 一、学习目标 1.组件的三大组成部分&#xff08;结构/样式/逻辑&#xff09; 2.组件通信 3.综合案例&#xff1a;小黑记事本&#xff08;组件版&#xff09; 4.进阶语法 二、scoped解决样式冲突 1.默认情况&#xff1a; 三、data必须是一个函数 1、data为什么要写…

C# 探险之旅:第十八节 - 元组(Tuple):神奇的背包与丢弃的艺术,还有变身大法!

嘿&#xff0c;探险家们&#xff01;欢迎再次踏上C#的奇妙旅程。今天&#xff0c;我们要聊的是一个非常实用又有点懒散的旅行伴侣——元组&#xff08;Tuple&#xff09;。想象一下&#xff0c;你正准备来一场说走就走的旅行&#xff0c;但是不想带太多行李&#xff0c;只想简单…

SAP软件如何启用反记账功能

SAP软件和国内ERP软件不一样&#xff0c;它在录入会计凭证时是不可以录入负数的&#xff08;即红冲凭证&#xff09;&#xff0c;因此无法直接实现传统意义上的红字冲销。 比如&#xff0c;如下SAP正常和冲销业务产生会计凭证如下&#xff1a; 正常的业务凭证&#xff1a; 借…

若依-帝可得app后端

视频地址 https://www.bilibili.com/video/BV1pf421B71v?t=510.1 APP后端技术栈 架构解析 验证码功能 开发环境使用改的是固定的验证码 12345正式环境使用的是 阿里云的短信方案@Override public void sendSms(String mobile) {// String code = RandomUtil.randomNumbers(5);…

金融分析-Transformer模型(基础理论)

Transformer模型 1.基本原理 transformer的core是注意力机制&#xff0c;其本质就是编码器-解码器。他可以通过多个编码器进行编码&#xff0c;再把编码完的结果输出给解码器进行解码&#xff0c;然后得到最终的output。 1.1编码器 数据在编码器中会经过一个self-attention的…

JS-手写new

我们先再来理一理原型 Object1 {name:deng,age:18 } Object2 {name:ru,age:18 } const Person function(){} Person.prototype Object1; const p1 new Person(); console.log(p1.name); //deng Person.prototype null; console.log(p1.name); //deng上面给Person的构造函…