iomuxc、pinctrl子系统、gpio子系统(学习总结)

iomuxc、pinctrl子系统、gpio子系统三者的关系

  1. 相互依赖:IOMUXC、pinctrl子系统和gpio子系统在功能上相互依赖。IOMUXC提供了引脚复用和电气属性的配置能力,pinctrl子系统负责从设备树中获取这些配置信息并完成初始化,而gpio子系统则在引脚被配置为GPIO功能时提供具体的操作接口。

  2. 分层结构:从系统架构的角度来看,这三者构成了一个分层的结构。IOMUXC位于最底层,提供硬件级别的引脚复用和电气属性配置;pinctrl子系统位于中间层,负责软件层面的引脚配置和初始化;gpio子系统则位于最上层,为开发者提供易于使用的GPIO操作接口。

  3. 协同工作:在实际应用中,这三者协同工作以实现引脚的有效管理和控制。例如,在配置一个LED灯的GPIO引脚时,首先需要通过IOMUXC将该引脚复用为GPIO功能,然后通过pinctrl子系统从设备树中获取该引脚的配置信息并完成初始化,最后通过gpio子系统提供的API接口来设置引脚的方向和输出值以控制LED灯的亮灭。

IOMUXC

一、IOMUXC的基本概念

  • 概念引入:为了推出功能丰富的核心板,SOC厂商引入了引脚复用-IOMUXC架构。这种架构通过输入输出多路复用器(Input/Output Multiplexer),使得每个引脚最多可复用好几种功能,每个功能又可以出现在不同的引脚上。
  • 核心功能:IOMUXC的核心功能是IO口复用,即利用有限的IO口资源,通过动态切换,满足多个内部外设的IO需求。

二、IOMUXC的架构与组成

  • 基本单元:IOMUX由一些基本的iomux_cell单元组成,每个基本IOMUX单元只处理一个pad复用信号。
  • 子块组成:IOMUXC通常由两个子块组成:IOMUXC_REGISTERS(包含所有IOMUXC寄存器)和IOMUXC_LOGIC(包含所有IOMUXC组合逻辑,如IP接口控制、地址解码器、可观察复用控制)。
  • 寄存器分类:在IOMUXC控制器中,寄存器主要分为三大类:IOMUXC_SW_PAD_CTRL_X(管脚控制寄存器)、IOMUXC_SW_MUX_CTL_PAD_X(输出路由寄存器)、IOMUXC_X_SELECT_INPUT(输入路由寄存器)。

三、IOMUXC的配置与使用

  • 配置方式:IOMUXC的配置通常涉及对控制器中的寄存器进行参数设置。这些参数包括控制寄存器的偏移地址、MUX控制寄存器的偏移地址、MUX模式、输入路由寄存器的偏移地址以及Daisy Chain模式等。
  • Linux内核配置:在Linux内核中,SOC厂商会把各功能引脚的配置参数值写到相应的宏定义头文件中(如xxx-pinfunc.h),用户可以根据芯片使用手册中的说明,在设备树(dtb)中添加或修改引脚定义。
  • 功能切换:IOMUXC只起了一个功能切换的作用,引脚配置完成后,还需要配置具体功能的控制器里寄存器参数,这样才能共同完成引脚的功能确定。

四、IOMUXC的应用场景

  • GPIO配置:在GPIO配置中,IOMUXC用于选择引脚的功能模式,如将某个引脚配置为GPIO输入或输出模式。
  • 外设接口配置:对于其他外设接口(如UART、SPI、I2C等),IOMUXC同样用于选择引脚的功能模式,以满足外设的IO需求。

五、总结

        IOMUXC是SOC设计中实现引脚复用的关键组件,它通过动态切换引脚功能,提高了IO资源的利用率,满足了不同外设和功能的IO需求。在配置和使用IOMUXC时,需要参考芯片使用手册和设备树文档,确保引脚功能的正确设置。

Pinctrl       

一、Pinctrl子系统的作用

        Pinctrl子系统的主要作用是管理和配置处理器上的引脚资源。在嵌入式系统中,引脚是处理器与外部世界进行通信和交互的接口。不同的处理器和硬件平台可能具有不同的引脚数量和功能,因此需要一种统一的机制来管理和配置这些引脚资源,以确保系统的正常运行。

