当前位置: 首页 > news >正文

GPIO子系统

1. GPIO子系统视频概述

1.1 GPIO子系统的作用

芯片内部有很多引脚,这些引脚可以接到GPIO模块,也可以接到I2C等模块。

通过Pinctrl子系统来选择引脚的功能(mux function)、配置引脚:

当一个引脚被复用为GPIO功能时,我们可以去设置它的方向、设置/读取它的值。

GPIO名为"General Purpose Input/Output",通用目的输入/输出,就是常用的引脚。

GPIO可能是芯片自带的,也可能通过I2C、SPI接口扩展:

GPIO有一些通用功能、通用属性。

1.2 通用功能

  • 可以设为输出:让它输出高低电平;

  • 可以设为输入,读取引脚当前电平;

  • 可以用来触发中断

对于芯片自带的GPIO,它的访问时很快的,可以在获得spinlocks的情况下操作它。

但是,对于通过I2C、SPI等接口扩展的GPIO,访问它们时可能导致休眠,所以这些"GPIO Expander"就不能在获得spinlocks的情况下使用。

1.3 通用属性

  • Active-High and Active-Low

    以LED为例,需要设置GPIO电平。但是有些电路可能是高电平点亮LED,有些是低电平点亮LED。

    可以使用如下代码:

gpiod_set_value(gpio, 1);  // 输出高电平点亮LED
gpiod_set_value(gpio, 0);  // 输出低电平点亮LED

对应同一个目标:点亮LED,对于不同的LED,就需要不同的代码,原因在于上面的代码中1、0表示的是"物理值"。

如果能使用"逻辑值",同样的逻辑值在不同的配置下输出对应的物理值,就可以保持代码一致,比如:

gpiod_set_value(gpio, 1);  // 输出逻辑1// 在Active-High的情况下它会输出高电平// 在Active-Low的情况下它会输出低电平
  • Open Drain and Open Source

    有多个GPIO驱动同时驱动一个电路时,就需要设置Open Drain或Open Source。

    • Open Drain:引脚被设置为低电平时才会驱动电路,典型场景是I2C接口。

    • Open Source:引脚被设置为高电平时才会驱动电路

1.4 GPIO子系统的作用

管理GPIO,既能支持芯片本身的GPIO,也能支持扩展的GPIO。

提供统一的、简便的访问接口,实现:输入、输出、中断。

2. GPIO子系统层次与数据结构

2.1 GPIO子系统的层次

2.1.1 层次

2.1.2 GPIOLIB向上提供的接口

概述:向上接口主要有几类:获得GPIO,设置方向,读值写值,释放GPIO;

在Linux内核中,GPIOLIB 是一个通用的 GPIO (通用输入输出) 抽象层,它提供了一组 API 供驱动程序和用户空间程序使用。以下是 GPIOLIB 向上提供的主要接口及其说明:

  1. gpio_request:

    • 请求一个GPIO引脚。如果成功,内核将保留该引脚供请求者使用,并返回一个唯一的GPIO编号。
  2. gpio_free:

    • 释放一个之前请求的GPIO引脚,使其可供其他驱动程序使用。
  3. gpio_direction_input:

    • 将GPIO引脚配置为输入模式。
  4. gpio_direction_output:

    • 将GPIO引脚配置为输出模式,并可选地设置初始输出值。
  5. gpio_get_value:

    • 读取GPIO引脚的输入值。
  6. gpio_set_value:

    • 写入GPIO引脚的输出值。
  7. gpio_get_value_cansleep:

    • gpio_get_value类似,但此函数可以在睡眠上下文中使用。
  8. gpio_set_value_cansleep:

    • gpio_set_value类似,但此函数可以在睡眠上下文中使用。
  9. gpio_cansleep:

    • 检查对GPIO引脚的操作是否可以在睡眠上下文中执行。
  10. gpio_to_irq:

    • 将GPIO引脚转换为中断号,以便可以请求中断。
  11. irq_to_gpio:

    • 将中断号转换回GPIO引脚。
  12. gpiochip_add:

    • 注册一个gpio_chip结构体,它描述了一组GPIO引脚及其操作函数。
  13. gpiochip_remove:

    • 移除之前注册的gpio_chip
  14. gpiochip_line_config:

    • 配置gpio_chip中的特定引脚。
  15. gpiochip_request_own:

    • 请求对gpio_chip中的引脚的所有权。
  16. gpiochip_request_unown:

    • 释放对gpio_chip中的引脚的所有权。
  17. gpiochip_set:

    • gpio_chip中的多个引脚设置值。
  18. gpiochip_clear:

    • 清除gpio_chip中的多个引脚的值。
  19. gpiochip_set_direction:

    • gpio_chip中的多个引脚设置方向。
  20. gpiochip_get_direction:

    • 获取gpio_chip中引脚的方向。

