编写虚拟的GPIO控制器的驱动程序:和pinctrl的交互使用

news2024/11/13 9:39:10

往期内容

本专栏往期内容:

  1. Pinctrl子系统和其主要结构体引入
  2. Pinctrl子系统pinctrl_desc结构体进一步介绍
  3. Pinctrl子系统中client端设备树相关数据结构介绍和解析
  4. inctrl子系统中Pincontroller构造过程驱动分析:imx_pinctrl_soc_info结构体
  5. Pinctrl子系统中client端使用pinctrl过程的驱动分析
  6. Pinctrl子系统中Pincontroller和client驱动程序的编写
  7. GPIO子系统层次与数据结构详解-CSDN博客
  8. GPIO子系统中Controller驱动源码分析

input子系统专栏:

  1. 专栏地址:input子系统
  2. input角度:I2C触摸屏驱动分析和编写一个简单的I2C驱动程序
    – 末片,有往期内容观看顺序

I2C子系统专栏:

  1. 专栏地址:IIC子系统
  2. 具体芯片的IIC控制器驱动程序分析:i2c-imx.c-CSDN博客
    – 末篇,有往期内容观看顺序

总线和设备树专栏:

  1. 专栏地址:总线和设备树
  2. 设备树与 Linux 内核设备驱动模型的整合-CSDN博客
    – 末篇,有往期内容观看顺序

img

目录

前言

Linux 4.x内核文档

  • Linux-4.9.88\Documentation\gpio📎drivers-on-gpio.txt📎gpio.txt📎gpio-legacy.txt📎sysfs.txt📎board.txt📎consumer.txt📎driver.txt
  • Linux-4.9.88\Documentation\devicetree\bindings\gpio\gpio.txt📎gpio.txt
  • Linux-4.9.88\drivers\gpio\gpio-mxc.c📎gpio-mxc.c
  • Linux-4.9.88\arch\arm\boot\dts\imx6ull.dtsi

本文主要讲解了如何在Linux 4.9.88内核中为虚拟GPIO控制器编写驱动程序,并展示了GPIO和Pinctrl子系统之间的交互方式。假设该虚拟GPIO控制器有4个引脚,然后在设备树中为其设置相应的设备节点和引脚配置。通过代码示例展示了如何实现GPIO的输入、输出功能,包括GPIO的值读取与设置。文介绍了GPIO控制器与Pinctrl的关系以及两者的映射机制,解释了gpio_pin_range和pinctrl_gpio_range结构体的作用,并提供了GPIO子系统中调用Pinctrl的流程示例。

1.编写虚拟的GPIO控制器的驱动程序

1.1 硬件功能

假设这个虚拟的GPIO Controller有4个引脚:

img

1.2 编写设备树文件

修改arch/arm/boot/dts/100ask_imx6ull-14x14.dts,添加如下代码:

/ {
    gpio_virt: virtual_gpiocontroller {
        compatible = "example,virtual_gpio";
        gpio-controller;
        #gpio-cells = <2>;
        ngpios = <4>;
    };

    myled {
        compatible = "XXX,leddrv";
        led-gpios = <&gpio_virt 2 GPIO_ACTIVE_LOW>;
    };
};

1.3 代码编写

代码编写:📎virtual_gpio_driver.c

#include <linux/module.h>
#include <linux/err.h>
#include <linux/init.h>
#include <linux/io.h>
#include <linux/mfd/syscon.h>
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/of_address.h>
#include <linux/gpio/consumer.h>
#include <linux/gpio/driver.h>
#include <linux/slab.h>
#include <linux/regmap.h>

// 定义一个全局的GPIO芯片结构体指针
static struct gpio_chip *g_virtual_gpio_chip;

// 用于模拟GPIO状态的全局变量
static int g_gpio_status = 0;

// 设备树匹配结构,匹配支持的设备
static const struct of_device_id virtual_gpio_of_match[] = {
    { .compatible = "example,virtual_gpio", },
    { },
};

