Linux第73步_学习Linux设备树和“OF函数”

掌握设备树是 Linux驱动开发人员必备的技能

1、了解设备树文件

在3.x版本以前的Linux内核源码中,存在大量的“arc/arm/mach-xxx”和“arc/arm/plat-xxx”文件夹,里面很多个“.c”和“.h”文件,它们用来描述设备信息。而现在的ARM架构是采用“设备树”来描述设备信息。“设备树”英文名字叫“Device Tree”。描述设备树的文件叫做“DTS”,是Device Tree Source的缩写。它主要用来描述板子上有哪些设备构成,如:I2C控制器、GPIO控制器、SPI控制器、UART控制器等。

设备树源文件扩展名为“.dts”,设备树头文件扩展名为“.dtsi”,它们经过DTC工具编译后生成的二进制文件,就是“.dtb”文件。

“.dts”设备树文件可以通过“#include”来引用“.h”、“.dtsi”和“.dts”文件。在编写设备树头文件时,我们最好选择“.dtsi”作为后缀。

一般“.dtsi”文件用于描述芯片的“内部外设信息”,比如CPU架构、主频、外设寄存器地址范围,如:UART、IIC、SPI、TIMER等等。

2、了解节点

设备树是描述板子上的“设备信息”的文件,均采用“树形结构”。每个设备树文件只有一个“根节点”,而“不同设备树文件的根节点”会合在一起形成一个根节点。每个设备都是一个节点,称之为“设备节点”,每个节点都采用“属性信息”来描述其“节点信息”。

认识“标准属性”、“节点”和“节点标签”,见下图:

标准属性

1)、compatiable属性,也叫兼容性属性。

如:compatible = "cirrus,cs42l51";

这个compatible只有一个属性值,就是“cirrus,cs42l51”,其中“cirrus”表示厂商,“cs42l51”表示驱动模块。

再如:compatible = "cirrus,cs42l51","cirrus,My_cs42l51";

这个compatible就有两个属性值,就是“cirrus,cs42l51”和"cirrus,My_cs42l51",其中“cirrus”表示厂商,“cs42l51”表示驱动模块,“My_cs42l51”表示驱动模块。

驱动文件的“OF匹配表”

const struct of_device_id cs42l51_of_match[] = { { .compatible = "cirrus,cs42l51", },{ }};

设备首先会使用第一个兼容值在Limux内核里面查找。看看能不能找到与之匹配的驱动文件,如果没有找到,就使用第二个兼容值查,以此类推,直到查找完 commpatible属性中的所有值。

compatible属性用于将设备和驱动绑定起来。驱动程序文件有一个“OF匹配表”,这个“OF匹配表”保存着一些compatible的值,如果设备节点的compatible属性值和“OF匹配表”中的任何一个值相等,那么这个设备就可以使用这个驱动。

2)、model属性

用于描述开发板的名字或设备模块的信息。

比如:model = "STMicroelectronics STM32MP157C-DK2 Discovery Board";

3)、status属性

status属性值

描述

okay

表明设备是可操作的

disabled

表明设备当前是不可操作的,但是在未来可以变为可操作的,比如:热插拔设备插入以后。至于disabled的具体含义还要看设备的绑定文档。

fail

表明设备不可操作,设备检测到了一系列的错误,而且设备也不大可能变得可操作。

fail-sss

含义和“fai1”相同,后面的“sss部分”是检测到的错误内容。

4)、reg属性

reg属性的值一般是(address,length)对。

reg 属性一般用于描述“设备地址空间资源信息”或者“设备地址信息”,比如某个外设的“寄存器地址范围信息”,或者I2C器件的设备地址等。

5)、ranges属性

ranges = <child-bus-address,parent-bus-address,length>;

child-bus-address表示“子总线地址空间的物理地址”;

parent-bus-address表示“父总线地址空间的物理地址”;

length表示“子总线地址空间的长度”;

若ranges属性值为空,则说明子地址空间和父地址空间完全相同;

6)、“#address-cells”和“#size-cells”属性

#address-cells的属性值为无符号32位整型,用于描述子节点的“reg和ranges”中的address所占的位数,1表示32位,2表示64位;

#size-cells的属性值为无符号32位整型,用于描述子节点的“reg和ranges”中的length所占的位数,0表示没有位数,1表示32位,2表示64位;