这些接口为内核中的驱动程序提供了一种通用的方式来操作硬件GPIO引脚,同时隐藏了具体的硬件细节。此外,GPIOLIB 还提供了一些辅助函数,用于处理GPIO引脚的请求和释放,以及配置引脚的输入/输出模式。

2.1.3 GPIOLIB向下提供的接口

概述:获得引脚,释放引脚,配置引脚,读取\写入值,清除引脚,获取地址,获取标签(信息),配置中断

  1. chip.request:

    • 用于请求一个 GPIO 引脚。硬件驱动程序需要实现此函数来请求并分配一个 GPIO 引脚。
  2. chip.free:

    • 用于释放一个之前请求的 GPIO 引脚。硬件驱动程序需要实现此函数来释放并回收该引脚。
  3. chip.direction_input:

    • 配置 GPIO 引脚为输入模式。硬件驱动需要实现此函数来设置引脚方向。
  4. chip.direction_output:

    • 配置 GPIO 引脚为输出模式,并可设置初始输出值。硬件驱动需要实现此函数。
  5. chip.get:

    • 读取 GPIO 引脚的值。硬件驱动需要实现此函数来返回引脚的当前状态。
  6. chip.set:

    • 向 GPIO 引脚写入高电平。硬件驱动需要实现此函数来设置引脚状态。
  7. chip.clear:

    • 向 GPIO 引脚写入低电平。硬件驱动需要实现此函数来清除引脚状态。
  8. chip.set_config:

    • 配置 GPIO 引脚的参数,如上拉/下拉、驱动强度等。硬件驱动需要实现此函数。
  9. chip.to_irq:

    • 如果支持,将 GPIO 引脚转换为中断号。硬件驱动需要实现此函数。
  10. chip.dbg_show:

    • 用于调试目的,显示 GPIO 引脚的状态。硬件驱动可以提供此函数。
  11. chip.label:

    • 获取 GPIO 芯片的标签。硬件驱动需要提供此函数。
  12. chip.base:

    • 获取 GPIO 芯片的基地址,通常用于芯片注册。
  13. chip.ngpio:

    • 获取 GPIO 芯片支持的 GPIO 引脚数量。
  14. chip.parent:

    • 获取 GPIO 芯片的父设备,通常用于设备树集成。
  15. chip.of_node:

    • 获取 GPIO 芯片的设备树节点。
  16. chip.of_xlate:

    • 用于设备树中 GPIO 引脚的转换,硬件驱动需要实现此函数。

这些接口定义在 struct gpio_chip 结构体中,硬件平台的 GPIO 驱动程序需要填充这个结构体并实现相应的函数。这样,GPIOLIB 可以与底层硬件交互,而上层的驱动程序和应用程序则可以使用 GPIOLIB 提供的通用接口来操作 GPIO 引脚。

2.2 重要的3个核心数据结构

记住GPIO Controller的要素,这有助于理解它的驱动程序:

  • 一个GPIO Controller里有多少个引脚?有哪些引脚?

  • 需要提供函数,设置引脚方向、读取/设置数值

  • 需要提供函数,把引脚转换为中断

以Linux面向对象编程的思想,一个GPIO Controller必定会使用一个结构体来表示,这个结构体必定含有这些信息:

  • GPIO引脚信息

  • 控制引脚的函数

  • 中断相关的函数

2.2.1 gpio_device

每个GPIO Controller用一个gpio_device来表示:

  • 里面每一个gpio引脚用一个gpio_desc来表示

  • gpio引脚的函数(引脚控制、中断相关),都放在gpio_chip里

2.2.2 gpio_chip

我们并不需要自己创建gpio_device,编写驱动时要创建的是gpio_chip,里面提供了:

  • 控制引脚的函数

  • 中断相关的函数

  • 引脚信息:支持多少个引脚?各个引脚的名字?

(实现GPIOLIB向下提供的接口函数) 

 

2.2.3 gpio_desc 

我们去使用GPIO子系统时,首先是获得某个引脚对应的gpio_desc。

gpio_device表示一个GPIO Controller,里面支持多个GPIO。

在gpio_device中有一个gpio_desc数组,每一引脚有一项gpio_desc。

2.3  怎么编写GPIO Controller驱动程序