二、Pinctrl子系统的组成

Pinctrl子系统主要由以下几个部分组成:

  1. Pinctrl Core:Pinctrl Core是Pinctrl子系统的核心部分,负责管理和维护系统上的引脚和Pinctrl配置,提供通用的Pinctrl接口供设备驱动程序使用,并管理设备驱动程序之间的引脚冲突和资源共享。

  2. Pinctrl驱动程序:Pinctrl驱动程序是一个用于管理芯片引脚的Linux内核驱动程序。它通过实现Pinctrl Core提供的接口来向Pinctrl Core注册自己,并提供芯片引脚的配置和控制功能。

  3. Pinctrl映射器:Pinctrl映射器是一个将Pinctrl配置映射到具体芯片引脚的模块。它负责解析Pinctrl配置,映射到具体的引脚,并将映射结果传递给Pinctrl驱动程序。Pinctrl映射器可以根据不同的芯片架构和芯片引脚布局进行定制。

三、Pinctrl子系统的工作原理

Pinctrl子系统的工作原理可以分为以下几个阶段:

  1. 解析阶段:在系统启动时,Pinctrl子系统会解析设备树(Device Tree)中的引脚配置信息。

  2. 配置阶段:解析完成后,Pinctrl子系统会根据解析得到的信息配置引脚资源。它会根据配置模式设置引脚的功能,并根据电气特性配置引脚的输入/输出电路。如果需要,Pinctrl子系统还会配置引脚的中断信息,以便处理外部事件。

  3. 应用阶段:配置完成后,Pinctrl子系统会将配置应用于处理器上的引脚。这意味着处理器上的引脚将按照配置信息进行工作。此时,其他驱动程序或应用程序可以通过Pinctrl子系统提供的接口来访问和操作这些引脚。

四、Pinctrl子系统的功能

Pinctrl子系统提供了丰富的功能,以满足不同的应用场景需求:

  1. 引脚复用:允许多个引脚通过复用的方式连接到芯片上的不同功能模块,从而提高了引脚的利用率。

  2. 引脚配置:支持对引脚进行详细的配置,包括设置引脚的电气特性(如上拉、下拉、开漏等)、驱动能力、速度等。

  3. 引脚组配置:支持将多个引脚组合成一个逻辑上的引脚组,以便进行批量配置和操作,提高了配置效率。

  4. 中断管理:支持引脚中断的配置和管理,使得开发者可以方便地处理外部事件。

五、imx6ull举例

以参数值为例进行分析:

MX6UL_PAD_UART1_RTS_B__GPIO1_IO19       0x17059 /* SD1 CD */

参数分为前后的两部分 MX6UL_PAD_UART1_RTS_B__GPIO1_IO19 0x17059

首先是 MX6UL_PAD_UART1_RTS_B__GPIO1_IO19  此参数是一个宏定义如下对应了5个数据

#define MX6UL_PAD_UART1_RTS_B__GPIO1_IO19            0x0090 0x031C 0x0000 0x5 0x0
参数值的宏定义对应了5个数据值对应关系如下表 :

说明数据值
mux_reg复用寄存器的地址或偏移量0x0090
conf_reg配置寄存器的地址或偏移量0x031C
input_reg输入寄存器的地址或偏移量0x0000
mux_mode复用模式0x5
input_val输入值0x0

iomuxc的 reg 属 性 可 知 IOMUXC 外 设 寄 存 器 起 始 地 址 为 0x020e0000 。

1.mux_reg :0x0090

UART1_RTS_Bpinmux_reg寄存器地址就是 :0x020e0000+0x0090= 0x020e0090。

2.conf_reg :0x031C

UART1_RTS_Bpinconf_reg寄存器地址就是 :0x020e0000+0x031c= 0x020e031c

3.input_reg :0x0000

input_reg 寄存器偏移地址,有些外设有 input_reg 寄存器,有 input_reg 寄存器的外设需要配置 input_reg 寄存器。

UART1_RTS_Bpininput_reg寄存器没有。

4.mux_mode:0x5

表示UART1_RTS_B复用为gpio1_io19 

5.input_val :0x0