// 设置GPIO为输出模式的函数实现
static int virtual_gpio_set_direction_output(struct gpio_chip *chip, unsigned offset, int value) {
    printk("Setting GPIO pin %d as output %s\n", offset, value ? "high" : "low");
    return 0; // 成功返回0
}

// 设置GPIO为输入模式的函数实现
static int virtual_gpio_set_direction_input(struct gpio_chip *chip, unsigned offset) {
    printk("Setting GPIO pin %d as input\n", offset);
    return 0; // 成功返回0
}

// 获取GPIO当前值的函数实现
static int virtual_gpio_get_value(struct gpio_chip *chip, unsigned offset) {
    int value = (g_gpio_status & (1 << offset)) ? 1 : 0;
    printk("Reading GPIO pin %d, current value = %d\n", offset, value);
    return value; // 返回当前值
}

// 设置GPIO值的函数实现
static void virtual_gpio_set_value(struct gpio_chip *chip, unsigned offset, int value) {
    printk("Setting GPIO pin %d to %d\n", offset, value);
    if (value) {
        g_gpio_status |= (1 << offset); // 设置为高电平
    } else {
        g_gpio_status &= ~(1 << offset); // 设置为低电平
    }
}

// 设备探测函数
static int virtual_gpio_probe(struct platform_device *pdev) {
    int ret;
    unsigned int ngpios;

    printk("Probing virtual GPIO driver: %s, line: %d\n", __FUNCTION__, __LINE__);

    // 分配gpio_chip结构体内存
    g_virtual_gpio_chip = devm_kzalloc(&pdev->dev, sizeof(*g_virtual_gpio_chip), GFP_KERNEL);

    // 配置gpio_chip的相关信息
    g_virtual_gpio_chip->label = pdev->name;
    g_virtual_gpio_chip->direction_output = virtual_gpio_set_direction_output;
    g_virtual_gpio_chip->direction_input = virtual_gpio_set_direction_input;
    g_virtual_gpio_chip->get = virtual_gpio_get_value;
    g_virtual_gpio_chip->set = virtual_gpio_set_value;
    g_virtual_gpio_chip->parent = &pdev->dev; // 设置父设备
    g_virtual_gpio_chip->owner = THIS_MODULE; // 设置模块所有者

    // 读取ngpios属性
    g_virtual_gpio_chip->base = -1; // 默认未分配基地址
    ret = of_property_read_u32(pdev->dev.of_node, "ngpios", &ngpios);
    g_virtual_gpio_chip->ngpio = ngpios; // 设置GPIO数量

    // 注册gpio_chip
    ret = devm_gpiochip_add_data(&pdev->dev, g_virtual_gpio_chip, NULL);

    return ret; // 返回结果
}

// 设备移除函数
static int virtual_gpio_remove(struct platform_device *pdev) {
    printk("Removing virtual GPIO driver: %s, line: %d\n", __FUNCTION__, __LINE__);
    return 0; // 成功返回0
}

// 定义platform_driver
static struct platform_driver virtual_gpio_driver = {
    .probe = virtual_gpio_probe,
    .remove = virtual_gpio_remove,
    .driver = {
        .name = "example_virtual_gpio",
        .of_match_table = of_match_ptr(virtual_gpio_of_match),
    },
};

// 初始化函数
static int __init virtual_gpio_init(void) {
    printk("Initializing virtual GPIO driver: %s, line: %d\n", __FUNCTION__, __LINE__);
    return platform_driver_register(&virtual_gpio_driver); // 注册platform_driver
}

// 清理函数
static void __exit virtual_gpio_exit(void) {
    printk("Exiting virtual GPIO driver: %s, line: %d\n", __FUNCTION__, __LINE__);
    platform_driver_unregister(&virtual_gpio_driver); // 注销platform_driver
}