举例说明“reg、 #address-cells和#size-cells”属性:

cpus {   #address-cells = <1>;//表示子节点cpureg和rangesaddress占32个位

   #size-cells = <0>;   //表示子节点cpureg和rangeslength占0个位   cpu0: cpu@0 {      compatible = "arm,cortex-a7";      device_type = "cpu";      reg = <0>;        //表示addres=0, 没有length,和前面定义一致

      clocks = <&scmi0_clk CK_SCMI0_MPU>;      clock-names = "cpu";      operating-points-v2 = <&cpu0_opp_table>;      nvmem-cells = <&part_number_otp>;       nvmem-cell-names = "part_number";       #cooling-cells = <2>;    }; };

scmi_sram: sram@2ffff000 {   compatible = "mmio-sram";   reg = <0x2ffff000 0x1000>//表示address=0x2ffff000,length=0x1000

   #address-cells = <1>;//表示scmi_shmreg和rangesaddress占32个位

   #size-cells = <1>;   //表示scmi_shmreg和rangeslength占32个位

   ranges = <0 0x2ffff000 0x1000>;  //分别为32位,和前面定义一致

   scmi0_shm: scmi_shm@0 {      reg = <0 0x80>;    //reg的address和length分别为32位,和前面定义一致

   };

};

soc {

   compatible = "simple-bus";   #address-cells = <1>; //表示sramreg和rangesaddres长度为32个位   #size-cells = <1>;    //表示sramreg和rangeslength长度为32个位

   interrupt-parent = <&intc>;   ranges = <0 0x10000000 0x100000>;

   sram: sram@10000000 {      compatible = "mmio-sram";      reg = <0x0 0x60000>;//reg的address和length均为32位,和前面定义一致

      #address-cells = <1>;      #size-cells = <1>;      ranges = <0 0x10000000 0x60000>;  //均为32位,和前面定义一致

   };};

以STM32MP157为例,创建设备树文件myfrst.dts ,要求在设备树里面的内容如下:

1)、芯片是由两个Cortex-A7 架构的32位CPU和Cortex-M4组成。

2)、STM32MP157内部sram,起始地址为 0x10000000,大小为384KB(0x60000)。

先搭建 “根节点框架”,如下:

/{   compatible = "st,stm32mp157d-atk", "st,stm32mp157"; };

接着添加cpus节点,如下:

/{   compatible = "st,stm32mp157d-atk", "st,stm32mp157";   cpus{

     #address-cells = <1>;//表示子节点cpureg和rangesaddress占32个位

     #size-cells = <0>;   //表示子节点cpureg和rangeslength占0个位

   };

 };

接着添加cpu0节点,如下:

/{   compatible = "st,stm32mp157d-atk", "st,stm32mp157";   cpus{

     #address-cells = <1>;//表示子节点cpureg和rangesaddress占32个位

     #size-cells = <0>;   //表示子节点cpureg和rangeslength占0个位

      cpu0: cpu@0 {        compatible = "arm,cortex-a7";        device_type = "cpu";        reg = <0>;        //表示addres=0, 没有length,和前面定义一致

     };

   };

 };

接着添加cpu1节点,如下:

/{   compatible = "st,stm32mp157d-atk", "st,stm32mp157";   cpus{

     #address-cells = <1>;//表示子节点cpu的reg和ranges的address占32个位

     #size-cells = <0>;   //表示子节点cpureg和rangeslength占0个位

      cpu0: cpu@0 {        compatible = "arm,cortex-a7";        device_type = "cpu";        reg = <0>;        //表示addres=0, 没有length,和前面定义一致

     };

      cpu1: cpu@1 {        compatible = "arm,cortex-m4";        device_type = "cpu";        reg = <1>;        //表示addres=1, 没有length,和前面定义一致

     };

   };

 };

接着添加soc节点,如下:

/{   compatible = "st,stm32mp157d-atk", "st,stm32mp157";   cpus{

     #address-cells = <1>;//表示子节点cpureg和rangesaddress占32个位

     #size-cells = <0>;   //表示子节点cpureg和rangeslength占0个位

      cpu0: cpu@0 {        compatible = "arm,cortex-a7";        device_type = "cpu";        reg = <0>;        //表示addres=0, 没有length,和前面定义一致

     };

      cpu1: cpu@1 {        compatible = "arm,cortex-m4";        device_type = "cpu";        reg = <1>;        //表示addres=1, 没有length,和前面定义一致

     };

   };

   soc {

      compatible = "simple-bus";      #address-cells = <1>; //表示sramreg和rangesaddres长度为32个位      #size-cells = <1>;    //表示sramreg和rangeslength长度为32个位

      ranges; //说明子地址空间和父地址空间完全相同;

   };

 };

接着添加sram节点,如下:

/{   compatible = "st,stm32mp157d-atk", "st,stm32mp157";   cpus{

     #address-cells = <1>;//表示子节点cpureg和rangesaddress占32个位

     #size-cells = <0>;   //表示子节点cpureg和rangeslength占0个位

      cpu0: cpu@0 {        compatible = "arm,cortex-a7";        device_type = "cpu";        reg = <0>;        //表示addres=0, 没有length,和前面定义一致

     };

      cpu1: cpu@1 {        compatible = "arm,cortex-m4";        device_type = "cpu";        reg = <1>;        //表示addres=1, 没有length,和前面定义一致

     };

   };

   soc {

      compatible = "simple-bus";      #address-cells = <1>; //表示sramreg和rangesaddres长度为32个位      #size-cells = <1>;    //表示sramreg和rangeslength长度为32个位

      ranges; //说明子地址空间和父地址空间完全相同;

      

      sram: sram@10000000 {        compatible = "mmio-sram";        reg = <0x0 0x60000>;//address和length均为32位,和前面定义一致

        ranges = <0 0x10000000 0x60000>;  //均为32位,和前面定义一致

     };

   };

 };

3、了解特殊节点

1)、aliases子节点

aliases {

   serial0 = &uart4;  //给&uart4起个别名叫“serial0”

};

2)、chosen子节点

chosen不是一个真实的设备,chosen节点主要是为了uboot向 Linux内核传递数据。

chosen {

   stdout-path = "serial0:115200n8";

//设置“stdout-path”属性,表示标准输出使用“serial0

};

4、学习“OF函数”

“OF函数原型”都定义在“include/linux/of.h”文件中。

1)、了解相关结构体

Linux内核使用device_node结构体来描述一个节点。

struct device_node {

const char *name;  /*节点名字*/

phandle phandle;

const char *full_name;  /*节点全名*/

struct fwnode_handle fwnode;

struct property *properties; /*属性*/

struct property *deadprops; /* removed properties */

struct device_node *parent; /*父节点*/

struct device_node *child;  /*子节点*/

struct device_node *sibling;

#if defined(CONFIG_OF_KOBJ)

struct kobject kobj;

#endif

unsigned long _flags;

void *data;

#if defined(CONFIG_SPARC)

unsigned int unique_id;

struct of_irq_controller *irq_trans;

#endif

};

Linux内核中使用结构体property表示属性

struct property {

char *name;           /*属性名字*/

int length;              /*属性长度*/

void *value;          /*属性值*/

struct property *next;  /*下一个属性*/

#if defined(CONFIG_OF_DYNAMIC) || defined(CONFIG_SPARC)

unsigned long _flags;

#endif

#if defined(CONFIG_OF_PROMTREE)

unsigned int unique_id;

#endif

#if defined(CONFIG_OF_KOBJ)

struct bin_attribute attr;

#endif

}

resource结构体定义在文件 include/linux/ioport.h中。

struct resource {

resource_size_t start;   /*开始地址,占32位*/

resource_size_t end;     /*结束地址,占32位*/

const char *name;        /*资源的名字*/

unsigned long flags;     /*资源标志或资源类型*/

unsigned long desc;

struct resource *parent, *sibling, *child;

};

2)、通过节点的名字查找指定的节点:

struct device_node *of_find_node_by_name(struct device_node *from, const char *name)

from:开始查找的节点,如果为NULL,表示从根节点开始查找整个设备树。
name:要查找的节点名字。
返回值:返回找到的节点,如果为NULL,表示查找失败。

3)、通过device_type属性查找指定的节点

struct device_node *of_find_node_by_type(struct device_node *from, const char *type)