input_val:就是写入 input_reg, 寄存器的值为0

        然后数据值 0x17059 就是 conf_reg 寄存器值。此值由用户自行设置,通 过此值来设置一个 IO 的上 / 下拉、驱动能力和速度等。在这里就相当于设置寄存器IOMUXC_SW_PAD_CTL_PAD_UART1_RTS_B 的值为 0x17059 。

向设备树中的节点添加pinCtrl节点例子如下

pinctrl_test: testgrp {fsl,pins = <MX6UL_PAD_GPIO1_IO00__GPIO1_IO00   config //onfig 是具体设置值..........>;
};
        设备树是通过属性来保存信息的,因此需要添加一个属性,属性名字一定要为“fsl,pins ”,
因为对于 I.MX 系列 SOC 而言, pinctrl 驱动程序是通过读取“ fsl,pins ”属性值来获取 PIN 的配
置信息.

GPIO

        GPIO子系统是Linux内核中用于统一和便捷地访问GPIO(通用输入输出)引脚的一个子系统。它提供了一组API函数,使得驱动程序和用户空间程序能够方便地设置GPIO的方向、读取或写入GPIO的值,以及处理GPIO中断等。以下是对GPIO子系统的详细介绍,包括相关的API函数和OF(设备树)函数。

一、GPIO子系统的作用

        GPIO子系统的主要作用是方便驱动开发者使用GPIO引脚。通过GPIO子系统,开发者可以在设备树中添加GPIO相关的信息,然后在驱动程序中使用GPIO子系统提供的API函数来操作GPIO引脚,如设置GPIO的方向、读取或写入GPIO的值等。这样,开发者就无需直接操作硬件寄存器,从而简化了驱动程序的开发过程。

二、GPIO子系统的架构

Linux的GPIO子系统驱动框架主要由以下几个部分组成:

  1. GPIO控制器驱动程序:这是与硬件相关的代码,用于处理GPIO控制器与系统总线之间的通信。该部分代码通常由芯片厂商提供,以与特定的GPIO硬件交互。

  2. 平台驱动程序:平台驱动程序用于与硬件平台交互,识别GPIO硬件并将其与相关的GPIO控制器驱动程序关联起来。平台驱动程序的主要任务是向系统注册GPIO控制器设备,与GPIO控制器驱动程序进行绑定,并为其分配资源。

  3. GPIO字符设备驱动程序:该驱动程序提供了用户空间API,使应用程序能够使用GPIO。用户可以通过/sys/class/gpio目录下的文件系统接口,通过读取和写入GPIO寄存器来控制GPIO。

三、GPIO子系统的API函数

GPIO子系统提供了一系列API函数,用于操作GPIO引脚。以下是一些常用的API函数及其功能:

  1. gpio_request(unsigned gpio, const char *label):用于申请一个GPIO引脚。在使用一个GPIO引脚之前,必须先通过此函数进行申请。

  2. gpio_free(unsigned gpio):用于释放之前申请的GPIO引脚。当不再需要使用某个GPIO引脚时,应调用此函数进行释放。

  3. gpio_direction_input(unsigned gpio):用于设置GPIO引脚为输入模式。

  4. gpio_direction_output(unsigned gpio, int value):用于设置GPIO引脚为输出模式,并可选地设置初始输出值。

  5. gpio_get_value(unsigned gpio):用于获取GPIO引脚的值(0或1)。

  6. gpio_set_value(unsigned gpio, int value):用于设置GPIO引脚的值(0或1)。

四、GPIO子系统的OF函数

在Linux内核中,设备树(Device Tree)是一种用于描述硬件设备的数据结构。GPIO子系统提供了一系列OF(设备树)函数,允许驱动程序从设备树中获取GPIO引脚的信息。以下是一些常用的OF函数及其功能:

  1. of_gpio_named_count(struct device_node *np, const char *propname):用于统计设备树中某个属性里面定义了几个GPIO信息。

  2. of_gpio_count(struct device_node *np):与of_gpio_named_count类似,但专门用于统计“gpios”属性的GPIO数量。

  3. of_get_named_gpio(struct device_node *np, const char *propname, int index):用于从设备树中获取指定属性的GPIO编号。该函数是驱动开发中常用的,因为它允许驱动程序根据设备树中的配置信息动态地获取GPIO编号。

五、举例

GPIO节点基本结构

