文章目录

  • 前言
    • 设备树
    • DTS语法内容
    • 标准属性
    • 向节点追加或修改内容
    • 设备树在目录中的体现
    • Linux 内核解析 DTB 文件
    • 帮助文档信息
    • 设备树节点的操作函数
      • 1、查找节点的 of 函数
      • 2、查找父/子节点的 OF 函数
      • 3、提取属性值的 OF 函数

前言

在linux2.6中,ARM架构的板级硬件细节过多的被编码在arch/arm/plat-xxx和arch/arm/mach-xxx充斥着大量的板级信息,这些细节对应内核来说不过是垃圾。

设备树

设备树是一种描述硬件的数据结构,它起源于OpenFirmware。采用设备树后,许多硬件的细节可以直接传递给linux,不需要在内核中充斥着大量的冗余代码。
设备树由一系列的节点和属性组成,节点可包含子节点。在设备树中,可描述的信息包括:

  • CPU数量和类型
  • 内存基地址和大小
  • 总线和桥
  • 外设连接
  • 中断控制器和中断使用情况
  • GPIO控制器和GPIO使用情况
  • 时钟控制器和时钟使用情况

bootload会将这些信息传递给内核,内核开始识别这些树,并解析成linux内核中platform_device,i2c_client,spi_device等设备,而这些设备使用的内存资源,中断等信息也传递给内核。内核会将这些资源绑定给相应的设备。

设备树的组成 DTS、DTC、DTB

DTS 是设备树源码文件, DTB 是将DTS 编译以后得到的二进制文件。那么将.dts 编译为.dtbn需要什么工具呢?需要用到 DTC 工具。

DTS语法内容

文件.dts是一种ASCII文本格式的设备树描述。基本上一个.dts文件对应一个ARM设备,一般放置在arch/arm/boot/dts/ 目录中。

1、.dtsi 头文件

设备树也支持头文件,设备树的头文件扩展名为.dtsi。在 imx6ull-alientekemmc.dts 中有如下所示内容:

#include <dt-bindings/input/input.h>//引用.h文件
#include "imx6ull.dtsi" //引用“imx6ull.dtsi”这个.dtsi 头文件

一般.dtsi 文件用于描述 SOC 的内部外设信息,比如 CPU 架构、主频、外设寄存器地址范围,比如 UART、 IIC 等等。
比如 imx6ull.dtsi 就是描述 I.MX6ULL 这颗 SOC 内部外设情况信息

#include <dt-bindings/gpio/gpio.h>
#include <dt-bindings/interrupt-controller/arm-gic.h>
#include "imx6ull-pinfunc.h"
#include "imx6ull-pinfunc-snvs.h"
#include "skeleton.dtsi"/ {aliases {can0 = &flexcan1;...};cpus {#address-cells = <1>;#size-cells = <0>;cpu0: cpu@0 {compatible = "arm,cortex-a7";device_type = "cpu";reg = <0>;clock-latency = <61036>; /* two CLK32 periods */operating-points = </* kHz uV */996000 1275000792000   1225000528000   1175000396000   1025000198000   950000>;/* kHz   uV */996000 1275000792000   1225000528000   1175000396000   1025000...};intc: interrupt-controller@00a01000 {compatible = "arm,cortex-a7-gic";#interrupt-cells = <3>;interrupt-controller;reg = <0x00a01000 0x1000>,<0x00a02000 0x100>;};...

文件描述了CPU arm,cortex-a7 ,支持 996MHz、 792MHz等频率, 时钟一些信息。

  • “/”是根节点,每个设备树文件只有一个根节点
  • aliases、 cpus 和 intc 是三个子节点,在设备树中节点命名格式如下:
node-name@unit-address

其中“node-name”是节点名字,为 ASCII 字符串,节点名字应该能够清晰的描述出节点的功能,比如“uart1”就表示这个节点是 UART1 外设。“unit-address”一般表示设备的地址或寄存器首地址,如果某个节点没有地址或者寄存器的话“unit-address”可以不要,比如“cpu@0”、“interrupt-controller@00a01000”

label: node-name@unit-address