from:开始查找的节点,如果为NULL,表示从根节点开始查找整个设备树;

type:要查找的节点对应的type字符串,也就是 device_type属性值。

返回值:返回找到的节点,如果为NULL,表示查找失败。

4)、根据device_type属性和compatible属性查找指定的节点

struct device_node *of_find_compatible_node(struct device_node *from, const char *type, const char *compatible)

from:开始查找的节点,如果为NULL,表示从根节点开始查找整个设备树;

type:要查找的节点对应的type字符串,也就是device_type属性值。若为NULL,则可忽略掉device_type属性值;

compatible:要查找的节点所对应的compatible 属性列表;

返回值:返回找到的节点,如果为NULL,表示查找失败。

5)、通过of_device_id匹配表来查找指定的节点

struct device_node *of_find_matching_node_and_match(struct device_node *from, const struct of_device_id *matches, const struct of_device_id **match)

from:开始查找的节点,如果为NULL,表示从根节点开始查找整个设备树。matches: of_device_id匹配表,也就是在此匹配表里面查找节点。

match:找到的匹配的of_device_id

返回值:返回找到的节点,如果为NULL,表示查找失败。

6)、通过路径来查找指定的节点

inline struct device_node *of_find_node_by_path(const char *path)

path:带有全路径的节点名,可以使用节点的别名,比如“/backlight”就是 backlight 这个节点的全路径。

返回值:返回找到的节点,如果为NULL,表示查找失败。

7)、获取指定节点的父节点

struct device_node *of_get_parent(const struct device_node *node)

node:要查找的父节点的节点名称。返回值: 返回找到的父节点。

8)、采用迭代方式查找子节点,即查找“prev”的下一个节点。

struct device_node *of_get_next_child(const struct device_node *node, struct device_node *prev)

node:父节点。

prev:前一个子节点,也就是从哪一个子节点开始迭代的查找下一个子节点。若设置为NULL,则表示从第一个子节点开始。

返回值: 返回找到的下一个子节点。

9)、查找指定的属性

property *of_find_property(const struct device_node *np, const char *name, int *lenp)

np:设备节点。

name:属性名字。

lenp:属性值的字节数

返回值:返回找到的属性。

10)、获取属性中元素的数量

int of_property_count_elems_of_size(const struct device_node *np, const char *propname, int elem_size)

np:设备节点。

proname:需要统计元素数量的属性名字。

elem_size:元素长度。

返回值: 返回得到的属性元素数量。

11)、从属性中获取指定标号的数据值

int of_property_read_u32_index(const struct device_node *np, const char *propname, u32 index, u32 *out_value)

np:设备节点。

proname:要读取的属性名字。index:要读取的值标号;

out_value:读取到的值返回值:0读取成功,负值,读取失败,-EINVAL表示属性不存在,-ENODATA 表示没有要读取的数据,-EOVERFLOW 表示属性值列表太小。

12)、读取属性中u8类型的数组数据

int of_property_read_u8_array(const struct device_node *np, const char *propname, u8 *out_values, size_t sz)

np:设备节点。proname:要读取的属性名字。out_value:读取到的数组值,数据类型为u8。

sz:要读取的数组元素数量。返回值:0,读取成功,负值,读取失败,-EINVAL 表示属性不存在,-ENODATA 表示没有要读取的数据,-EOVERFLOW 表示属性值列表太小。

13)、读取属性中u16类型的数组数据

int of_property_read_u16_array(const struct device_node *np, const char *propname, u16 *out_values, size_t sz)

np:设备节点。proname:要读取的属性名字。out_value:读取到的数组值,数据类型为u16。sz:要读取的数组元素数量。返回值:0,读取成功,负值,读取失败,-EINVAL 表示属性不存在,-ENODATA 表示没有要读取的数据,-EOVERFLOW 表示属性值列表太小。

14)、读取属性中u32类型的数组数据

int of_property_read_u32_array(const struct device_node *np, const char *propname, u32 *out_values, size_t sz)

np:设备节点。proname:要读取的属性名字。out_value:读取到的数组值,数据类型为u32。sz:要读取的数组元素数量。返回值:0,读取成功,负值,读取失败,-EINVAL 表示属性不存在,-ENODATA 表示没有要读取的数据,-EOVERFLOW 表示属性值列表太小。