// 模块初始化和清理宏
module_init(virtual_gpio_init);
module_exit(virtual_gpio_exit);

// 模块许可证
MODULE_LICENSE("GPL");

of_property_read_u32:📎of.h

2.GPIO子系统与Pinctrl子系统的交互

Linux-4.9.88\drivers\gpio\gpio-74x164.c📎gpio-74x164.c

2.1 使用GPIO前应该设置Pinctrl

假设使用这个虚拟的GPIO Controller的pinA来控制LED:

img

要使用pinA来控制LED,首先要通过Pinctrl子系统把它设置为GPIO功能,然后才能设置它为输出引脚、设置它的输出值。

所以在设备树文件里,应该添加Pinctrl的内容:

virtual_pincontroller {
    compatible = "XXX,virtual_pinctrl";
    myled_pin: myled_pin {
        functions = "gpio"; // 设置引脚功能为GPIO
        groups = "pin0"; // 指定该引脚所在的组
        configs = <0x11223344>; // 配置该引脚的其他特性
    };
};

gpio_virt: virtual_gpiocontroller {
    compatible = "XXX,virtual_gpio";
    gpio-controller; // 标识这是一个GPIO控制器
    #gpio-cells = <2>; // GPIO单元的数量
    ngpios = <4>; // GPIO引脚数量
};

myled {
    compatible = "XXX,leddrv"; // LED驱动
    led-gpios = <&gpio_virt 0 GPIO_ACTIVE_LOW>; // 指定使用的GPIO引脚
    pinctrl-names = "default"; // 指定Pinctrl的名称
    pinctrl-0 = <&myled_pin>; // 指定使用的Pinctrl设置
};

许多芯片并不需要在设备树中显式地将引脚配置为GPIO功能。这是因为某些芯片(例如STM32MP157)在内部实现上已经将GPIO功能与引脚复用整合在一起。因此,Pinctrl的使用在某些情况下是虚拟的,它与GPIO密切相关。

2.2 GPIO和Pinctrl的映射关系

2.2.1 示例

img

  • 左边的Pinctrl支持8个引脚,在Pinctrl的内部编号为0~7

  • 图中有2个GPIO控制器

    • GPIO0内部引脚编号为03,假设在GPIO子系统中全局编号为100103
    • GPIO1内部引脚编号为03,假设在GPIO子系统中全局编号为104107
  • 假设我们要使用pin1_1,应该这样做:

    • 根据GPIO1的内部编号1,可以换算为Pinctrl子系统中的编号5
    • 使用Pinctrl的函数,把第5个引脚配置为GPIO功能

2.2.2 数据结构

gpio_pin_range 结构体定义了 GPIO 控制器控制的引脚范围和对应的 pinctrl 设备,允许 GPIO 控制器管理一个 pinctrl 设备的引脚范围。

/** 
 * struct gpio_pin_range - GPIO 控制器所控制的引脚范围
 * @node: 连接到范围列表的链表节点,用于内部维护 pin range 的集合。
 * @pctldev: 指向管理相应引脚的 pinctrl 设备(pinctrl_dev)的指针,
 *           该设备将处理引脚复用、方向控制等功能。
 * @range: 由 GPIO 控制器控制的引脚的实际范围,包含引脚的起始位置、数量等信息。
 */
struct gpio_pin_range {
    struct list_head node;            // 列表头,维护 GPIO 范围的链表结构
    struct pinctrl_dev *pctldev;      // 与 GPIO 控制器关联的 pinctrl 设备
    struct pinctrl_gpio_range range;  // 由 GPIO 控制器控制的引脚范围信息
};
  • node:这是一个链表节点,通常用于将多个 gpio_pin_range 链接成一个链表,以便管理和迭代多个引脚范围。
  • pctldev:指向 pinctrl 设备的指针,pinctrl 设备负责管理 GPIO 引脚的复用和配置。
  • range:定义了 GPIO 控制器管理的实际引脚范围,包含引脚基地址和数量等信息。