引入 label 的目的就是为了方便访问节点,可以直接通过&label 来访问这个节点,比如通过&cpu0 就可以访问“cpu@0”这个节点。很明显通过&intc 来访问“interrupt-controller@00a01000”这个节点要方便很多!

每个节点都有不同属性,不同的属性又有不同的内容,属性都是键值对,值可以为空或任意的字节流。设备树源码中常用的几种数据形式如下所示:

  • 字符串
compatible = "arm,cortex-a7";
  • 32 位无符号整数
reg = <0 0x123456 100>;
  • 字符串列表
compatible = "fsl,imx6ull-gpmi-nand", "fsl, imx6ul-gpmi-nand";

标准属性

1、compatible 属性

compatible 属性也叫做“兼容性”属性,这是非常重要的一个属性! compatible 属性的值是一个字符串列表, compatible 属性用于将设备和驱动绑定起来。字符串列表用于选择设备所要
使用的驱动程序, compatible 属性的值格式如下所示:

"manufacturer,model"

manufacturer 表示厂商, model 一般是模块对应的驱动名字。
实例:

compatible = "fsl,imx6ul-evk-wm8960","fsl,imx-audio-wm8960";

其中“fsl”表示厂商是飞思卡尔,“imx6ul-evk-wm8960”和“imx-audio-wm8960”表示驱动模块名字。设备首先使用第一个兼容值在 Linux 内核里面查找,如果没有找到的话就使用第二个兼容值查。

2、 model 属性
model 属性值也是一个字符串,一般 model 属性描述设备模块信息,比如名字什么的,比如:

model = "wm8960-audio";

3、 status 属性

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

4、 #address-cells 和#size-cells 属性

#address-cells 属性值决定了子节点 reg 属性中地址信息所占用的字长(32 位)
#size-cells 属性值决定了子节点 reg 属性中长度信息所占的字长(32 位)
#address-cells 和#size-cells 表明了子节点应该如何编写 reg 属性值,一般 reg 属性都是和地址有关的内容,和地址相关的信息有两种:起始地址和地址长度, reg 属性的格式一为:

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

每个“address length”组合表示一个地址范围,其中 address 是起始地址, length 是地址长度.
#address-cells 表明 address 这个数据所占用的字长, #size-cells 表明 length 这个数据所占用的字长

aips3: aips-bus@02200000 {compatible = "fsl,aips-bus", "simple-bus";#address-cells = <1>;#size-cells = <1>;dcp: dcp@02280000 {compatible = "fsl,imx6sl-dcp";reg = <0x02280000 0x4000>;};
};

说明 aips3: aips-bus@02200000 节点起始地址长度所占用的字长为 1,地址长度所占用的字长也为 1
子节点 dcp: dcp@02280000 的 reg 属性值为<0x02280000 0x4000>相当于设置了起始地址为 0x02280000,地址长度为 0x40000,但是 dcp的地址长度(范围)并没有 0x4000 这么多

5、 reg 属性
reg 属性一般用于描述设备地址空间资源信息,一般都是某个外设的寄存器地址范围信息,一般是(address, length)对。举例在4中已经说明。

6、 ranges 属性
ranges属性值可以为空或者按照(child-bus-address,parent-bus-address,length)格式编写的数字矩阵, ranges 是一个地址映射/转换表, ranges 属性每个项目由子地址、父地址和地址空间长度这三部分组成:

child-bus-address:子总线地址空间的物理地址,由父节点的#address-cells 确定此物理地址所占用的字长。

parent-bus-address: 父总线地址空间的物理地址,同样由父节点的#address-cells 确定此物理地址所占用的字长。

length: 子地址空间的长度,由父节点的#size-cells 确定此地址长度所占用的字长。

