嵌入式驱动学习第四周——设备树

前言

   掌握设备树是 Linux 驱动开发人员必备的技能!因为在新版本的 Linux 中,ARM 相关的驱动全部采用了设备树。本篇博客重点介绍一下设备树与设备树语法。

   嵌入式驱动学习专栏将详细记录博主学习驱动的详细过程,未来预计四个月将高强度更新本专栏,喜欢的可以关注本博主并订阅本专栏,一起讨论一起学习。现在关注就是老粉啦!

目录

  • 前言
  • 1. 设备树简介
    • 1.1 设备树介绍
    • 1.2 dtb、dts、dtc、dtsi文件的关系
    • 1.3 编译设备树
    • 1.4 设备树特点
  • 2. 设备树语法
    • 2.1 基本构成
    • 2.2 节点的格式
    • 2.3 节点属性
      • 2.3.1 compatible属性
      • 2.3.2 model属性
      • 2.3.3 status属性
      • 2.3.4 #address-cells和#size-cell
      • 2.3.5 reg属性
      • 2.3.6 ranges属性
      • 2.3.7 name和device_type
      • 2.3.8 特殊节点
        • 2.3.8.1 aliases子节点
        • 2.3.8.2 chosen子节点
  • 3. 获取设备树节点信息
    • 3.1 查找节点
      • 3.1.1 根据节点路径:
      • 3.1.2 根据节点类型和compatible属性寻找节点函数
      • 3.1.3 其他方式
    • 3.2 获取属性值
      • 3.2.1 device_node结构体
      • 3.2.2 获取节点属性
      • 3.2.3 其他of函数
  • 4. Linux设备树调试
  • 参考资料

1. 设备树简介

1.1 设备树介绍

   描述设备树的文件叫DTS,该文件采用树形结构描述板级设备即开发板上的设备信息:CPU数量,内存基地址,IIC接口上接了哪些设备,如下所示:

在这里插入图片描述

   设备树是一种描述硬件的数据结构,在Linux3.x版本上才开始使引入,采用了设备树之后,许多硬件的细节可以直接通过它传递给Linux,而不再需要在内核中进行大量的冗余编码,它通过bootloader将硬件资源传给内核,使得内核和硬件资源描述相对独立。

   ARM 社区引入了 PowerPC 等架构已经采用的设备树(Flattened Device Tree),将这些描述板级硬件信息的内容都从 Linux 内中分离开来,用一个专属的文件格式来描述,这个专属的文件就叫做设备树,文件扩展名为.dts。一个 SOC 可以作出很多不同的板子,这些不同的板子肯定是有共同的信息,将这些共同的信息提取出来作为一个通用的文件,其他的.dts 文件直接引用这个通用文件即可,这个通用文件就是.dtsi 文件,类似于 C 语言中的头文件。一般.dts 描述板级信息(也就是开发板上有哪些 IIC 设备、SPI 设备等),.dtsi 描述 SOC 级信息(也就是 SOC 有几个 CPU、主频是多少、各个外设控制器信息等)。

1.2 dtb、dts、dtc、dtsi文件的关系

   这四个代表四种不同的文件格式,可以类比到C语言中的相关知识来理解。

   我们都知道,C语言编写.c文件的时候需要添加C库.h文件来添加我们所需要用到的函数,宏等。然后要用编译器将.c文件编译成计算机能理解的二进制文件。

   同样的,在设备树中,dts是设备树源码,相当于.c文件,是我们编写和能看懂的文件,然后需要添加.dtsi文件来得到一些板级信息,相当于.h文件。最后要将这个文本文件编译成计算机理解的二进制文件,即用dtc编译工具编译成.dtb这个二进制文件。总结下来,对应关系如下所示:

.dts   -->  .c文件
.dtsi  -->   .h文件
.dtb   -->   .exe文件
dtc   -->   编译器

   dtc的源码存放于scripts/dtc目录中,对应于该目录下Makefile中hostprogs-y:=dtc这一编译目标