pinctrl_gpio_range 结构体描述了由 GPIO 控制器所处理的 GPIO 引脚范围,为每个 GPIO 控制器提供一个编号空间的子范围。

/**
 * struct pinctrl_gpio_range - 每个 GPIO 控制器提供的 GPIO 编号范围
 * @node: 用于内部使用的链表节点,连接到范围列表中
 * @name: 此 GPIO 控制器范围的名称,用于标识 GPIO 控制器
 * @id: 该范围的芯片 ID,用于在范围内区分 GPIO 控制器
 * @base: GPIO 范围的基地址偏移,用于计算 GPIO 引脚编号
 * @pin_base: 如果 pins 数组为 NULL,此字段表示 GPIO 引脚范围的基引脚编号
 * @pins: 指向引脚枚举数组的指针,该数组列出 GPIO 范围中的所有引脚
 * @npins: GPIO 范围内的引脚数量,包含基引脚编号
 * @gc: 可选指针,指向 gpio_chip 结构体,该结构体用于 GPIO 控制器的基本信息
 */
struct pinctrl_gpio_range {
    struct list_head node;       // 内部链表节点,连接到 GPIO 范围列表
    const char *name;            // 范围名称,标识 GPIO 控制器
    unsigned int id;             // GPIO 范围 ID,唯一标识该范围
    unsigned int base;           // GPIO 编号范围的基地址偏移,用于计算引脚编号
    unsigned int pin_base;       // 引脚范围的基引脚编号,如果 pins 数组为 NULL 使用此基数
    unsigned const *pins;        // 引脚数组的指针,列出该 GPIO 范围内的所有引脚
    unsigned int npins;          // GPIO 范围中的引脚数量,包括基引脚编号
    struct gpio_chip *gc;        // 可选的 gpio_chip 指针,用于指向 GPIO 控制器信息
};
  • node:内部链表节点,用于管理 pinctrl_gpio_range 的链表结构。
  • name:范围的名称,通常是 GPIO 控制器的名称,用于标识该范围。
  • id:范围 ID,唯一标识该 GPIO 范围,用于在控制器中区分不同的 GPIO 范围。
  • base:GPIO 编号范围的基地址偏移量,通过该偏移量确定 GPIO 控制器管理的具体引脚编号。
  • pin_base:基引脚编号,表示该 GPIO 范围的起始引脚,通常在 pins 数组为空时使用。
  • pins:指向引脚编号数组的指针,列出该 GPIO 范围内的所有 GPIO 引脚。
  • npins:范围内的引脚数量,包括基引脚编号。
  • gc:可选的指向 gpio_chip 结构体的指针,用于与 GPIO 控制器相关联,提供 GPIO 控制器的基本信息。

2.3 GPIO调用Pinctrl的过程

GPIO子系统中的request函数,用来申请某个GPIO引脚,

它会导致Pinctrl子系统中的这2个函数之一被调用:pmxops->gpio_request_enablepmxops->request

调用关系如下:

gpiod_get //获取GPIO描述符的主函数,通常用于申请和配置GPIO引脚。
    gpiod_get_index 
        desc = of_find_gpio(dev, con_id, idx, &lookupflags);//查找设备树中指定的GPIO。
        ret = gpiod_request(desc, con_id ? con_id : devname); //用于确认请求并进行最终设置。
                    ret = gpiod_request_commit(desc, label); //如果GPIO芯片结构体中的request指针非空,它会调用芯片的request函数。
                                if (chip->request) {
                                    ret = chip->request(chip, offset);
                                }

编写GPIO驱动程序时,所设置chip->request函数,一般直接调用gpiochip_generic_request,它导致Pinctrl把引脚复用为GPIO功能。