如果 ranges 属性值为空值,说明子地址空间和父地址空间完全相同,不需要进行地址转换。

 soc {#address-cells = <1>;#size-cells = <1>;compatible = "simple-bus";interrupt-parent = <&gpc>;ranges;//为空

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。

向节点追加或修改内容

imx6ull.dtsi 有以下内容,表示I2C节点。不同的I2C设备有不通的详细属性,采用追加节点方法不会对共有信息带来污染。

i2c1: i2c@021a0000 {#address-cells = <1>;#size-cells = <0>;compatible = "fsl,imx6ul-i2c", "fsl,imx21-i2c";reg = <0x021a0000 0x4000>;interrupts = <GIC_SPI 36 IRQ_TYPE_LEVEL_HIGH>;clocks = <&clks IMX6UL_CLK_I2C1>;status = "disabled";
};

现在要在 i2c1 节点下创建一个子节点

&i2c1 {clock-frequency = <100000>;pinctrl-names = "default";pinctrl-0 = <&pinctrl_i2c1>;status = "okay";fxls8471@1e {compatible = "fsl,fxls8471";reg = <0x1e>;position = <0>;interrupt-parent = <&gpio5>;interrupts = <0 8>;
};

子节点可以修改增加一些属性;
比如子节点中clock-frequency 新增加的属性。
status 状态由disabled变成 okay

设备树在目录中的体现

/proc/device-tree目录下,很熟悉的属性信息和目录,依次进入查看信息。

root@ATK-IMX6U:/proc/device-tree# ls -l
total 0
-r--r--r--  1 root root  4 Apr 11 17:16 '#address-cells'
drwxr-xr-x  2 root root  0 Apr 11 17:16 aliases
drwxr-xr-x  2 root root  0 Apr 11 17:16 backlight
drwxr-xr-x  2 root root  0 Apr 11 17:16 chosen
drwxr-xr-x  6 root root  0 Apr 11 17:16 clocks
-r--r--r--  1 root root 34 Apr 11 17:16 compatible
drwxr-xr-x  3 root root  0 Apr 11 17:16 cpus
drwxr-xr-x  3 root root  0 Apr 11 17:16 gpio_keys@0
drwxr-xr-x  2 root root  0 Apr 11 17:16 interrupt-controller@00a01000
drwxr-xr-x  4 root root  0 Apr 11 17:16 leds
drwxr-xr-x  2 root root  0 Apr 11 17:16 memory
-r--r--r--  1 root root 36 Apr 11 17:16 model
-r--r--r--  1 root root  1 Apr 11 17:16 name
drwxr-xr-x  2 root root  0 Apr 11 17:16 pxp_v4l2
drwxr-xr-x  5 root root  0 Apr 11 17:16 regulators
drwxr-xr-x  3 root root  0 Apr 11 17:16 reserved-memory
drwxr-xr-x  2 root root  0 Apr 11 17:16 sii902x-reset
-r--r--r--  1 root root  4 Apr 11 17:16 '#size-cells'
drwxr-xr-x 12 root root  0 Apr 11 17:16 soc
drwxr-xr-x  2 root root  0 Apr 11 17:16 sound
drwxr-xr-x  3 root root  0 Apr 11 17:16 spi4

1、在当前目录下执行 cat model

root@ATK-IMX6U:/proc/device-tree# cat model
Freescale i.MX6 ULL 14x14 EVK Boardroot@ATK-IMX6U:/proc/device-tree#
root@ATK-IMX6U:/proc/device-tree# cat compatible
fsl,imx6ull-14x14-evkfsl,imx6ullroot@ATK-IMX6U:/proc/device-tree#

model 的内容是“Freescale i.MX6 ULL 14x14 EVK Board”
compatible 的内容为“fsl,imx6ull-14x14-evkfsl,imx6ull”
打开文件 imx6ull-alientek-emmc.dts查看一下,这正是根节点“/”的 model 和 compatible 属性值

2、soc子节点

root@ATK-IMX6U:/proc/device-tree/soc# ls
'#address-cells'   busfreq             interrupt-parent  '#size-cells'
aips-bus@02000000  compatible          name              sram@00900000
aips-bus@02100000  dma-apbh@01804000   pmu               sram@00904000
aips-bus@02200000  gpmi-nand@01806000  ranges            sram@00905000

3、aliases 子节点

root@ATK-IMX6U:/proc/device-tree/aliases# ls
can0       gpio0  gpio4  i2c3  serial0  serial4  spi0  usbphy0
can1       gpio1  i2c0   mmc0  serial1  serial5  spi1  usbphy1
ethernet0  gpio2  i2c1   mmc1  serial2  serial6  spi2
ethernet1  gpio3  i2c2   name  serial3  serial7  spi3

与imx6ull.dtsi中的 aliases一致

4、chosen 子节点

chosen 并不是一个真实的设备, chosen 节点主要是为了 uboot 向 Linux 内核传递数据,重点是 bootargs 参数,一般.dts 文件中 chosen 节点通常为空或者内容很少, imx6ull-alientekemmc.dts 中 chosen 节点内容如下所示:

chosen {stdout-path = &uart1;
}

chosen 节点仅仅设置了属性“stdout-path”,表示标准输出使用 uart1。

root@ATK-IMX6U:/proc/device-tree/chosen# ls
bootargs  name  stdout-path

有bootargs 这不是uboot的启动参数吗?

root@ATK-IMX6U:/proc/device-tree/chosen# cat bootargs
console=ttymxc0,115200 root=/dev/mmcblk1p2 rootwait rwroot@ATK-IMX6U:/proc/device-tree/chosen#

cat 查看确实是启动信息
1,我们并没有在设备树中设置 chosen 节点的 bootargs 属性,那么 bootargs这个属性是怎么产生的如何关联起来的呢?
2,为什么和uboot中的参数不一致?

chosen 节点的 bootargs 属性不是我们在设备树里面设置的,那么只有一种可能,那就是 uboot 自己在 chosen 节点里面添加了 bootargs 属性,并且设置 bootargs 属性的值为 bootargs环境变量的值。

uboot 源码中搜索“chosen”,在文件 common/fdt_support.c中

int fdt_chosen(void *fdt)
{//寻找chosen节点nodeoffset = fdt_find_or_add_subnode(fdt, 0, "chosen");if (nodeoffset < 0)return nodeoffset;//读取bootargs环境str = getenv("bootargs");
}

Linux 内核解析 DTB 文件

启动内核流程函数

start_kernel 函数中最终调用了函数为unflatten_dt_node

帮助文档信息

设备树是用来描述板子上的设备信息的,不同的设备其信息不同,反映到设备树中就是属性不同。那么我们在设备树中添加一个硬件对应的节点的时候从哪里查阅相关的说明呢?路径为:Linux 源码目录/Documentation/devicetree/bindings,

比如我们现在要想在 I.MX6ULL 这颗 SOC 的 I2C 下添加一个节点,那么就可以查看Documentation/devicetree/bindings/i2c/i2c-imx.txt,此文档详细的描述了 I.MX 系列的 SOC 如何在设备树中添加 I2C 设备节点,文档内容如下所示:

root@ubuntu:/home/wy/imx6ul/kernel/Documentation/devicetree/bindings/i2c# cat i2c-imx.txt
* Freescale Inter IC (I2C) and High Speed Inter IC (HS-I2C) for i.MXRequired properties:
- compatible :- "fsl,imx1-i2c" for I2C compatible with the one integrated on i.MX1 SoC- "fsl,imx21-i2c" for I2C compatible with the one integrated on i.MX21 SoC- "fsl,vf610-i2c" for I2C compatible with the one integrated on Vybrid vf610 SoC
- reg : Should contain I2C/HS-I2C registers location and length
- interrupts : Should contain I2C/HS-I2C interrupt
- clocks : Should contain the I2C/HS-I2C clock specifierOptional properties:
- clock-frequency : Constains desired I2C/HS-I2C bus clock frequency in Hz.The absence of the propoerty indicates the default frequency 100 kHz.
- dmas: A list of two dma specifiers, one for each entry in dma-names.
- dma-names: should contain "tx" and "rx".Examples:i2c@83fc4000 { /* I2C2 on i.MX51 */compatible = "fsl,imx51-i2c", "fsl,imx21-i2c";reg = <0x83fc4000 0x4000>;interrupts = <63>;
};i2c@70038000 { /* HS-I2C on i.MX51 */compatible = "fsl,imx51-i2c", "fsl,imx21-i2c";reg = <0x70038000 0x4000>;interrupts = <64>;clock-frequency = <400000>;
};i2c0: i2c@40066000 { /* i2c0 on vf610 */compatible = "fsl,vf610-i2c";reg = <0x40066000 0x1000>;interrupts =<0 71 0x04>;dmas = <&edma0 0 50>,<&edma0 0 51>;dma-names = "rx","tx";
};

设备树节点的操作函数

1、查找节点的 of 函数

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

1、 of_find_node_by_name 函数

//通过节点名字查找指定的节点
struct device_node *of_find_node_by_name(struct device_node *from,
const char *name);
//from:开始查找的节点,如果为 NULL 表示从根节点开始查找整个设备树。
//name:要查找的节点名字

2、of_find_node_by_type 函数

//通过device_type查找指定的节点
struct device_node *of_find_node_by_type(struct device_node *from, const char *type)

3、 of_find_compatible_node 函数

device_type 和 compatible 这两个属性查找指定的节点
struct device_node *of_find_compatible_node(struct device_node *from,const char *type,const char *compatible)

4、of_find_matching_node_and_match 函数

//通过 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)

5、 of_find_node_by_path 函数

//通过路径来查找指定的节点
inline struct device_node *of_find_node_by_path(const char *path)

2、查找父/子节点的 OF 函数

1、 of_get_parent 函数
用于获取指定节点的父节点

struct device_node *of_get_parent(const struct device_node *node)
//node 要查找的父节点的节点

2、 of_get_next_child 函数

//用迭代的查找子节点
struct device_node *of_get_next_child(const struct device_node *node,struct device_node *prev)
//node:父节点。
//prev:前一个子节点,也就是从哪一个子节点开始迭代的查找下一个子//节点。可以设置为NULL,表示从第一个子节点开始。
//返回 找到的下一个子节点。

3、提取属性值的 OF 函数

property 结构体

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

1、 of_find_property 函数

property *of_find_property(const struct device_node *np,const char *name,int *lenp)
//np:设备节点。
//name: 属性名字。
//lenp:属性值的字节数
//返回找到的属性

2、 of_property_count_elems_of_size 函数
用于获取属性中元素的数量,比如 reg 属性值是一个数组,那么使用此函数可以获取到这个数组的大小

int of_property_count_elems_of_size(const struct device_node *np,const char *propname,int elem_size)
//np:设备节点。
//proname: 需要统计元素数量的属性名字。
//elem_size:元素长度。
//返回 得到的属性元素数量

3、 of_property_read_u32_index 函数
从属性中获取指定标号的 u32 类型数据值(无符号 32
位),比如某个属性有多个 u32 类型的值,那么就可以使用此函数来获取指定标号的数据值

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

4、
of_property_read_u8_array 函数
of_property_read_u16_array 函数
of_property_read_u32_array 函数
of_property_read_u64_array 函数

分别是读取属性中 u8、 u16、 u32 和 u64 类型的数组数据,比如大多数的 reg 属性都是数组数据,可以使用这 4 个函数一次读取出 reg 属性中的所有数据

5、
of_property_read_u8 函数
of_property_read_u16 函数
of_property_read_u32 函数
of_property_read_u64 函数

有些属性只有一个整形值,这四个函数就是用于读取这种只有一个整形值的属性,分别用于读取 u8、 u16、 u32 和 u64 类型属性值

6、 of_property_read_string 函数

//用于读取属性中字符串值
int of_property_read_string(struct device_node *np,
const char *propname,
const char **out_string)

7、 of_n_addr_cells 函数
用于获取#address-cells 属性值

8、 of_n_size_cells 函数
of_size_cells 函数用于获取#size-cells 属性值

9、of_iomap 函数
采用设备树以后就可以直接通过 of_iomap 函数来获取内存地址所对应的虚拟地址,不需要使用 ioremap 函数了

linux 设备树(.dts)实战解析相关推荐

  1. linux dts 语法格式,设备树DTS格式解析

    8种机械键盘轴体对比 本人程序员,要买一个写代码的键盘,请问红轴和茶轴怎么选? 宿主机: ubuntu16.04 开发板: tq-imx6ull 内核版本: linux-4.1.15 用实例讲解下设备 ...

  2. linux 设备树dts基础

    ​ ​ 活动地址:CSDN21天学习挑战赛 学习的最大理由是想摆脱平庸,早一天就多一份人生的精彩:迟一天就多一天平庸的困扰.各位小伙伴,如果您: 想系统/深入学习某技术知识点- 一个人摸索学习很难坚持 ...

  3. linux设备树dts文件详解

    1.什么是设备树? (1)设备树(dt:device tree)是linux内核采用的参数表示和传递技术,在系统引导启动阶段进行设备初始化的时候,将设备树中描述的硬件信息传递给操作系统: (2)dts ...

  4. i.MX6ULL终结者Linux设备树DTS设备树语法结构

    文章目录 1 dtsi头文件 2 设备节点信息 3 设备节点及label的命名 4 标准属性 5 根节点compatible属性 6 在设备节点中添加或修改内容 一般情况下,我们不会从头编写一个完整的 ...

  5. linux设备树DTS到是是啥玩意

    一直想搞明白,自从linux开始使用设备树后,从哪里开始加载和bootloadt kenel之间怎么关联,然后总线驱动如何将这些设备挂上去的. 下周开始总结. 先转载一些基本概念: 简介 dts 硬件 ...

  6. Linux 设备树 DTS 语法

    DTS 语法 .dtsi 头文件 设备树支持头文件,设备树的头文件扩展名为.dtsi //linux-5.5.4\linux-5.5.4\arch\arm\boot\dts\s5pv210-smdkv ...

  7. Linux下设备树dts内容(详细)总结及示例解析

    文章目录 一.简介 二.设备树基础内容 2.1 设备树文件存放路径 2.2 DTS.DTB和DTC关系 2.3 传统驱动代码和使用设备树的对比 三.设备树内容属性介绍 3.1 节点名称 3.2 com ...

  8. Linux设备树 .dtb文件,查看“第二课:设备树的规范(dts和dtb)”的源代码

    因为以下原因,您没有权限编辑本页: 您所请求的操作仅限于该用户组的用户使用:用户 您可以查看与复制此页面的源代码.= 第01节_DTS格式= dts文件通过编译生成dtb格式文件 [[File:ldd ...

  9. [ZedBoard移植嵌入式Linux教程(9,10)]编译设备树dts为dtb,制作根文件系统

    九.编译设备树dts为dtb 前面的linux内核源码目录中已经包含了设备树编译器Device Tree Compiler(dtc),在目录arch/arm/boot/dts/目录下. 将前面生成的x ...

最新文章

  1. 知识星球作业(第5周) - 关于view的知识
  2. 用access做考场桌贴_利用Word、Excel、Access进行考务安排及学生成绩分析的有效途径-教育文档...
  3. Android5.0源码分析—— Zygote进程分析
  4. o2o家庭助手demo
  5. lua怎么嵌入php,linux下安装php的lua扩展
  6. SQL注入漏洞入门(操作实现)
  7. 使用递归函数求解字符串的逆置问题
  8. php页面源代码怎么优化,php代码优化及php相关问题总结
  9. Atitit. 软件---多媒体区---- jmf 2.1.1 Java Media Framework 支持的格式
  10. 打码兔官网 验证码识别 远程答题服务 代答平台 验证码识别软件下载
  11. java+mysql学科竞赛管理系统(java,web)
  12. 443端口与80端口
  13. python中kwlist是什么意思_Python keyword.kwlist方法代碼示例
  14. 【运筹学】整数规划 ( 整数规划求解方法 | 指派问题 )
  15. BS 476-31 与BS 476-33 测试方法是类似的吗?
  16. 安卓小项目之刀刀人脸识别系统
  17. 经验分享:计算机专业求职面试,这 5 句自我介绍模板记好了!
  18. 极大似然估计详解,写的太好了!
  19. 向SQL Server 中导入长文本
  20. 大型互联网支付公司职位--朝阳

热门文章

  1. 启动 Scala REPL 报错:java.lang.NoClassDefFoundError:javax/script/Compilable
  2. 压力测试工具Apache JMeter:11:搭建容器化分布式测试环境
  3. 云呐|RFID固定资产管理软件系统怎么用
  4. 创建可引导的Ubuntu USB闪存盘
  5. 计算机协会维修部面试,协会社团面试自我介绍
  6. 开学后的认识与计划,目标
  7. 外设驱动库开发笔记50:HP203B气压传感器驱动
  8. 单体架构-->SOA架构-->微服务架构
  9. SQL注入-Day15
  10. 股票买卖(C/C++)