在设备树中,一个典型的GPIO节点可能包含以下几个属性:

  1. gpio-controller:指定GPIO控制器的名称或引用。这通常是一个phandle,指向设备树中定义GPIO控制器的节点。

  2. #gpio-cells:表示每个GPIO引脚描述所占用的单元数。这通常与GPIO控制器的硬件设计相关。

  3. gpio-range:定义GPIO引脚的范围,包括起始引脚号和引脚数量。例如,<&gpio0 0 16>表示从GPIO控制器gpio0的第0个引脚开始,共有16个引脚。

  4. interrupt-parent:指定中断控制器的名称或引用,如果GPIO引脚用于中断的话。

  5. interrupts:描述GPIO引脚的中断配置,包括中断号、触发方式和中断处理函数等。

  6. status:表示GPIO节点的状态,通常是"okay"表示节点有效。

&gpio0 {  /* GPIO控制器引用,假设gpio0是在设备树的其他部分定义的GPIO控制器节点 */  gpio-controller; /* 声明这是一个GPIO控制器节点 */  #gpio-cells = <2>; /* 每个GPIO引脚描述占用2个单元 */  example_device_gpios: example_gpio@0 {  /* 定义一个名为example_gpio的GPIO子节点,起始地址为0 */  reg = <0>; /* 指定GPIO引脚的起始地址,这里为0 */  #gpio-cells = <1>; /* 在这个子节点中,每个GPIO描述占用1个单元(通常对于单个引脚来说是这样) */  gpio-range = <&gpio0 0 1>; /* 从gpio0控制器的第0个引脚开始,使用1个引脚 */  /* 如果需要,还可以添加中断相关属性 */  // interrupt-parent = <&intc>; /* 指定中断控制器 */  // interrupts = <0 1>; /* 中断号和触发方式(例如,0表示中断号,1表示边沿触发) */  status = "okay"; /* 节点状态为有效 */  };  
};  /* 注意:上述示例中的具体值(如#gpio-cells、gpio-range等)会根据实际的硬件和GPIO控制器设计而有所不同。 */  
/* 另外,设备树中的节点和属性命名也应遵循具体的硬件和驱动程序的要求。 */

解释

  • &gpio0:这是对设备树中其他地方定义的GPIO控制器节点的引用。
  • gpio-controller:声明这个节点是一个GPIO控制器节点。
  • #gpio-cells:指定每个GPIO描述所需的单元数。这取决于GPIO控制器的硬件设计。
  • example_device_gpios: example_gpio@0:定义了一个名为example_gpio的子节点,用于描述特定设备的GPIO配置。@0表示这个节点的起始地址(或索引)是0。
  • reg:指定了GPIO引脚的起始地址。在某些情况下,这个属性可能不是必需的,因为gpio-range已经提供了足够的信息。
  • #gpio-cells(在子节点中):在这个特定的子节点中,每个GPIO描述所需的单元数。对于单个引脚来说,这通常是1。
  • gpio-range:定义了从哪个GPIO控制器的哪个引脚开始使用,以及使用多少个引脚。
  • interrupt-parentinterrupts(可选):如果GPIO引脚用于中断,则需要指定中断控制器和中断配置。
  • status:表示节点的状态。通常是"okay"表示节点有效且应该被内核包含。

请注意,上述模板是一个简化的示例,实际设备树中的GPIO节点可能会根据具体的硬件和驱动程序要求包含更多的属性和子节点。在编写设备树时,应仔细参考硬件手册和驱动程序文档以确保正确的配置。

CODE-LED