分配、设置、注册gpioc_chip结构体,示例:drivers\gpio\gpio-74x164.c

3. 编写一个虚拟GPIO控制器的驱动程序

概述:核心:分配/设置/注册一个gpio_chip结构体。

头文件支持,定义全局变量结构体指针chip()

定义一个全局变量用于模拟GPIO的

#include <linux/module.h>      // 模块化编程支持
#include <linux/err.h>         // 错误处理
#include <linux/init.h>        // 模块初始化和清理宏
#include <linux/io.h>          // IO操作
#include <linux/mfd/syscon.h>  // 系统控制
#include <linux/of.h>          // 设备树操作
#include <linux/of_device.h>    // 设备树设备操作
#include <linux/of_address.h>  // 设备树地址解析
#include <linux/gpio/consumer.h> // GPIO消费者
#include <linux/gpio/driver.h>  // GPIO驱动
#include <linux/slab.h>        // 内存分配
#include <linux/regmap.h>      // 寄存器映射static struct gpio_chip * g_virt_gpio; // 定义一个全局的gpio_chip指针
static int g_gpio_val = 0;             // 定义一个全局变量,用于模拟GPIO值

 定义设备树匹配表,设置GPIO属性->方向(输入和输出),获取GPIO的值,设置GPIO的值

// 设备树匹配表
static const struct of_device_id virtual_gpio_of_match[] = {{ .compatible = "100ask,virtual_gpio", },{ },
};// 设置GPIO方向为输出
static int virt_gpio_direction_output(struct gpio_chip *gc,unsigned offset, int val)
{printk("set pin %d as output %s\n", offset, val ? "high" : "low");return 0;
}// 设置GPIO方向为输入
static int virt_gpio_direction_input(struct gpio_chip *chip,unsigned offset)
{printk("set pin %d as input\n", offset);return 0;
}// 获取GPIO值
static int virt_gpio_get_value(struct gpio_chip *gc, unsigned offset)
{return (g_gpio_val & (1<<offset)) ? 1 : 0;
}// 设置GPIO值
static void virt_gpio_set_value(struct gpio_chip *gc,unsigned offset, int val)
{if (val)g_gpio_val |= (1 << offset);elseg_gpio_val &= ~(1 << offset);
}

 平台驱动探测函数:分配,设置(设置函数,设置值),注册(在内核中添加身份信息)

// 平台设备探测函数
static int virtual_gpio_probe(struct platform_device *pdev)
{int ret;printk(KERN_INFO "%s %s %d\n", __FILE__, __FUNCTION__, __LINE__);/* 1. 分配gpio_chip */g_virt_gpio = devm_kzalloc(&pdev->dev, sizeof(*g_virt_gpio), GFP_KERNEL);/* 2. 设置gpio_chip *//* 2.1 设置函数 */g_virt_gpio->label = pdev->name;g_virt_gpio->direction_output = virt_gpio_direction_output;g_virt_gpio->direction_input  = virt_gpio_direction_input;g_virt_gpio->get = virt_gpio_get_value;g_virt_gpio->set = virt_gpio_set_value;g_virt_gpio->parent = &pdev->dev;g_virt_gpio->owner = THIS_MODULE;/* 2.2 设置base、ngpio值 */g_virt_gpio->base = -1;ret = of_property_read_u32(pdev->dev.of_node, "ngpios", &g_virt_gpio->ngpio);/* 3. 注册gpio_chip */ret = devm_gpiochip_add_data(g_virt_gpio, NULL);return 0;
}

定义平台设备移除函数,定义虚拟GPIO驱动结构体,定义入口函数(注册平台驱动),出口函数(反注册平台驱动),

// 平台设备移除函数
static int virtual_gpio_remove(struct platform_device *pdev)
{printk(KERN_INFO "%s %s %d\n", __FILE__, __FUNCTION__, __LINE__);return 0;
}// 虚拟GPIO驱动结构体
static struct platform_driver virtual_gpio_driver = {.probe = virtual_gpio_probe,.remove = virtual_gpio_remove,.driver = {.name = "100ask_virtual_gpio",.of_match_table = of_match_ptr(virtual_gpio_of_match),}
};/* 1. 入口函数 */
static int __init virtual_gpio_init(void)
{    printk(KERN_INFO "%s %s %d\n", __FILE__, __FUNCTION__, __LINE__);/* 1.1 注册一个platform_driver */return platform_driver_register(&virtual_gpio_driver);
}/* 2. 出口函数 */
static void __exit virtual_gpio_exit(void)
{printk(KERN_INFO "%s %s %d\n", __FILE__, __FUNCTION__, __LINE__);/* 2.1 反注册platform_driver */platform_driver_unregister(&virtual_gpio_driver);
}module_init(virtual_gpio_init);
module_exit(virtual_gpio_exit);MODULE_LICENSE("GPL");

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