gpiochip_generic_request(struct gpio_chip *chip, unsigned offset)
    pinctrl_request_gpio(chip->gpiodev->base + offset) //该函数负责将引脚配置为GPIO功能
        ret = pinctrl_get_device_gpio_range(gpio, &pctldev, &range); // gpio是引脚的全局编号

        /* Convert to the pin controllers number space */
        pin = gpio_to_pin(range, gpio);
        
        ret = pinmux_request_gpio(pctldev, range, pin, gpio);
                    ret = pin_request(pctldev, pin, owner, range);

Pinctrl子系统中的pin_request函数就会把引脚配置为GPIO功能:

static int pin_request(struct pinctrl_dev *pctldev,
                       int pin, const char *owner,
                       struct pinctrl_gpio_range *gpio_range) {
    const struct pinmux_ops *ops = pctldev->desc->pmxops;

    // 检查是否有用于请求引脚的操作
    if (gpio_range && ops->gpio_request_enable) {
        // 请求并启用单个GPIO引脚
        status = ops->gpio_request_enable(pctldev, gpio_range, pin);
    } else if (ops->request) {
        // 如果有通用请求函数,则调用
        status = ops->request(pctldev, pin);
    } else {
        // 默认情况下,不做任何操作
        status = 0;
    }

    return status; // 返回请求状态
}

2.4 编程_GPIO使用Pinctrl

2.4.1 做什么

如果不想在使用GPIO引脚时,在设备树中设置Pinctrl信息,

如果想让GPIO和Pinctrl之间建立联系,

需要做这些事情:

  1. 表明GPIO和Pinctrl间的联系

在GPIO设备树中使用gpio-ranges来描述它们之间的联系:

  • GPIO系统中有引脚号
  • Pinctrl子系统中也有自己的引脚号
  • 2个号码要建立映射关系
  • 在GPIO设备树中使用如下代码建立映射关系
// 当前GPIO控制器的0号引脚, 对应pinctrlA中的128号引脚, 数量为12
gpio-ranges = <&pinctrlA 0 128 12>; 
  1. 解析这些联系

在GPIO驱动程序中,解析跟Pinctrl之间的联系:处理gpio-ranges:

  • 这不需要我们自己写代码
  • 注册gpio_chip时会自动调用
int gpiochip_add_data(struct gpio_chip *chip, void *data)
    status = of_gpiochip_add(chip);
                status = of_gpiochip_add_pin_range(chip);