/*************************************************************************
#    > File Name: pinctrl_gpio.c
#    > Author: HENG-W
#    > Mail: 
#    > Created Time: 2024年09月04日 星期三 18时36分27秒
#    > Describe: pinctrl_gpio子系统实验练习
#*************************************************************************/
/*头文件*/
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/gpio.h>
#include <linux/init.h>
#include <linux/ide.h>
#include <linux/errno.h>
#include <linux/cdev.h>
#include <linux/device.h>
#include <linux/of.h>
#include <linux/of_gpio.h>
#include <linux/of_address.h>
#include <asm/io.h>
#include <asm/uaccess.h>
#include <asm/mach/map.h>
/*
1.首先在 imx6ull-zealginat-emmc.dts 文件,
在根节点“/”下创建如下内容zealginat-pinctrl-gpio-led {compatible = "zealginat-pinctrl-gpio-led";status = "okay";pinctrl-0 = <&zealginat_zealgaint_pinctrl_led>;pinctrl-names = "pinctrl-gpio-led";pinctrl-gpio-led-pin = <&gpio1 3 GPIO_ACTIVE_LOW>;};2. iomuxc 节点的 imx6ul-evk 子节点下创建一个名为“zealginat_zealgaint_pinctrl_led”的子节点zealginat_zealgaint_pinctrl_led: ledgrp {fsl,pins = <MX6UL_PAD_GPIO1_IO03__GPIO1_IO03	0x10B0>;};
3.检查 PIN 是否被其他外设使用!!!检查 PIN 是否被其他外设使用!!!检查 PIN 是否被其他外设使用!!!检查 PIN 是否被其他外设使用!!!查找如下两个参数是否有重复MX6UL_PAD_GPIO1_IO03__GPIO1_IO03<&gpio1 3 GPIO_ACTIVE_LOW>;
*/
/*定义设备数量、设备名、开灯关灯宏定义*/
#define GPIO_DEV_COUNT 1
#define GPIO_DEV_NAME "pinctrl_gpio"
#define LED_ON  1
#define LED_OFF 0/*定义pinctrl_gpio设备结构体*/
struct pinctrl_gpio_dev {dev_t devid;             /* 设备号*/int major;              /* 主设备号*/int minor;              /* 次设备号*/struct cdev cdev;       /* cdev结构体*/struct device *device;  /* 设备结构体指针*/struct class  *class;   /* 类结构体指针*/   struct device_node *node;   /* 设备树节点指针*/int led_gpio_num;       /* led gpio编号*/int led_status;         /* led状态*/
};
/*声明并初始化pinctrl_gpio_dev结构体*/  
static struct pinctrl_gpio_dev pinctrl_gpio_led;
/*打开设备*/
static int pinctrl_gpio_open(struct inode *inode, struct file *file)
{/*设置私有数据*/file->private_data = &pinctrl_gpio_led;printk("pinctrl_gpio_open\n");return 0;
}
/*向设备写数据*/
static ssize_t pinctrl_gpio_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos)
{int retvale = 0;unsigned char databuf[1];unsigned char ledstatus;struct pinctrl_gpio_dev *dev = file->private_data; /* 获取私有数据*//*4、从用户空间拷贝数据*/retvale = copy_from_user(databuf, buf, count);if (retvale< 0) {printk("copy_from_user failed\n");return -EFAULT;}ledstatus = databuf[0]; /* 获取用户输入 状态值*/if (ledstatus == LED_ON) {gpio_set_value(dev->led_gpio_num, LED_ON);dev->led_status = LED_ON;} else if (ledstatus == LED_OFF) {gpio_set_value(dev->led_gpio_num, LED_OFF);dev->led_status = LED_OFF;} else {printk("input error\n");}return 0;
}
/*关闭设备*/
static int pinctrl_gpio_release(struct inode *inode, struct file *file)
{printk("pinctrl_gpio_release\n");return 0;
}/*设备操作函数结构体*/
static const struct file_operations pinctrl_gpio_fops = {.owner = THIS_MODULE,.open = pinctrl_gpio_open,.write = pinctrl_gpio_write,.release = pinctrl_gpio_release,
};/*驱动程序加载函数*/
static int __init pinctrl_gpio_init(void)
{int ret;/*1、获取设备树节点*/pinctrl_gpio_led.node = of_find_node_by_path("/zealginat-pinctrl-gpio-led");if (!pinctrl_gpio_led.node) {printk("can't find zealginat-pinctrl-gpio-led node\n");return -ENOENT;}/*2、获取led gpio编号*/pinctrl_gpio_led.led_gpio_num = of_get_named_gpio(pinctrl_gpio_led.node, "pinctrl-gpio-led-pin", 0);if (pinctrl_gpio_led.led_gpio_num < 0) {printk("can't get pinctrl-gpio-led-pin\n");return -ENOENT;} else {printk("pinctrl-gpio-led-pin num:%d\n", pinctrl_gpio_led.led_gpio_num);}/*3、设置GPIO1_IO03为输出模式,输出高电平,默认关闭*/ret = gpio_request(pinctrl_gpio_led.led_gpio_num, "pinctrl-gpio-led-pin");if (ret < 0) {printk("can't request gpio %d\n", pinctrl_gpio_led.led_gpio_num);gpio_free(pinctrl_gpio_led.led_gpio_num);return -1;}ret = gpio_direction_output(pinctrl_gpio_led.led_gpio_num, LED_ON);/*设置为输出模式,默认关闭,高电平关闭所以是LED_ON  1 */if (ret < 0) {printk("can't set direction of gpio %d\n", pinctrl_gpio_led.led_gpio_num);gpio_free(pinctrl_gpio_led.led_gpio_num);return -1;}  /*4、申请字符设备号*//*初始化主设备号*/pinctrl_gpio_led.major = 0;if (pinctrl_gpio_led.major){pinctrl_gpio_led.devid = MKDEV(pinctrl_gpio_led.major, 0);ret = register_chrdev_region(pinctrl_gpio_led.devid, GPIO_DEV_COUNT, GPIO_DEV_NAME);    /* 申请设备号*/}else{ret = alloc_chrdev_region(&pinctrl_gpio_led.devid, 0, GPIO_DEV_COUNT, GPIO_DEV_NAME);   /* 申请设备号*/pinctrl_gpio_led.major = MAJOR(pinctrl_gpio_led.devid);                                 /* 获取主设备号*/pinctrl_gpio_led.minor = MINOR(pinctrl_gpio_led.devid);                                 /* 获取次设备号*/                          }if (ret<0){printk("can't register char device\n");goto err_unregister_chrdev;}else{printk("pinctrl_gpio_led major num:%d, minor num:%d\n", pinctrl_gpio_led.major, pinctrl_gpio_led.minor);}/*5、创建字符设备*/pinctrl_gpio_led.cdev.owner = THIS_MODULE;cdev_init(&pinctrl_gpio_led.cdev, &pinctrl_gpio_fops);ret = cdev_add(&pinctrl_gpio_led.cdev, pinctrl_gpio_led.devid, GPIO_DEV_COUNT);if (ret < 0) {printk("can't add cdev\n");goto err_destroy_cdev;}else {printk("cdev add success\n");}/*6、创建类*/pinctrl_gpio_led.class = class_create(THIS_MODULE, GPIO_DEV_NAME);if (IS_ERR(pinctrl_gpio_led.class)) {printk("can't create class\n");goto err_destroy_class;} else {printk("class create success\n");}/*7、创建设备*/pinctrl_gpio_led.device = device_create(pinctrl_gpio_led.class, NULL, pinctrl_gpio_led.devid, NULL, GPIO_DEV_NAME);if (IS_ERR(pinctrl_gpio_led.device)) {printk("can't create device\n");goto err_device_create;     } else {printk("device create success\n");}return 0;
err_device_create:class_destroy(pinctrl_gpio_led.class);cdev_del(&pinctrl_gpio_led.cdev);unregister_chrdev_region(pinctrl_gpio_led.devid, GPIO_DEV_COUNT);return 0;
err_destroy_class:cdev_del(&pinctrl_gpio_led.cdev);unregister_chrdev_region(pinctrl_gpio_led.devid, GPIO_DEV_COUNT);return 0;
err_destroy_cdev:unregister_chrdev_region(pinctrl_gpio_led.devid, GPIO_DEV_COUNT);return 0;
err_unregister_chrdev:return 0;
}/*驱动程序卸载载函数*/
static void __exit pinctrl_gpio_exit(void)
{gpio_free(pinctrl_gpio_led.led_gpio_num);device_destroy(pinctrl_gpio_led.class, pinctrl_gpio_led.devid);class_destroy(pinctrl_gpio_led.class);cdev_del(&pinctrl_gpio_led.cdev);unregister_chrdev_region(pinctrl_gpio_led.devid, GPIO_DEV_COUNT);printk("pinctrl_gpio_led exit\n");
}module_init(pinctrl_gpio_init);
module_exit(pinctrl_gpio_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("HENG-W");
MODULE_DESCRIPTION("pinctrl_gpio driver for i.MX6ull");
MODULE_VERSION("1.0");

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

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

相关文章

C++中protobuffer的具体使用方法以及重要原理的实现

一、protobuffer的具体使用 对于基本的知识可以看我之前的文章。 那一片文章主要是知识点&#xff0c;这一片是实战。 1、头部 我们通过syntax 这个来指定版本号&#xff0c;如果不写的话就会默认为proto2&#xff0c;2这个版本是一个比较旧的版本。旧的版本写起来就比较繁琐。…

25届计算机毕业设计,如何打造Java SpringBoot+Vue博客系统,一步一脚印,开发心得分享

✍✍计算机编程指导师 ⭐⭐个人介绍&#xff1a;自己非常喜欢研究技术问题&#xff01;专业做Java、Python、微信小程序、安卓、大数据、爬虫、Golang、大屏等实战项目。 ⛽⛽实战项目&#xff1a;有源码或者技术上的问题欢迎在评论区一起讨论交流&#xff01; ⚡⚡ Java实战 |…

Spring源码-从源码层面讲解声明式事务配置文件的加载和相关对象的创建1(创建对向,属性填充,动态代理均有涉及)

tx.xml事务配置文件的解析 <?xml version"1.0" encoding"UTF-8"?> <beans xmlns"http://www.springframework.org/schema/beans"xmlns:xsi"http://www.w3.org/2001/XMLSchema-instance"xmlns:context"http://www.spr…

项目实战 - 贪吃蛇

目录 1. 基本功能 2. 技术要点 3. 环境 4. 效果演示 5. 控制台设置 6. Win32 API介绍 6.1 Win32 API 6.2 程序台控制(Console) 6.3 控制台屏幕上的坐标(COORD) 6.4 GetStdHandle 6.5 GetConsoleCursorInfo 6.5.1 CONSOLE_CURSOR_INFO 6.6 SetConsoleCursorInfo 6…

Android终端如何快速接入GB28181平台实现实时音视频回传

技术背景 GB28181是由中国国家标准委员会发布的基于IP网络的安防视频监控标准。Android平台GB28181设备对接模块&#xff0c;主要涉及到视频监控领域&#xff0c;可实现不具备国标音视频能力的 Android终端&#xff0c;通过平台注册接入到现有的GB/T28181—2016服务&#xff0…

数据结构——单链表查询、逆序、排序

1、思维导图 2、查、改、删算法 //快慢排序法找中间值 int mid_link(Link_t *plink) {Link_Node_t *pfast plink->phead;Link_Node_t *pslow pfast;int m 0;while(pfast ! NULL){pfast pfast->pnext;m;if(m % 2 0){pslow pslow->pnext;}}printf("%d\n&quo…

WPF-快速构建统计表、图表并认识相关框架

一、使用ScottPlot.Wpf 官网地址&#xff1a;https://scottplot.net/quickstart/wpf/ 1、添加NuGet包&#xff1a;ScottPlot.Wpf 2、XAML映射命名空间&#xff1a; xmlns:ScottPlot"clr-namespace:ScottPlot.WPF;assemblyScottPlot.WPF" 3、简单示例&#xff1a;…

刘润《关键跃升》读书笔记6

把教练传授内容的知识含量分成五个级别&#xff1a;⽩⽔级、啤酒级、⻩酒 级、红酒级和⽩酒级&#xff08;⻅图3-4&#xff09; 第⼀个层级是⽩⽔级&#xff08;0&#xff09;。教练在传授的时候&#xff0c;什么都没有教&#xff0c;只 会训⼈。 ⼆个层级是啤酒级&#xff08…

LaTeX各符号表示方式(持续更新~)

- "\mu"&#xff1a;穆 miu - "\sigma"&#xff1a;西格玛xigema - "\lambda"&#xff1a;兰姆达或拉姆达lamuda - "\alpha"&#xff1a;阿尔法aerfa - "\beta"&#xff1a;贝塔beita - "\gamma"&#xff1a;伽马…

比特币客户端和API

1. 比特比客户端的安装 Bitcoin Core 客户端适用于从 x86 Windows 到 ARM Linux 的不同架构和平台&#xff0c;如下图所示&#xff1a; 2. Bitcoin Core客户端的类型 2.1 Bitcoind Bitcoind 末尾的字母 d 表示 daemon (守护程序&#xff09;。所谓守护程序&#xff0c;就是指…

deep-live-cam实时换中文整合包下载,双击exe直接运行

windows环境整合包下载地址&#xff1a; 点击下载 直接解压&#xff0c;双击启动.exe即可使用 硬件要求&#xff1a;有英伟达显卡&#xff0c;且要支持CUDA 硬件不符合要求也不用急&#xff0c;软件也有对应mac版本和windows非N卡版本&#xff0c;我还没做成整合包&#xff0c;…

【python因果推断库6】使用 pymc 模型的工具变量建模 (IV)1

目录 使用 pymc 模型的工具变量建模 (IV) 使用 pymc 模型的工具变量建模 (IV) 这份笔记展示了一个使用工具变量模型&#xff08;Instrumental Variable, IV&#xff09;的例子。我们将会遵循 Acemoglu, Johnson 和 Robinson (2001) 的一个案例研究&#xff0c;该研究尝试解开…

大屏可视化:阿里 DataV 大屏怎么做自适应的?

你好&#xff0c;我是沐爸&#xff0c;欢迎点赞、收藏、评论和关注。 阿里 DataV 大屏是一款功能强大的数据可视化应用搭建工具&#xff0c;由阿里云提供&#xff0c;旨在帮助用户通过图形化的界面轻松搭建专业水准的可视化应用。 下面我们一起看下 DataV 大屏 是如何做自适应…

Leetcode 第 408 场周赛题解

Leetcode 第 408 场周赛题解 Leetcode 第 408 场周赛题解题目1&#xff1a;3232. 判断是否可以赢得数字游戏思路代码复杂度分析 题目2&#xff1a;3233. 统计不是特殊数字的数字数量思路代码复杂度分析 题目3&#xff1a;3234. 统计 1 显著的字符串的数量思路代码复杂度分析 题…

矮草坪渲染尝试

本来说写unity里的&#xff0c;由于three测试方便&#xff0c;先试试three 这个图片是目标效果 可以看见草很矮&#xff0c;很密集&#xff0c;如果用instance来绘制的话&#xff0c;遭不住的 忽然发现这个效果很像绒毛效果 于是找了博客康康 https://zhuanlan.zhihu.com/p/256…

Ubuntu | 安装 Truffle 框架(安装缓慢)

目录 预备工作具体步骤Step1&#xff1a;安装 nvma. 官方方式&#xff08;可能失败&#xff09;b. 压缩包安装方式 Step2&#xff1a;安装 node.js 和 npmStep3&#xff1a;安装 Truffle 参考博客 前言&#xff1a;昨天安装 Truffle 框架&#xff0c;结果缓冲条转了一晚上都没安…

企业全球组网有哪几种常用的组网方式?

为了实现全球范围内的高效通信和数据传输&#xff0c;企业需要选择适合自身需求的组网方式。企业全球组网的有哪几种主要方式&#xff1f;一般包括传统的MPLS网络、云网络、SD-WAN技术和全球VPN&#xff0c;以帮助企业在全球范围内建立稳定、高效的网络连接。 1、传统的MPLS网络…

探索AWS EC2:云计算的强大引擎

在数字化转型的浪潮中&#xff0c;企业对计算资源的需求不断增长。亚马逊弹性计算云&#xff08;EC2&#xff09;作为AWS&#xff08;亚马逊网络服务&#xff09;的核心产品之一&#xff0c;凭借其强大的功能和灵活性&#xff0c;成为了全球企业构建和扩展应用的首选平台。无论…

数据结构(邓俊辉)学习笔记】串 10——BM_BC算法:坏字符

文章目录 1.坏字符2. 特殊情况 1.坏字符 实际上&#xff0c;刚才的实例中我们所展示的那样一个计算过程&#xff0c;就是所谓 BM 算法所采用的策略之一&#xff0c;而这一策略&#xff0c;将我们刚才所说的教训称作坏字符。 在这里&#xff0c;不妨改为基于蛮力算法的第二个版…

设置电子签名

设置点赞签名代码 export class Signature {width: number 300height: number 300canvas!: HTMLCanvasElementctx!: CanvasRenderingContext2Dprivate drawing: boolean falsepreTask: string[] []nextTask: string[] []private allTask: { x: number; y: number; color: …