4.1 使用GPIO前应该设置Pinctrl

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

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

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

virtual_pincontroller {compatible = "100ask,virtual_pinctrl";myled_pin: myled_pin {functions = "gpio";groups = "pin0";configs = <0x11223344>;};
};gpio_virt: virtual_gpiocontroller {compatible = "100ask,virtual_gpio";gpio-controller;#gpio-cells = <2>;ngpios = <4>;
};myled {compatible = "100ask,leddrv";led-gpios = <&gpio_virt 0 GPIO_ACTIVE_LOW>;pinctrl-names = "default";pinctrl-0 = <&myled_pin>;	
};

这段代码包含了三个主要部分,分别定义了三个不同的设备节点,它们在设备树(Device Tree)中用于描述硬件设备的配置和它们之间的关系。以下是对每个部分的解释:

  1. virtual_pincontroller 节点

    • compatible 属性指定了设备的兼容字符串,用于确定使用哪个驱动程序。
    • myled_pin 是一个子节点,代表一个具体的引脚配置。
    • functions 属性定义了引脚的复用功能,这里是 "gpio",表示该引脚被用作通用输入输出。
    • groups 属性指定了引脚组,这里是 "pin0"。
    • configs 属性提供了引脚的配置参数,这里使用了一个32位的十六进制数 0x11223344
  2. gpio_virt 节点

    • 同样使用 compatible 属性来指定驱动程序。
    • gpio-controller 表示这是一个GPIO控制器。
    • #gpio-cells 属性定义了每个GPIO引脚需要多少个单元来描述,这里是 <2>,通常表示一个单元用于GPIO号,另一个用于标志。
    • ngpios 属性定义了控制器拥有的GPIO引脚数量,这里是 <4>,表示有4个GPIO引脚。
    • 这个节点可能与 virtual_pincontroller 节点相关联,用于控制引脚的GPIO功能。
  3. myled 节点

    • compatible 属性指定了LED驱动的兼容字符串。
    • led-gpios 属性定义了控制LED的GPIO引脚,格式为 <&gpio_virt 0 GPIO_ACTIVE_LOW>,表示使用 gpio_virt 控制器的第0号引脚,且为低电平有效。
    • pinctrl-names 和 pinctrl-0 属性用于指定引脚控制的名称和默认配置,这里引用了 myled_pin 节点。

设备树节点之间的关系:

  • gpio_virt 节点定义了一个GPIO控制器,它可能控制着一些物理或虚拟的GPIO引脚。
  • myled 节点定义了一个LED设备,它使用 gpio_virt 控制器的第0号引脚来控制LED的开关。
  • virtual_pincontroller 节点定义了一个虚拟的引脚控制器,它可能用于更复杂的引脚控制逻辑,比如配置引脚的复用功能、配置参数等。

代码作用:

  • 这段设备树配置告诉内核如何初始化和配置相关的硬件设备,特别是如何将特定的GPIO引脚配置为控制LED,并指定了引脚的其他配置参数。
  • 当内核启动时,它将解析设备树中的这些节点,并根据这些信息加载相应的驱动程序,初始化硬件设备。

在嵌入式Linux系统中,设备树是一种重要的机制,用于描述硬件设备的配置,特别是在没有BIOS或UEFI等传统固件的情况下。设备树允许内核以一种硬件无关的方式来初始化和控制硬件设备。

但是很多芯片,并不要求在设备树中把把引脚复用为GPIO功能。

比如STM32MP157,在它的设备树工具STM32CubeMX即使把引脚配置为GPIO功能,它也不会在设备树中出现。

原因在于:GPIO走了后门。

现实的芯片中,并没有Pinctrl这样的硬件,它的功能大部分是在GPIO模块中实现的。

Pinctrl是一个软件虚拟处理的概念,它的实现本来就跟GPIO密切相关。

甚至一些引脚默认就是GPIO功能。

按理说:

一个引脚可能被用作GPIO,也可能被用作I2C,GPIO和I2C这些功能时相同低位的。

要用作GPIO,需要先通过Pinctrl把引脚复用为GPIO功能。

但是Pinctrl和GPIO关系密切,当你使用gpiod_get获得GPIO引脚时,它就偷偷地通过Pinctrl把引脚复用为GPIO功能了。