of_gpiochip_add_pin_range
    for (;; index++) {
        ret = of_parse_phandle_with_fixed_args(np, "gpio-ranges", 3,
                index, &pinspec);

        pctldev = of_pinctrl_get(pinspec.np); // 根据gpio-ranges的第1个参数找到pctldev

        // 增加映射关系	
        /* npins != 0: linear range */
        ret = gpiochip_add_pin_range(chip,
                                     pinctrl_dev_get_devname(pctldev),
                                     pinspec.args[0],
                                     pinspec.args[1],
                                     pinspec.args[2]);
  1. 编程
  • 在GPIO驱动程序中,提供gpio_chip->request
  • 在Pinctrl驱动程序中,提供pmxops->gpio_request_enablepmxops->request

2.4.2 编程

  1. GPIO控制器编程

在编写GPIO驱动程序时,需要关注以下几个方面:

  1. 设置请求函数

    • 确保在GPIO芯片结构体中正确设置chip->request指针,通常指向gpiochip_generic_request。这样可以确保引脚被正确复用为GPIO功能。
  2. 理解设备树

    • 如果GPIO引脚来自设备树,确保在设备树中正确描述GPIO的相关属性和配置,以便gpiod_get和相关函数能够正确查找和请求GPIO。
  3. 错误处理

    • 在每个调用中检查返回值,确保处理潜在的错误,避免因引脚请求失败而导致驱动不稳定。
  4. 功能分离

    • 在实现请求和释放引脚时,确保保持代码的清晰和可读,尽量将复杂逻辑分离到辅助函数中,以便于维护。

gpio_chip中提供request函数:

c chip->request = gpiochip_generic_request;

📎virtual_gpio_driver.c
(参考)>>
📎virtual_gpio_driver0.c

  1. Pinctrl编程
static const struct pinmux_ops virtual_pmx_ops = {
    .get_functions_count = virtual_pmx_get_funcs_count,
    .get_function_name = virtual_pmx_get_func_name,
    .get_function_groups = virtual_pmx_get_groups,
    .set_mux = virtual_pmx_set,
    .gpio_request_enable = virtual_pmx_gpio_request_enable,
};

📎virtual_pinctrl_driver.c📎core.h

  1. led:

📎virtual_pinctrl_client.c(参考) 》 📎leddrv.c

📎ledtest.c

2.4.3 注意

IMX6ULL使用GPIO时必须设置Pinctrl,如果不设置,只有那些默认就是GPIO功能的引脚可以正常使用。

原因:

  • GPIO控制器的设备树中,没有gpio-ranges
  • Pinctrl驱动中并没有提供pmxops->gpio_request_enablepmxops->request
  • gpio_chip结构体中direction_inputdirection_output,并没有配置引脚为GPIO功能

3.GPIO子系统的sysfs接口

  • Linux-4.9.88\drivers\gpio\gpiolib-sysfs.c📎gpiolib-sysfs.c

3.1 驱动程序

📎gpiolib-sysfs.c

3.2 常用的sysfs文件

3.2.1 有哪些GPIO控制器

/sys/bus/gpio/devices目录下,列出了所有的GPIO控制器,如下表示有11个GPIO控制器:

/sys/bus/gpio/devices/gpiochip0
/sys/bus/gpio/devices/gpiochip1
/sys/bus/gpio/devices/gpiochip2
/sys/bus/gpio/devices/gpiochip3
/sys/bus/gpio/devices/gpiochip4
/sys/bus/gpio/devices/gpiochip5
/sys/bus/gpio/devices/gpiochip6
/sys/bus/gpio/devices/gpiochip7
/sys/bus/gpio/devices/gpiochip8
/sys/bus/gpio/devices/gpiochip9
/sys/bus/gpio/devices/gpiochip10

3.2.2 每个GPIO控制器的详细信息

/sys/class/gpio/gpiochipXXX下,有这些信息:

/sys/class/gpio/gpiochip508]# ls -1
base     // 这个GPIO控制器的GPIO编号
device
label    // 名字
ngpio    // 引脚个数
power
subsystem
uevent

3.2.3 查看GPIO使用情况

cat /sys/kernel/debug/gpio

3.2.4 通过sysfs使用GPIO

如果只是简单的引脚控制(比如输出、查询输入值),可以不编写驱动程序。

但是涉及中断的话,就需要编写驱动程序了。

1. 确定GPIO编号

查看每个/sys/class/gpio/gpiochipXXX目录下的label,确定是你要用的GPIO控制器,也称为GPIO Bank。

根据它名字gpiochipXXX,就可以知道基值是XXX。

基值加上引脚offset,就是这个引脚的编号。

2. 导出/设置方向/读写值

举例:

echo 509 > /sys/class/gpio/export
echo out > /sys/class/gpio/gpio509/direction
echo 1 > /sys/class/gpio/gpio509/value
echo 509 > /sys/class/gpio/unexport

echo 509 > /sys/class/gpio/export
echo in > /sys/class/gpio/gpio509/direction
cat /sys/class/gpio/gpio509/value
echo 509 > /sys/class/gpio/unexport

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

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

相关文章

【MySQL】数据库整合攻略 :表操作技巧与详解

前言&#xff1a;本节内容讲述表的操作&#xff0c; 对表结构的操作。 是对表结构中的字段的增删查改以及表本身的创建以及删除。 ps&#xff1a;本节内容本节内容适合安装了MySQL的友友们进行观看&#xff0c; 实操更有利于记住哦。 目录 创建表 查看表结构 修改表结构 …