生成dts文件对应的dtb文件
dtc -I dts -O dtb -o xxx.dtb xxxdts
反过来生成dts文件
dtc -I dtb -O dts -o xxx.dts xxxdtb

1.3 编译设备树

   进入到Linux源码根目录下,然后执行如下指令进行编译:

make dtbs	(这个指令只编译设备树)
或者
make all (这个指令是编译所有的东西,包括.ko,zImage)

1.4 设备树特点

在这里插入图片描述

   设备树可以用树状结构描述硬件资源,如上图所示,在根节点/下,挂载本地总线的SPI总线,UART总线等的树干为根节点的子节点。若是SPI下的设备不止一个,那么又可以从这根树枝下分出枝干

   设备树可以复用,例如多个硬件平台都使用i.MX6ULL作为主控芯片, 那么我们可以将i.MX6ULL芯片的硬件资源写到一个单独的设备树文件里面一般使用“.dtsi”后缀, 其他设备树文件直接使用“# includexxx”引用即可。

2. 设备树语法

   设备树文件存放地址:

源码地址/arch/arm/boot/boot/dts

   此处打开正点原子的imx6ull-alientek-emmc.dts文件来学习一下设备树语法,此处提一个事情,设备树语法中的注释用/* ... */表示

2.1 基本构成

   首先来看以下一段:

#include <dt-bindings/input/input.h>
#include "imx6ull.dtsi"

   这一段首先是包含头文件,设备树是可以像C语言那样使用“#include”引用“.h”后缀的头文件,也可以引用设备树“.dtsi”后缀的头文件。 imx6ull.dtsi由NXP官方提供,是一个imx6ull平台“共用”的设备树文件。.dts 文件引用 C 语言中的.h 文件,甚至也可以引用.dts 文件。