4.2 GPIO和Pinctrl的映射关系

从上图可知:

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

  • 图中有2个GPIO控制器

    • GPIO0内部引脚编号为0~3,假设在GPIO子系统中全局编号为100~103

    • GPIO1内部引脚编号为0~3,假设在GPIO子系统中全局编号为104~107

  • 假设我们要使用pin1_1,应该这样做:

    • 根据GPIO1的内部编号1,可以换算为Pinctrl子系统中的编号5

    • 使用Pinctrl的函数,把第5个引脚配置为GPIO功能

数据结构

 

4.3 GPIO调用Pinctrl的过程

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

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

调用关系如下:

gpiod_getgpiod_get_indexdesc = of_find_gpio(dev, con_id, idx, &lookupflags);ret = gpiod_request(desc, con_id ? con_id : devname);ret = gpiod_request_commit(desc, label);if (chip->request) {ret = chip->request(chip, offset);}

这段代码片段是Linux内核中使用GPIO描述符(gpiod)API处理GPIO线的一部分。这个API用于以更抽象的方式处理GPIO,允许更好的硬件抽象,使跨不同硬件平台的GPIO操作变得更容易。以下是每个函数的作用详解:。

- `gpiod_get_index` 函数可能是获取特定索引GPIO线GPIO描述符的包装器或过程的一部分。
- `of_find_gpio` 函数使用设备树根据设备和连接ID找到GPIO描述符。
- `gpiod_request` 函数使用描述符请求GPIO线,并为GPIO线的使用请求一个标签。
- `gpiod_request_commit` 函数提交GPIO请求,使GPIO线准备好使用。
- 如果GPIO芯片有一个自定义的请求函数 (`chip->request`),这里会调用它来执行任何必要的硬件特定设置。

这段代码片段是通常涉及配置GPIO线(例如,将其设置为输入或输出,配置上拉/下拉电阻等)并然后用于其预定目的(例如,从传感器读取输入,驱动LED等)的更大过程中的一部分。确切的实现细节可以根据硬件平台和正在使用的GPIO线的具体要求而有所不同。
 

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

gpiochip_generic_request(struct gpio_chip *chip, unsigned offset)pinctrl_request_gpio(chip->gpiodev->base + offset)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);

代码流程解释:

  • gpiochip_generic_request 函数被调用以请求一个GPIO。
  • pinctrl_request_gpio 函数使用设备的基地址和GPIO偏移量来计算全局GPIO编号。
  • pinctrl_get_device_gpio_range 函数根据全局GPIO编号获取引脚控制器设备和GPIO的编号范围。
  • 通过gpio_to_pin将全局GPIO编号转换为引脚控制器的编号空间。
  • pinmux_request_gpio 函数请求引脚复用,确保引脚可以被用作所需的功能。
  • pin_request 函数在引脚控制器中实际请求引脚,保留它并标记为已使用。

这个过程是Linux内核中处理GPIO请求的标准方式,确保了在不同硬件平台上对GPIO的请求是统一和一致的。通过这种方式,驱动程序可以请求和使用GPIO,而不必担心底层硬件的具体细节。

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 there is no kind of request function for the pin we just assume* we got it by default and proceed.*/if (gpio_range && ops->gpio_request_enable)/* This requests and enables a single GPIO pin */status = ops->gpio_request_enable(pctldev, gpio_range, pin);else if (ops->request)status = ops->request(pctldev, pin);elsestatus = 0;
}

这段代码是一个名为 pin_request 的静态函数,它的作用是请求(reserve)一个特定的引脚(pin),以供驱动程序或其他用途使用。

这个 pin_request 函数是引脚控制子系统中的一个关键组件,它确保了对特定引脚的独占访问,防止多个驱动程序同时使用同一个引脚。这是嵌入式系统和硬件抽象中常见的需求,特别是在多个硬件设备可能需要使用相同物理引脚的情况下。

相关文章:

GPIO子系统

1. GPIO子系统视频概述 1.1 GPIO子系统的作用 芯片内部有很多引脚&#xff0c;这些引脚可以接到GPIO模块&#xff0c;也可以接到I2C等模块。 通过Pinctrl子系统来选择引脚的功能(mux function)、配置引脚&#xff1a; 当一个引脚被复用为GPIO功能时&#xff0c;我们可以去设…...

学会这个Python库,接口测试so easy