CocoaPods安装步骤详解 - 2024

引言 CocoaPods的安装&#xff0c;如果有VPN就一直开启&#xff0c;会让整个流程非常顺畅。 在现代 iOS 开发中&#xff0c;依赖管理变得越来越重要&#xff0c;CocoaPods 成为开发者们首选的依赖管理工具。它不仅可以简化库的安装与更新&#xff0c;还能帮助开发者更高效地管…

二叉树-堆

树的几个重要定义 1.树根子树根亲缘关系 2.节点的度:有几个子树或根有几个孩子 3.叶子节点:没有孩子的终端节点 度为0 4.分支节点:度不为0的节点 5.树叶子分支节点 6.父亲节点/双亲节点 7.子节点 8.树的度:最大节点的度就是树的度 9.树的层:一般从第一层开始数,也有从0层开始数…

内置RTK北斗高精度定位的4G执法记录仪、国网供电服务器记录仪

内置RTK北斗高精度定位的4G执法记录仪、国网供电服务器记录仪BD311R 发布时间: 2024-10-23 11:28:42 一、 产品图片&#xff1a; 二、 产品特性&#xff1a; 4G性能&#xff1a;支持2K超高清图传&#xff0c;数据传输不掉帧&#xff0c;更稳定。 独立北…

浮动路由:实现出口线路的负载均衡冗余备份。

浮动路由 Tip&#xff1a;浮动路由指在多条默认路由基础上加入优先级参数&#xff0c;实现出口线路冗余备份。 ip routing-table //查看路由表命令 路由优先级参数&#xff1a;越小越优 本次实验测试两条默认路由&#xff0c;其中一条默认路由添加优先级参数&#xff0c;设置…

ssm077铁岭河医院医患管理系统+vue(论文+源码)_kaic

毕业设计&#xff08;论文) 题 目&#xff1a; 医院医患管理系统 姓 名&#xff1a; 学 号&#xff1a; 所属学院&#xff1a; 专业班级&#xff1a; 指导&#xff1a; 职 称&#xff1a; 完成日期 2021年 月 摘 要 21世纪的今天&#xf…

关于在VS中使用Qt不同版本报错的问题

最开始需要配置的地方 首先看一下我的Qt有关的环境变量&#xff1a; Path环境变量里&#xff1a; 这里就是把对应Qt编译器环境下的bin目录放进来&#xff1a;比如你使用的是msvc2017_64或者MinGW QMAKESPEC环境变量&#xff1a; 这个就选择Qt对应的编译器目录下的\mkspecs\w…

Redis 权限控制(ACL)|ACL 命令详解、ACL 持久化

官网文档地址&#xff1a;https://redis.io/docs/latest/operate/oss_and_stack/management/security/acl/ 使用版本&#xff1a;Redis7.4.1 什么是 ACL&#xff1f; ACL&#xff08;Access Control List&#xff09;&#xff0c;权限控制列表&#xff0c;是 Redis 提供的一种…

任务中心全新升级,新增分享接口文档功能,MeterSphere开源持续测试工具v3.4版本发布

2024年11月5日&#xff0c;MeterSphere开源持续测试工具正式发布v3.4版本。 在这一版本中&#xff0c;系统设置方面&#xff0c;任务中心支持实时查看系统即时任务与系统后台任务&#xff1b;接口测试方面&#xff0c;新增接口文档分享功能、接口场景导入导出功能&#xff0c;…

GEE 数据集——美国gNATSGO(网格化国家土壤调查地理数据库)完整覆盖了美国所有地区和岛屿领土的最佳可用土壤信息