15)、读取属性中u64类型的数组数据

int of_property_read_u64_array(const struct device_node *np, const char *propname, u64 *out_values, size_t sz)

np:设备节点。proname:要读取的属性名字。out_value:读取到的数组值,数据类型为u64。sz:要读取的数组元素数量。返回值:0,读取成功,负值,读取失败,-EINVAL 表示属性不存在,-ENODATA 表示没有要读取的数据,-EOVERFLOW 表示属性值列表太小。

16)、读取属性中只有一个u8类型的数据

int of_property_read_u8(const struct device_node *np, const char *propname, u8 *out_value)

np:设备节点。proname:要读取的属性名字。out_value:读取到的u8类型的数据值。返回值:0,读取成功,负值,读取失败,-EINVAL 表示属性不存在,-ENODATA 表示没有要读取的数据,-EOVERFLOW 表示属性值列表太小。

17)、读取属性中只有一个u16类型的数据

int of_property_read_u16(const struct device_node *np, const char *propname, u16 *out_value)

np:设备节点。proname:要读取的属性名字。out_value:读取到的u16类型的数据值。返回值:0,读取成功,负值,读取失败,-EINVAL 表示属性不存在,-ENODATA 表示没有要读取的数据,-EOVERFLOW 表示属性值列表太小。

18)、读取属性中只有一个u32类型的数据

int of_property_read_u16(const struct device_node *np, const char *propname, u32 *out_value)

np:设备节点。proname:要读取的属性名字。out_value:读取到的u32类型的数据值。返回值:0,读取成功,负值,读取失败,-EINVAL 表示属性不存在,-ENODATA 表示没有要读取的数据,-EOVERFLOW 表示属性值列表太小。

19)、读取属性中只有一个u64类型的数据

int of_property_read_u16(const struct device_node *np, const char *propname, u64 *out_value)

np:设备节点。proname:要读取的属性名字。out_value:读取到的u64类型的数据值。返回值:0,读取成功,负值,读取失败,-EINVAL 表示属性不存在,-ENODATA 表示没有要读取的数据,-EOVERFLOW 表示属性值列表太小。

20)、读取属性中的字符串值

int of_property_read_string(struct device_node *np, const char *propname, const char **out_string)

np:设备节点。proname:要读取的属性名字。out_string:读取到的字符串值。返回值:0,读取成功,负值,读取失败。

21)、获取“#address-cells”属性值

int of_n_addr_cells(struct device_node *np)

np:设备节点。返回值:返回“#address-cells”的属性值。

22)、获取“#size-cells”属性值

int of_n_size_cells(struct device_node *np)

np:设备节点。返回值:返回“#size-cells”的属性值。

23)、査看“节点的compatible属性”是否有包含“compat指定的字符串”,也就是检查设备节点的兼容性

int of_device_is_compatible(const struct device_node *device, const char *compat)

device:设备节点;

compat:要查看的字符串。返回值:0,表示“节点的compatible属性”中不包含“compat指定的字符串”;正数,表示“节点的compatible属性”中包含“compat指定的字符串”。

24)、读取“reg”或者“assigned-addresses”属性值

const __be32 *of_get_address(struct device_node *dev, int index, u64 *size, unsigned int *flags)

dev:设备节点。

index:要读取的地址标号。

size:地址长度。flags:参数,比如“IORESOURCE_IO”、“IORESOURCE_MEM”等返回值:返回读取到的地址数据首地址,若返回值为NUIL,则表示读取失败。

25)、将从设备树读取到的地址addr转换为物理地址

u64 of_translate_address(struct device_node *dev, const __be32 *addr)

dev:设备节点。

addr:要转换的地址。

返回值:返回得到的物理地址,如果为 OF_BAD_ADDR,则表示转换失败。

26)、将reg属性值转换为resource结构体类型

int of_address_to_resource(struct device_node *dev, int index, struct resource *r)

dev:设备节点。

index:地址资源标号

r:得到的resource 类型的资源值。

返回值:0,成功:负值,失败。

27)、将“reg属性中地址信息”转换为“虚拟地址”,如果reg属性有多段的话,可以通过index参数指定要完成内存映射的是哪一段

void __iomem *of_iomap(struct device_node *np, int index)