/ {model = "Freescale i.MX6 ULL 14x14 EVK Board";compatible = "fsl,imx6ull-14x14-evk", "fsl,imx6ull";key {#address-cells = <1>;#size-cells = <1>;compatible = "atkmini-key";pinctrl-names = "default";pinctrl-0 = <&pinctrl_key>;key-gpio = <&gpio1 18 GPIO_ACTIVE_LOW>;interrupt-parent = <&gpio1>;interrupts = <18 IRQ_TYPE_EDGE_FALLING>;status = "okay";};gpioled {#address-cells = <1>;#size-cells = <1>;compatible = "atkmini-gpioled";pinctrl-names = "default";pinctrl-0 = <&pinctrl_led>;led-gpio = <&gpio1 3 GPIO_ACTIVE_LOW>;status = "okay";};mini {#address-cells = <1>;#size-cells = <0>;compatible = "atkmini-led";status = "okay";reg = < 0x020c406c 0x04		/* CCM_CCGR1_BASE         */0x020e0068 0x04		/* SW_MUX_GPIO1_IO03_BASE */0x020e02f4 0x04		/* SW_PAD_GPIO1_IO03_BASE */0x0209c000 0x04		/* GPIO1_DR_BASE          */0x0209c004 0x04>;		/* GPIO1_GDIR_BASE        */};chosen {stdout-path = &uart1;};dht11 {compatible = "alientek, dht11";pinctrl-names = "default";pinctrl-0 = <&pinctrl_dht11>;dht11-gpio = <&gpio1 1 GPIO_ACTIVE_LOW>;status = "okay";};ds18b20 {compatible = "alientek, ds18b20";pinctrl-names = "default";pinctrl-0 = <&pinctrl_ds18b20>;ds18b20-gpio = <&gpio1 1 GPIO_ACTIVE_LOW>;status = "okay";};memory {reg = <0x80000000 0x20000000>;};reserved-memory {#address-cells = <1>;#size-cells = <1>;ranges;linux,cma {compatible = "shared-dma-pool";reusable;size = <0x8000000>;linux,cma-default;};};/* 以下内容省略
}

   这一段是设备树节点,每个{}就是一个节点,最外面的/{...}就是根节点,每个设备树只有一个根节点。但是如果打开imx6ull.dtsi文件可以发现它也有一个根节点,虽然imx6ull-alientek-emmc.dts引用了imx6ull.dtsi文件, 但这并不代表imx6ull-alientek-emmc.dts设备树有两个根节点,因为不同文件的根节点最终会合并为一个

   然后我们可以看到根节点内部也有很多{...},比如ds18b20 {...}memory {}这些都是根节点的子节点。

   最后来看下一段:

&cpu0 {arm-supply = <&reg_arm>;soc-supply = <&reg_soc>;dc-supply = <&reg_gpio_dvfs>;
};&clks {assigned-clocks = <&clks IMX6UL_CLK_PLL4_AUDIO_DIV>;assigned-clock-rates = <722534400>;
};&csi {status = "okay";port {csi_ep: endpoint {remote-endpoint = <&camera_ep>;};};
};

   这一部分是设备树节点的追加内容,最明显的特点就是添加了一个&符号。该符号表示向已经存在的子节点追加数据,这些已经存在的节点可以是本文件中的,也可以是#include中定义的。

2.2 节点的格式

   知道了设备树的组成后,来具体看看一个节点如何定义:

node-name@unit-address {属性1 = ""属性2 = ""属性3 = ""子节点
}

   node-name是节点名称,长度为1~31个字符,最好使用大写或小写字母开头,且能描述设备类别。根节点是一个特殊的节点,其用/指代。

   @unit-address是指定单元地址,@可理解为分隔符,unit-address的值要与节点“reg”属性的第一个地址一致,如果没有reg节点,可以省略,这时就要求同级设备树下,节点名唯一。因此要么节点名唯一,要么节点名重复单单元地址不同,总之就是node-name@unit-address这个整体要求同级唯一。

   还有一种方式就是添加了节点标签:

label:node-name@unit-address
比如:
cpu0:cpu@0

   引入 label 的目的就是为了方便访问节点,可以直接通过&label 来访问这个节点,比如通过&cpu0 就可以访问“cpu@0”这个节点,而不需要输入完整的节点名字。此外还有一个很重要的作用就是对接点进行扩展,当其他位置需要引用时可以使用节点标签来向该节点中追加内容。

2.3 节点属性

   设备树源码中常用的几种数据形式:字符串、32位无符号整数

2.3.1 compatible属性

   属性值类型:字符串

   一般compatible属性的格式如下所示,manufacturer 表示厂商,model 一般是模块对应的驱动名字。

compatible = "manufacturer,model"
例如:
compatible = "fsl,imx6ull-14x14-evk", "fsl,imx6ull";

   设备树中的每一个代表了一个设备的节点都要有一个compatible属性。 compatible是系统用来决定绑定到设备的设备驱动的关键。 compatible属性是用来查找节点的方法之一。

   一般驱动程序文件都会有一个 OF 匹配表,此 OF 匹配表保存着一些 compatible 值,如果设备节点的 compatible 属性值和 OF 匹配表中的任何一个值相等,那么就表示设备可以使用这个驱动。如下:

static const struct of_device_id imx6ull_of_match {{.compatible = "fsl,imx6ull-14x14-evk"},{ //Sentinel }
};static struct platform_driver imx6ull_driver = {.driver = {.name   = "xxx",.of_match_table = imx6ull_of_match,},.probe = imx6ull_probe,.remove = imx6ull_remove,
};

2.3.2 model属性

   属性值类型:字符串

   一般 model 属性描述设备模块信息,比如名字什么的。

model = "wm8960-audio";

2.3.3 status属性

   属性值类型:字符串

   该属性是设备的状态信息,可选状态如表所示:

status值描述
“okay”表示设备可操作
“disable”表示设备当前是不可操作的,但在未来可以变为可操作,比如热插拔设备插入后
“fail”表明设备不可操作,设备检测到了一系列错误,且设备不大可能变得可操作
“fail-sss”含义与"fail"相同,后面的sss是检测到的错误内容

2.3.4 #address-cells和#size-cell

   属性值类型:整数

   #address-cells 和#size-cells 这两个属性可以用在任何拥有子节点的设备中,用于描述子节点的地址信息。#address-cells 和#size-cells 表明了子节点应该如何编写 reg 属性值。具体的结合下面的reg属性讲解。

2.3.5 reg属性

   属性值类型:整数(表示地址)

   reg的形式如下:

reg = <address1 length1 address2 length2 address3 length3……>

   #address-cells控制address的数量,#size-cells控制length的数量。如下:

spi4 {compatible = "spi-gpio";pinctrl-names = "default";pinctrl-0 = <&pinctrl_spi4>;status = "disabled";gpio-sck = <&gpio5 11 0>;gpio-mosi = <&gpio5 10 0>;num-chipselects = <1>;#address-cells = <1>;#size-cells = <0>;gpio_spi: gpio_spi@0 {compatible = "fairchild,74hc595";gpio-controller;#gpio-cells = <2>;reg = <0>;registers-number = <1>;registers-default = /bits/ 8 <0x57>;spi-max-frequency = <100000>;};
};

   父节点设置了#address-cells = <1>以及#size-cells = <0>,于是在子节点中就是reg<0>,表示只设置了起始地址,没有设置地址长度。

2.3.6 ranges属性

   属性值类型:任意数量的 <子地址、父地址、地址长度>编码

   比如对于#address-cells和#size-cells都为1的话,以ranges=<0x0 0x10 0x20>为例,表示将子地址的从0x0~(0x0 + 0x20)的地址空间映射到父地址的0x10~(0x10 + 0x20)

   可以为空,如下所示:

soc {...ranges;...
}

   不为空时如下所示:

soc {compatible = "simple-bus";#address-cells = <1>;#size-cells = <1>;ranges = <0x0 0xe0000000 0x00100000>;serial {device_type = "serial";compatible = "ns16550";reg = <0x4600 0x100>;clock-frequency = <0>;interrupts = <0xA 0x8>;interrupt-parent = <&ipic>;};
};

   节点 soc 定义的 ranges 属性,值为<0x0 0xe0000000 0x00100000>,此属性值指定了一个 1024KB(0x00100000)的地址范围,子地址空间的物理起始地址为 0x0,父地址空间的物理起始地址为 0xe0000000。

   serial 是串口设备节点,reg 属性定义了 serial 设备寄存器的起始地址为 0x4600,寄存器长度为 0x100。经过地址转换,serial 设备可以从 0xe0004600 开始进行读写操作,0xe0004600=0x4600+0xe0000000。

2.3.7 name和device_type

   属性值类型:字符串

   这两个属性值已经被抛弃了。

2.3.8 特殊节点

2.3.8.1 aliases子节点

   aliases子节点的作用就是为其他节点起一个别名,如下所示:

aliases {can0 = &flexcan1;can1 = &flexcan2;ethernet0 = &fec1;ethernet1 = &fec2;gpio0 = &gpio1;gpio1 = &gpio2;gpio2 = &gpio3;gpio3 = &gpio4;gpio4 = &gpio5;i2c0 = &i2c1;i2c1 = &i2c2;/*----------- 以下省略------------*/
}

   以can0 = &flexcan1;为例。flexcan1是一个节点的名字, 设置别名后我们可以使用can0来指代flexcan1节点,与节点标签类似。 在设备树中更多的是为节点添加标签,没有使用节点别名,别名的作用是“快速找到设备树节点”。 在驱动中如果要查找一个节点,通常情况下我们可以使用“节点路径”一步步找到节点。 也可以使用别名“一步到位”找到节点。

2.3.8.2 chosen子节点

   chosen子节点不代表实际硬件,它主要用于给内核传递参数,此外这个节点还用作uboot向linux内核传递配置参数的“通道”, 我们在Uboot中设置的参数就是通过这个节点传递到内核的, 这部分内容是uboot和内核自动完成的。

3. 获取设备树节点信息

3.1 查找节点

3.1.1 根据节点路径:

   就和windows下查找文件一样,我们也可以通过节点路径查找节点。

/** @description: 根据节点路径查找节点* @param-path : 指定节点在设备树中的路径* @return     : 返回device_node结构体指针,如果查找失败返回NULL,否则返回device_node类型的结构体指针,保存设备节点的信息。*/
struct device_node *of_find_node_by_path(const char *path)

   得到device_node结构体之后我们就可以使用其他of 函数获取节点的详细信息。

3.1.2 根据节点类型和compatible属性寻找节点函数

/** @description     : 根据节点类型和compatible属性寻找节点函数* @param-from      : 指定从哪个节点开始查找,它本身并不在查找行列中,只查找它后面的节点,如果设置为NULL表示从根节点开始查找* @param-type      : 要查找节点的类型,这个类型就是device_node-> type* @param-compatible: 要查找节点的compatible属性* @return          : device_node类型的结构体指针,保存获取得到的节点。同样,如果失败返回NULL*/
struct device_node *of_find_compatible_node(struct device_node *from,const char *type, const char *compatible)

3.1.3 其他方式

  常用的为以上几种,如果想看其他的话可以看野火的文档。

3.2 获取属性值

   找到一个设备节点就会返回这个设备节点对应的结构体指针(device_node*)。这个过程可以理解为把设备树中的设备节点“获取”到驱动中。“获取”成功后我们再通过一组of函数从设备节点结构体(device_node)中获取我们想要的设备节点属 性信息。其of函数存放在以下目录下:

内核源码/include/linux/of.h

3.2.1 device_node结构体

struct device_node {const char *name;const char *type;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;
#endifunsigned long _flags;void    *data;
#if defined(CONFIG_SPARC)const char *path_component_name;unsigned int unique_id;struct of_irq_controller *irq_trans;
#endif
};
  • name: 节点中属性为name的值
  • type: 节点中属性为device_type的值
  • full_name: 节点的名字,在device_node结构体后面放一个字符串,full_name指向它
  • properties: 链表,连接该节点的所有属性
  • parent: 指向父节点
  • child: 指向子节点
  • sibling: 指向兄弟节点

3.2.2 获取节点属性

/** @description: 寻找指定属性* @param-np   : 设备节点* @param-name : 属性名字* @param-lenp : 属性值的字节数* @return     : 找到的属性
property *of_find_property(const struct device_node *np, const char *name, int *lenp)

   属性的property结构体:

struct property {char	*name;		// 属性名字int	length;			// 属性长度void	*value;		// 属性值struct property *next;	// 下一个属性unsigned long _flags;unsigned int unique_id;struct bin_attribute attr;
};

3.2.3 其他of函数

   太多了,可以看原子的资料,或者查看这位博主的博客:Linux 学习笔记: 设备树—常用OF操作函数

4. Linux设备树调试

   我们可以在Linux下查看设备树信息:

cd /proc/device-tree
ls

在这里插入图片描述

   Linux内核在启动时会解析设备树的各个节点信息,并在/proc/device-tree目录下根据节点名字创建不同的文件或文件夹

   如果要查看其下面有哪些属性和节点,cd进去即可,比如我要看最后一个spi4:

cd spi4
ls

在这里插入图片描述

参考资料

[1] 【正点原子】I.MX6U嵌入式Linux驱区动开发指南 第四十三章
[2] 【野火】嵌入式Linux驱动开发实战指南——基于I.MX6ULL系列
[3] Device Tree -----设备树
[4] Linux 学习笔记: 设备树—常用OF操作函数

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

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

相关文章

Vue3的与2的简单区别

Vue2选项式api Vue3组合式API setup方法的使用&#xff0c;最后需要return setup语法糖省略了内部的export default{} 和return 内容 以及组件的注册 reactive生成响应式对象&#xff0c;只能适用于复杂对象&#xff0c;简单类型不可 ref生成响应式数据&#xff1a;复杂类型和简…

详细剖析多线程(更新中...)

文章目录 前言一、认识线程1.1线程概念1.2为什么要有线程1.3线程和进程的区别&#xff08;经典面试题&#xff09; 二、创建线程2.1继承 Thread 类,重写run2.2实现 Runnable 接口,重写run2.3继承 Thread 类,重写run&#xff0c;匿名内部类2.4实现 Runnable 接口,重写run&#x…

Linux信号补充——信号捕捉处理

一、信号的捕捉处理 ​ 信号保存后会在合适的时间进行处理&#xff1b; 1.1信号处理时间 ​ 进程会在操作系统的调度下处理信号&#xff0c;操作系统只管发信号&#xff0c;即信号处理是由进程完成的&#xff1b; ​ 1.信号处理首先进程得检查是否有信号&#xff1b;2.进程…

赋能智能未来:AI大模型的学习之旅

随着人工智能的迅速发展&#xff0c;AI大模型已经成为技术领域的一个热点。这些模型以其强大的数据处理能力和预测精度&#xff0c;正在不断推动着科技的边界&#xff0c;并且在医疗、金融、交通等多个行业中显示出了巨大的潜力。然而&#xff0c;构建和训练一个高效的AI大模型…

浅谈如何自我实现一个消息队列服务器(2)——实现 broker server 服务器

文章目录 一、实现 broker server 服务器1.1 创建一个SpringBoot项目1.2 创建Java类 二、硬盘持久化存储 broker server 里的数据2.1 数据库存储2.1.1 浅谈SQLiteMyBatis 2.1.2 如何使用SQLite 2.2 使用DataBaseManager类封装数据库操作2.3 文件存储消息2.3.1 存储消息时&#…

宏景eHR report_org_collect_tree.jsp SQL注入漏洞复现

0x01 产品简介 宏景eHR人力资源管理软件是一款人力资源管理与数字化应用相融合,满足动态化、协同化、流程化、战略化需求的软件。 0x02 漏洞概述 宏景eHR report_org_collect_tree.jsp 接口处存在SQL注入漏洞,未经过身份认证的远程攻击者可利用此漏洞执行任意SQL指令,从而…

Docker部署Alist全平台网盘神器结合内网穿透实现无公网IP访问云盘资源

&#x1f308;个人主页: Aileen_0v0 &#x1f525;热门专栏: 华为鸿蒙系统学习|计算机网络|数据结构与算法|MySQL| ​&#x1f4ab;个人格言:“没有罗马,那就自己创造罗马~” #mermaid-svg-oZuxWTWUiXLx3aQO {font-family:"trebuchet ms",verdana,arial,sans-serif;f…

SpringBoot实战(二十七)集成WebFlux

目录 一、WebFlux1.1 定义1.2 WebFlux 与 Spring MVC 区别 二、代码实现2.1 Maven 配置2.2 暴露 RESTful API 接口的方式方式一&#xff1a;基于注解的控制器方式二&#xff1a;函数式路由器&#xff08;Functional Endpoints&#xff09; 2.3 测试Service2.4 测试ServiceImpl2…

Streamlit实战手册:从数据应用到机器学习模型部署

Streamlit实战手册&#xff1a;从数据应用到机器学习模型部署 简介Streamlit核心功能介绍Streamlit的安装创建第一个Streamlit应用界面布局与导航数据处理与展示 Streamlit的进阶应用交互式组件按钮复选框单选按钮滑块 图表与可视化使用Matplotlib绘图使用Plotly创建交互式图表…

【题目】【网络系统管理】2019年全国职业技能大赛高职组计算机网络应用赛项H卷

极安云科专注职业教育技能竞赛培训4年&#xff0c;包含信息安全管理与评估、网络系统管理、网络搭建等多个赛项及各大CTF模块培训学习服务。本团队基于赛项知识点&#xff0c;提供完整全面的系统性理论教学与技能培训&#xff0c;成立至今持续优化教学资源与讲师结构&#xff0…

Springboot 整合 Knife4j (API文档生成工具)

目录 一、Knife4j 介绍 二、Springboot 整合 Knife4j 1、pom.xml中引入依赖包 2、在application.yml 中添加 Knife4j 相关配置 3、打开 Knife4j UI界面 三、关于Knife4j框架中常用的注解 1、Api 2、ApiOperation ​3、ApiOperationSupport(order X) ​4、ApiImplici…

Leetcode 994. 腐烂的橘子

心路历程&#xff1a; 一开始以为和刚做过的岛屿问题很像&#xff0c;只不过是把岛屿问题换成BFS去做&#xff0c;然后再加上一些计数的规则。结果做完后发现只能通过一半左右的测试用例&#xff0c;发现有一个逻辑错误在于&#xff0c;当腐烂的橘子位于两端时&#xff0c;可以…

C#探索之路基础篇(2):接口Interface的概念、实现、应用范围

文章目录 1 概念2 示例代码&#xff1a;2.1 简单接口的实现2.2 简单的使用接口2.3 使用接口呈现多态性2.4 通过接口实现一个数组迭代器2.5 通过接口来实现松耦合的关系2.6 使用接口实现可扩展、便利性 3 使用范围与时机4 注意事项 不知道大家在学习的过程中&#xff0c;有没有反…

笔试总结01

1、spring原理 1、spring原理 spring的最大作用ioc/di,将类与类的依赖关系写在配置文件中&#xff0c;程序在运行时根据配置文件动态加载依赖的类&#xff0c;降低的类与类之间的藕合度。它的原理是在applicationContext.xml加入bean标记,在bean标记中通过class属性说明具体类…

vue3+threejs新手从零开发卡牌游戏(二):初始化场景

在删掉初始化中一些没用的代码后&#xff0c;在views目录下新建game文件夹&#xff0c;在里面新建一个index.vue&#xff0c;这里就当成游戏的主入口。 目录结构如下&#xff1a; 下面开始尝试创建场景&#xff1a; 一、添加一个div作为threejs的画布对象&#xff0c;之后整个…

ubuntu - 编译 linphone-sdk

业务需求需要定制sdk&#xff0c;首先声明我们需要的是在Android4.4上跑的sdk&#xff0c;因此本次编译的sdk最低支持为19&#xff08;不同版本需要的环境不一致&#xff09;&#xff0c;编译过程较容易&#xff0c;难点在于环境配置 环境准备 Ubuntu 18.04.6 android-sdk_r24.…

mysql分页查询多用GitCode平台

目录 一、在GitCode平台AI搜索结果&#xff08;这个更优&#xff09; 二、在百度搜索输入“mysql Java分页查询”的输出结果&#xff1a; 三、推荐的文章 四、GitCode的使用 1&#xff09;如搜索jdk11可以直接下载jdk11的包 2&#xff09;搜索开源项目 3&#xff09;如搜…

步进电机驱动器的接线与使用(接线详细)

今天小编就来继续学习与使用步行电机的学习&#xff0c;如果位置对你有帮助&#xff0c;评论收藏&#xff0c;点赞一下 步进电机驱动器 步进电机驱动器是一种专用于控制步进电机的电子设备&#xff0c;用于控制步进电机的转动和位置。步进电机是一种将电信号转换为机械运动的电…

Compose UI 之 Segmented buttons 分段按钮

Segmented buttons SegmentedButton 是一种分段式按钮组件,它允许用户在一组相关的选项中选择一个或几个。 上图中:① 单选的分段式按钮。② 多选的分段式按钮。 分段式按钮的几个特点: 分段式按钮是带有状态的按钮,又有单选和多选之分。 从设计上将,不论是单选或是多选…

【GPT概念-03】:人工智能中的注意力机制

说明 注意力机制生成分数&#xff08;通常使用输入函数&#xff09;&#xff0c;确定对每个数据部分的关注程度。这些分数用于创建输入的加权总和&#xff0c;该总和馈送到下一个网络层。这允许模型捕获数据中的上下文和关系&#xff0c;而传统的固定序列处理方法可能会遗漏这…