前言 我们在做接口测试时&#xff0c;大多数返回的都是json属性&#xff0c;我们需要通过接口返回的json提取出来对应的值&#xff0c;然后进行做断言或者提取想要的值供下一个接口进行使用。 但是如果返回的json数据嵌套了很多层&#xff0c;通过查找需要的词&#xff0c;就…...

Stable Diffusion4.8.7(Ai绘画)软件安装教程

软件下载 [名称]&#xff1a;Stable Diffusion4.8.7&#xff08;Ai绘画&#xff09; [大小]&#xff1a;16.52GB [语言]&#xff1a;简体中文 [安装环境]&#xff1a;Win11/Win10/Win8/Win7 [硬件要求]&#xff1a;CPU2.0GHz &#xff0c;内存4G&#xff08;或更高&#x…...

操作系统错误处理

错误处理 1、通过函数的返回值表示执行错误&#xff1a; // 返回合法值表示成功 返回非法值表示失败 // 计算大小、查找 long file_size(const char* path) {FILE* fp fopen(path,"r");if(NULL fp)return -1; // 返回非法值fseek(fp,SEEK_END,0);long size …...

【靶场实操】sql-labs通关详解----第一节:基础注入方式(Less-1~Less-10)

目录 一、注入方式简要概括 1.1 SQL常见注入方式 1.2 爆破函数 二、靶场实操 2.1 Less-1 2.1.1 判断类型 2.1.2 联合注入查询 2.2 Less-2 2.2.1 判断类型 2.2.2 注入攻击 2.2.3 字符型与数字型漏洞对比 2.3 Less-3 2.3.1 判断 2.3.2 注入 2.4 Less-4 2.4.1 判断…...

力扣676.实现一个魔法字典