np:设备节点。

index:reg属性中要完成内存映射的段,如果reg属性只有一段的话,则index=0。

返回值:经过内存映射后的虚拟内存首地址,如果为NULL的话,则表示内存映射失败。

注意:也可以使用ioremap()函数来完成物理地址到虚拟地址的内存映射。在采用设备树以后,大部分的驱动都使用of_iomap()函数来获取内存地址所对应的虚拟地址。

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

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

相关文章

MySQL实战:SQL优化及问题排查

有更合适的索引不走&#xff0c;怎么办&#xff1f; MySQL在选取索引时&#xff0c;会参考索引的基数&#xff0c;基数是MySQL估算的&#xff0c;反映这个字段有多少种取值&#xff0c;估算的策略为选取几个页算出取值的平均值&#xff0c;再乘以页数&#xff0c;即为基数 查…

FPGA高端项目:FPGA基于GS2971的SDI视频接收+GTX 8b/10b编解码SFP光口传输,提供2套工程源码和技术支持

目录 1、前言免责声明 2、相关方案推荐本博已有的 SDI 编解码方案本方案的SDI接收转HDMI输出应用本方案的SDI接收图像缩放应用本方案的SDI接收纯verilog图像缩放纯verilog多路视频拼接应用本方案的SDI接收HLS图像缩放Video Mixer多路视频拼接应用本方案的SDI接收OSD动态字符叠加…

【ARM Trace32(劳特巴赫) 高级篇 21 -- SystemTrace ITM 使用介绍】

文章目录 SystemTrace ITMSystemTrace ITM 常用命令Trace Data AnalysisSystemTrace ITM CoreSight ITM (Instrumentation Trace Macrocell) provides the following information: Address, data value and instruction address for selected data cyclesInterrupt event info…

Maven基础简介

作者简介&#xff1a; zoro-1&#xff0c;目前大二&#xff0c;正在学习Java&#xff0c;数据结构&#xff0c;spring等 作者主页&#xff1a; zoro-1的主页 欢迎大家点赞 &#x1f44d; 收藏 ⭐ 加关注哦&#xff01;&#x1f496;&#x1f496; Maven简介 Maven是什么 Maven…

Qt5.14.2揭秘Qt与SSL/TLS的完美邂逅:打造坚不可摧的网络安全防线

引言&#xff1a; 在数字化时代&#xff0c;数据安全是每个开发者和用户都不可忽视的问题。Qt&#xff0c;作为一个强大的跨平台开发框架&#xff0c;为我们提供了丰富的网络功能&#xff0c;其中就包括了对SSL/TLS加密通信的支持。本文将带你深入了解如何在Qt中实现SSL证书认证…

JVM的工作流程

目录 1.JVM 简介 2.JVM 执行流程 3. JVM 运行时数据区 3.1 堆&#xff08;线程共享&#xff09; 3.3 本地方法栈&#xff08;线程私有&#xff09; 3.4 程序计数器&#xff08;线程私有&#xff09; 3.5 方法区&#xff08;线程共享&#xff09; 4.JVM 类加载 ① 类…

软件测试的就业前景如何?

近年来&#xff0c;进入软件测试的就业人数逐渐增加。现在的社会对软件测试这个职业都有很大的需求。也有很多刚步入社会的年轻人想学习软件测试。那么你知道学习软件测试的的发展前景怎么样吗?看看下面的详细介绍。 关于软件测试行业发展前景问题&#xff0c;是很多准备入行…

c++ 常用的STL

前言 写这篇博客目的是为了记录在刷算法题中使用过的STL&#xff0c;因为有些不太常用的会遗忘。这篇博客只是作为笔记&#xff0c;不是详细的STL&#xff0c;因此只会对常用方法说明&#xff0c;不会详细介绍。此外在后面用到新的STL内容时会再补充。 列队 基础列队 基本列…

【python】time库知识整理

简介 python的time库是python内置库&#xff0c;主要负责处理与时间相关的事务。 获取当前时间 函数作用time()获取当前时间戳ctime()获取字符串形式的时间gmtime()调用内部方法&#xff0c;赋予属性&#xff0c;能够被程序调用执行 time返回的是时间戳 ctime是返回的我们…

MPU6050详解