目录 简介 代码 引用 网址推荐 知识星球 机器学习 gNATSGO&#xff08;网格化国家土壤调查地理数据库&#xff09; 简介 gNATSGO&#xff08;网格化国家土壤调查地理数据库&#xff09;数据库是一个综合数据库&#xff0c;完整覆盖了美国所有地区和岛屿领土的最佳可用土…

3.PyCharm工具

第三方IDE&#xff0c;集成开发工具&#xff0c;官网下载。 社区版本&#xff0c;免费使用。 创建项目

Rust移动开发:Rust在iOS端集成使用介绍

iOS调用Rust 上篇介绍了 Rust移动开发&#xff1a;Rust在Android端集成使用介绍, 这篇主要看下iOS上如何使用Rust&#xff0c;Rust可以给移动端开发提供跨平台&#xff0c;通用组件支持。 该篇适合对iOS、Rust了解&#xff0c;想知道如何整合调用和编译的&#xff0c;如果想要…

video素材格式转换--mp4转webm(vue3+Nodejs)

总体实现使用ffmpeg 自动化demo实现 vue3Nodejsffmpeg 一、官网下载ffmpeg https://ffmpeg.org/ 1-1选择对应系统下载 1-2下载完成后配置环境变量 1-2-1将下载文件的bin目录配置到环境变量中 例如:D:\ffmpeg\bin 1-3测试ffmpeg是否安装成功 ffmpeg -version 如图 证明安装成…

YOLOPv2论文翻译

YOLOPv2: Better, Faster, Stronger for Panoptic Driving Perception 摘要 在过去的十年中&#xff0c;多任务学习方法在解决全景驾驶感知问题方面取得了令人鼓舞的成果&#xff0c;既提供了高精度又具备高效能的性能。在设计用于实时实际自动驾驶系统的网络时&#xff0c;这…

Golang | Leetcode Golang题解之第553题最优除法

题目&#xff1a; 题解&#xff1a; func optimalDivision(nums []int) string {n : len(nums)if n 1 {return strconv.Itoa(nums[0])}if n 2 {return fmt.Sprintf("%d/%d", nums[0], nums[1])}ans : &strings.Builder{}ans.WriteString(fmt.Sprintf("%d…

基于LORA的一主多从监测系统_实物展示

提供&#xff1a;成品硬件 4G模块 详细开发流程 源码 原理图 主节点和子节点A的合照来一张 主节点 子节点A

教程:FFmpeg结合GPU实现720p至4K视频转换

将一个 720p 的视频放大编码到 4K&#xff0c;这样的视频处理在很多业务场景中都会用到。很多视频社交、短视频、视频点播等应用&#xff0c;都会需要通过服务器来处理大量的视频编辑需求。 本文我们会探讨一下做这样的视频处理&#xff0c;最低的 GPU 指标应该是多少。利用开源…

css | padding vs margin

前置知识 height是作用域内容(content)区域的 padding和margin用百分比的时候是怎么算的&#xff1f;父元素的宽度。注意&#xff0c;不是根据父元素相应的属性&#xff0c;就是父亲的width 自身的height是0 以下代码&#xff0c;外面盒子是100x10的&#xff0c;里面的widt…

监控架构- Grafana-监控大屏

1. Grafana极速上手指南 1.1 环境准备 主机ip地址grafana10.0.0.66zabbix_server10.0.0.62 1.2 部署grafana 9.3.6 ##去官网找rpm包下载并上传 ## 安装 yum localinstall -y grafana-9.3.6-1.x86_64.rpm## 启动服务并设置开机自启动 systemctl enable --now grafana-server…

数据分析反馈:提升决策质量的关键指南

内容概要 在当今快节奏的商业环境中&#xff0c;数据分析与反馈已成为提升决策质量的重要工具。数据分析不仅能为企业提供全面的市场洞察&#xff0c;还能帮助管理层深入了解客户需求与行为模式。掌握数据收集的有效策略和工具&#xff0c;企业能够确保获得准确且相关的信息&a…