力扣676.实现一个魔法字典 字典树 dfs class Trie{public:Trie* next[26];bool is_end false;};class MagicDictionary {public:Trie* root new Trie();void add(string& word){Trie* p root;for(char c:word){if(p->next[c-a] NULL) p->next[c-a] new Trie…...

ctfshow-web入门-sql注入(web171-web175)

目录 1、web171 2、web172 3、web173 4、web174 5、web175 1、web171 单引号测一下&#xff0c;报错 -- 闭合后回显正常 也可以用 # &#xff0c;不过需要 URL 编码 成功闭合之后&#xff0c;先判断下字段数&#xff1a; 1 order by 3-- 3 的时候正常 4 的时候报错&am…...

视频怎么添加音乐?分享5种视频添加音乐方法

在如今火爆的短视频时代&#xff0c;为视频添加合适的背景音乐&#xff0c;无疑是让其脱颖而出的关键一步。无论是打造个人Vlog、纪录片&#xff0c;还是创意短片&#xff0c;音乐都能赋予视频独特的情感与氛围。那么怎么给视频添加上背景音乐呢&#xff1f;给大家分享5种简单的…...

黑马JavaWeb后端案例开发(包含所有知识点!!!)

目录 1.准备工作 环境搭建 开发规范 REST&#xff08;REpresentation State Transfer&#xff09;,表述性状态转换&#xff0c;它是一种软件架构风格 注意事项 统一响应结果 2.部门管理功能 查询部门 删除部门 新增部门 RequestMapping 3.员工管理功能 分页查询 批…...

FPGA开发——蜂鸣器实现音乐播放器的设计

一、概述 我们在进行蜂鸣器的学习的时候&#xff0c;总会在想既然蜂鸣器能够发出声音&#xff0c;那么它能够播放音乐吗&#xff0c;今天这篇我们文章我们就一起来学习怎样使用使用蜂鸣器来播放音乐&#xff0c;也就是怎样成为一个音乐播放器。 1、蜂鸣器的类型 在设计的时候…...

InnoDB存储引擎(1)

InnoDB存储引擎的优点 InnoDB在设计时考虑到了处理大数据量时的性能&#xff0c;支持事务&#xff0c;回滚和崩溃修复的能力&#xff0c;通过多版本并发控制来减少锁定(降低了锁的争用),同时还支持外键的约束&#xff1b;通过缓冲池在内存中缓存数据来提高查询的性能&#xff…...

VMWare虚拟机共享主机的网络访问外网

1.主机中启动客户端并连接外网 2.设置虚拟网络类型为NAT 3.启动虚拟并通过主机访问外网...

LeetCode Easy|【415. 字符串相加】

力扣题目链接 题目本身难度不大&#xff0c;但是后续的一些补充内容还是值得搞清楚的 主要的逻辑如下&#xff1a; 其实本题的目的就是让我们来模拟我们的竖式加法。所以很直观的一个想法就是使用双指针&#xff1a;分别指向两个 num 的末尾。随后就会产生一些问题&#xff1a…...

RAG 革命:NVIDIA 工作站如何成为企业 AI 的秘密武器

在深圳的一家科技初创公司&#xff0c;首席技术官李梅正在向她的团队展示一个令人兴奋的新项目。“看这个&#xff0c;” 她指着屏幕上的实时演示说&#xff0c;“我们刚刚用公司的技术文档训练了一个 AI 助手&#xff0c;它现在可以回答任何关于我们产品的问题&#xff0c;而且…...

九大原则,轻松构建个人高效SOP

1、原则一、工作汇报SOP SCQA模型(升职加薪的关键!&#xff09; 清晰定义问题和提出解决方案 类别 关键词 解读 S - Situation 情景 陈述项目背景&#xff0c;目标&#xff0c;愿景 C - Complication 冲突 讲卡点&#xff0c;讲冲突 Q - Question 疑问-问题 这些冲…...

Airtest的demo实现多设备并行

Airtest的demo实现多设备并行 它实现是的获取adb连接上的所有设备&#xff0c;然后在每一台设备上跑给定的测试用例&#xff0c;跑完之后生成单机的测试报告&#xff0c;最后再汇总这些单机测试报告的结果&#xff0c;形成汇总&#xff08;聚合&#xff09;报告&#xff1a; 同…...

社区养老服务小程序的设计

管理员账户功能包括&#xff1a;系统首页&#xff0c;个人中心&#xff0c;用户管理&#xff0c;服务人员管理&#xff0c;服务产品管理&#xff0c;服务预约管理&#xff0c;服务状态管理&#xff0c;服务退订管理&#xff0c;活动管理&#xff0c;视频管理 微信端账号功能包…...

Interceptor拦截器开发

因为1登录后的接口都需要token验证代码,会出现重复代码;2当前的接口不防刷,会被恶意攻击 所以在controller层增加请求拦截,如果你的token不合法,就不让你做后续的处理了 拦截器的作用是什么 作用: 1、对controller层代码的访问进行拦截,合法的请求,那此层代码就处理,反…...

美团 AIGC产品经理面经(已拿 offer)

背景&#xff1a;211本科毕业&#xff0c;毕业之后在北京一家中型电商公司做了3年商家后台产品经理&#xff0c;目前通过老薛的朋友关系拿到了美团的offer。 目前还有几家在面试流程中&#xff0c;继续加油&#x1f4aa; 美团AIGC产品面经-业务面 &#x1f4a5;1、自我介绍&a…...

@RequestBody与@RequestParam

RequestBody会将请求体中的数据&#xff0c;转换成对象.最主要的是RequestBody就是要返回Json的字符串&#xff01;&#xff01;&#xff01; RequestParam会从http请求查询参数中提取数据&#xff01; RequestParam和RequestBody是Spring Framework中用于处理HTTP请求的注解…...

vmware上,虚机经常丢失网卡。导致无法上网。

1、winR 输入 services.msc 2、重启这两个服务。 VMware NAT service和VMware DHCP service...

git 鉴权失败

这条错误信息通常出现在使用Git进行远程操作时&#xff0c;比如克隆仓库、拉取更新或推送代码。错误的含义是&#xff1a; HTTP Basic: Access denied&#xff1a;访问被拒绝。The provided password or token is incorrect&#xff1a;提供的密码或令牌不正确。Your account …...

[C++] 容器适配器:深入理解Stack与Queue的底层原理

文章目录 容器适配器简介deque的缺陷为什么使用deque作为stack和queue的底层默认容器 stack和queue的简单讲解Stack&#xff08;栈&#xff09;栈的操作图示栈的相关接口 Queue&#xff08;队列&#xff09; Stack和Queue的模拟实现Stack&#xff08;栈&#xff09;作为容器适配…...

Eclipse maven 的坑

在使用 eclipse 时&#xff0c; eclipse 的右下角 一直在提示 “JPA java change event handler” &#xff0c;eclipse使用起来很卡&#xff0c;解决办法 问题描述&#xff1a; 在使用 eclipse时&#xff0c; eclipse 的右下角 一直在提示 “JPA java change event handler”…...

多模态视觉大语言模型——LLaVA

论文题目:Visual Instruction Tuning 论文地址:https://arxiv.org/abs/2304.08485 github: https://github.com/haotian-liu/LLaVA 1. Abstract 本文首次尝试使用GPT-4生成多模态指令数据,并基于这些数据训练了LLaVA(Large Language and Vision Assistant)模型,这是一种结…...

服务注册到nacos上,不能点击下线的问题处理

nacos不能下线&#xff1a; 修改 /usr/local/mid/nacos/data 文件夹下 protocol 文件重命名为 protocol_bak&#xff0c;然后再重启nacos nacos单机启动命令&#xff1a;cd sh startup.sh -m standalone nginx启动命令&#xff1a;cd /usr/local/mid/nginx/sbin ./…...

未来3-5年,哪些工作会被AI取代

一篇由高盛经济学家约瑟夫布里格斯 &#xff08;Joseph Briggs&#xff09;和德维西科德纳尼 &#xff08;Devesh Kodnani&#xff09;撰写的报告指出&#xff0c;全球预计将有3亿个工作岗位被生成式AI取代。 报告称&#xff1a;“最近出现的生成式人工智能将降低劳动力成本和…...

鸿蒙系统开发【网络管理】

网络管理 介绍 此Demo展示如何查询网络详情、域名解析、网络状态监听等功能。 效果预览&#xff1a; 使用说明&#xff1a; 1.启动应用&#xff0c;在点击检查网络、网络详情、网络连接信息后&#xff0c;展示对应的信息&#xff1b; 2.在域名解析的模块下&#xff0c;输入…...

nginx如何处理请求

nginx如何处理请求 注&#xff1a;内容翻译自Nginx官网文档 How nginx processes a request。 基于名称的虚拟服务器 nginx首先要决定哪个服务器应该处理请求。让我们从一个简单的配置开始&#xff0c;三个虚拟服务器都监听在端口*:80: server {listen 80;server_name e…...

换地不换IP?揭秘微博IP地址的奥秘

在这个信息飞速传递的时代&#xff0c;社交媒体成为我们生活中不可或缺的一部分。微博&#xff0c;作为其中的佼佼者&#xff0c;不仅是我们获取资讯的重要渠道&#xff0c;也是展现自我、分享生活的重要平台。然而&#xff0c;你有没有遇到过这样的情况&#xff1a;明明已经换…...

免费做试用的网站/seo是什么意思呢

点击左上方蓝字关注我们 开放域问答&#xff08;Open-domain QA&#xff09;一直是自然语言处理领域的重要研究课题。百度从面向端到端问答的检索模型出发&#xff0c;提出了RocketQA训练方法&#xff0c;大幅提升了对偶式检索模型的效果&#xff0c;为实现端到端问答迈出了重要…...

网站制作中文版/百度关键词搜索次数

原题地址&#xff1a;http://oj.leetcode.com/problems/insertion-sort-list/ 题意&#xff1a;对链表进行插入排序。 解题思路&#xff1a;首先来对插入排序有一个直观的认识&#xff0c;来自维基百科。 代码循环部分图示&#xff1a; 代码&#xff1a; class Solution: # par…...

宁波企业自助建站系统/线上推广策划方案范文

由于浏览器的安全限制&#xff0c;网络连接的跨域访问时不被允许的&#xff0c;当然其中也包括了XmlHttpRequest。但是&#xff0c;有些时候我们需要通过跨域访问来获取一些资源&#xff0c;例如&#xff1a; 作为用户&#xff0c;我们需要在自己的网站用AJAX调用一些其他网站提…...

天津品牌网站建设公司/安卓优化大师

你以前更新Lync 2010 KB如何更新?你现在更新Lync 2013 KB如何更新?如果你使用Windows更新&#xff0c;那就不用向下面看了。如果你使用SCCM更新&#xff0c;那你也不用向下面看了。如果你是手动更新&#xff0c;那就千万注意以下的过程了&#xff0c;否则&#xff0c;吃亏的是…...

张家港手机网站建设/太原高级seo主管

一.apt-getapt-get是一条linux命令&#xff0c;适用于deb包管理式的操作系统&#xff0c;主要用于自动从互联网的软件仓库中搜索、安装、升级、卸载软件或操作系统。什么是apt-get编辑是debian&#xff0c;ubuntu发行版的包管理工具&#xff0c;与红帽中的yum工具非常类似。apt…...

网站开发论坛/百度总部

CSS left 属性 CSS 参考手册 实例 把图像的左边缘设置在其包含元素左边缘向右 100 像素的位置&#xff1a; img{position:absolute;left:100px;}亲自试一试 浏览器支持 所有主流浏览器都支持 left 属性。 注释&#xff1a;任何的版本的 Internet Explorer &#xff08;包括 IE8…...