文章目录 前言MPU6050简介MPU6050参数 硬件电路MPU6050框图电荷泵的原理 内部时钟生成需要使用的寄存器&#xff08;常用&#xff09;采样率划分器配置寄存器陀螺仪配置寄存器加速度计配置寄存器加速度计测量寄存器温度测量寄存器陀螺仪测量寄存器电源管理1寄存器电源管理2寄存…

Tomcat实现java博客项目、状态页及常见配置介绍

目录 一、自建博客 1. 项目背景 2. 操作示例 二、状态页 1. 概述 2. server status 信息状态页 3. manager app 项目管理状态页 4. host manger 虚拟主机管理状态页 三、常见配置 1. 端口8005/tcp安全配置管理 2. tomcat端口号 3. 虚拟主机设置 4. Context配置 一…

R语言自定义颜色

一、创建颜色梯度&#xff08;渐变色&#xff09; 在绘热图时&#xff0c;需要将数值映射到不同的颜色上&#xff0c;这时就需要一系列的颜色梯度colorRampPalette 函数支持自定义的创建一系列的颜色梯度。 代码示例&#xff1a; library(RColorBrewer)x <- colorRampPal…

【kubernetes】关于k8s集群的pod控制器

目录 一、deployment控制器 二、statefulset控制器 1、验证数据可以持久化 2、验证删除后名称不会改变&#xff0c;数据还会一直存在 3、验证扩容的创建过程是升序串行执行&#xff0c;并且自动创建pv 4、验证滚动更新的时候也是升序执行&#xff0c;数据持久化还在 5、验…

【排序算法】深入理解归并排序算法:从原理到实现

目录 1. 引言 2. 归并排序算法原理 3. 归并排序的时间复杂度分析 4. 归并排序的应用场景 5. 归并排序的优缺点分析 5.1 优点&#xff1a; 5.2 缺点&#xff1a; 6. Java、JavaScript 和 Python 实现归并排序算法 6.1 Java 实现&#xff1a; 6.2 JavaScript 实现&…

A5自媒体wordpress主题模板

一个简洁的wordpress个人博客主题&#xff0c;适合做个人博客&#xff0c;SEO优化效果挺不错的。 https://www.wpniu.com/themes/204.html

什么是ETL?什么是ELT?怎么区分它们使用场景

在大数据处理的领域中&#xff0c;ETL和ELT是两个经常被数据工程师提到的工具&#xff0c;而有很多数据工程师对这两种工具的区别和使用和定位有一定的模糊&#xff0c;其实它们分别代表了两种不同的数据集成方法。尽管这两种方法看起来都是从源系统提取数据&#xff0c;转换数…

2024AI在医疗领域中的辅助趋势与现有进展

2024 年 AI 辅助研发趋势随着人工智能技术的持续发展与突破&#xff0c;2024年AI辅助研发正成为科技界和工业界瞩目的焦点。从医药研发到汽车设计&#xff0c;从软件开发到材料科学&#xff0c;AI正逐渐渗透到研发的各个环节&#xff0c;变革着传统的研发模式。在这一背景下&am…

rabbitmq 基本总结

rabbitmq 的基本概念 vhost、broker、producer、 consumer、 exchange、 queue、 routing key rabbitmq 常用的队列类型&#xff0c;工作队列&#xff08;简单队列&#xff09;,pub/sub, routing key&#xff0c; topic 模式 <dependency><groupId>com.rabbitmq&l…

启动项目报502怎么处理呢?

您好&#xff0c;我是码农飞哥&#xff08;wei158556&#xff09;&#xff0c;感谢您阅读本文&#xff0c;欢迎一键三连哦。 &#x1f4aa;&#x1f3fb; 1. Python基础专栏&#xff0c;基础知识一网打尽&#xff0c;9.9元买不了吃亏&#xff0c;买不了上当。 Python从入门到精…

蓝桥杯练习系统(算法训练)ALGO-982 最小距离

资源限制 内存限制&#xff1a;256.0MB C/C时间限制&#xff1a;1.0s Java时间限制&#xff1a;3.0s Python时间限制&#xff1a;5.0s 最小距离 问题描述 数轴上有n个数字&#xff0c;求最近的两个数&#xff0c;即min(abs(x-y)) 输入格式 第一行包含一个整数n。   …