DTS入门知识

本文目标是了解dts基本语法,可以尝试去看内核dts中的文件,follow去配置。

一、dts产生原因

DTS即Device Tree Source 设备树源码, DeviceTree是一种描述硬件的数据结构,它起源于OpenFirmware (OF)。

它替代arch/arm/plat-xxx和arch/arm/mach-xxx中的板级spec代码,便于code管理。

ARM平台的相关code相关规范调整:

1、ARM的核心代码仍然保存在arch/arm目录下

2、ARM SOC core architecture code保存在arch/arm目录下

3、ARM SOC的周边外设模块的驱动保存在drivers目录下

4、ARM SOC的特定代码在arch/arm/mach-xxx目录下

5、ARM SOC board specific的代码被移除,由Device Tree机制来负责传递硬件拓扑和硬件资源信息。

本质上,Device Tree改变了原来用hardcode方式将HW配置信息嵌入到内核代码的方法,改用bootloader传递一些参数。

如果我们认为kernel是一个black box,那么其输入参数应该包括:

a.识别platform的信息   b. runtime的配置参数   c.设备的拓扑结构以及特性

对于嵌入式系统,在系统启动阶段,bootloader会加载内核并将控制权转交给内核,此外,还需要把上述的三个参数信息传递给kernel,以便kernel可以有较大的灵活性。在linux kernel中,Device Tree的设计目标就

是如此。

二、dts基本知识

2.1 dts加载过程

如果要使用Device Tree,首先用户要了解自己的硬件配置和系统运行参数,并把这些信息组织成Device Tree source file。通过DTC(Device Tree Compiler),可以将这些适合人类阅读的Device Tree source file变成适合机器处理的Device Tree binary file(有一个更好听的名字,DTB,device tree blob)。在系统启动的时候,boot program(例如:firmware、bootloader)可以将保存在flash中的DTB copy到内存(当然也可以通过其他方式,例如可以通过bootloader的交互式命令加载DTB,或者firmware可以探测到device的信息,组织成DTB保存在内存中),并把DTB的起始地址传递给client program(例如OS kernel,bootloader或者其他特殊功能的程序)。对于计算机系统(computer system),一般是firmware->bootloader->OS,对于嵌入式系统,一般是bootloader->OS。

在高通msm8992平台:

sbl将烧写在emmc中的cdt.bin进行读取和处理,获得nPlatform和nSubtype,如果没有CDT分区,那么就使用代码里配置的cdt,存入共享内存;

lk将从共享内存中获得nPlatform和nSubtype进行相应处理,确定dtb entry,然后选择一个对应的dtb(所有dtb保存在boot.img中)从emmc中读进内存地址hdr->tags_addr,这个参数会传递给kernel;

kernel通过传入的dtb地址进行设备的创建。

2.2 dts描述信息

Device Tree由一系列被命名的结点(node)和属性(property)组成,而结点本身可包含子结点。所谓属性,其实就是成对出现的name和value。在Device Tree中,可描述的信息包括(原先这些信息大多被hard code到kernel中):

CPU的数量和类别

内存基地址和大小

总线和桥

外设连接

中断控制器和中断使用情况

GPIO控制器和GPIO使用情况

Clock控制器和Clock使用情况

它基本上就是画一棵电路板上CPU、总线、设备组成的树,Bootloader会将这棵树传递给内核,然后内核可以识别这棵树,并根据它展开出Linux内核中的platform_device、i2c_client、spi_device等设备,而这些设备用到的内存、IRQ等资源,也被传递给了内核,内核会将这些资源绑定给展开的相应的设备。

是否Device Tree要描述系统中的所有硬件信息?答案是否定的。基本上,那些可以动态探测到的设备是不需要描述的,例如USB device。不过对于SOC上的usb host controller,它是无法动态识别的,需要在devicetree中描述。同样的道理,在computersystem中,PCI device可以被动态探测到,不需要在device tree中描述,但是PCI bridge如果不能被探测,那么就需要描述之。

.dts文件是一种ASCII 文本格式的Device Tree描述,此文本格式非常人性化,适合人类的阅读习惯。基本上,在ARM Linux在,一个.dts文件对应一个ARM的machine,一般放置在内核的arch/arm/boot/dts/目录。由于一个SoC可能对应多个machine(一个SoC可以对应多个产品和电路板),势必这些.dts文件需包含许多共同的部分,Linux内核为了简化,把SoC公用的部分或者多个machine共同的部分一般提炼为.dtsi,类似于C语言的头文件。其他的machine对应的.dts就include这个.dtsi。

譬如在arch/arm/boot/dts/qcom/目录下,高通的很多.dtsi都include了skeleton.dtsi或者skeleton64.dtsi。

正常情况下所有的dts文件以及dtsi文件都含有一个根节点”/”,这样include之后就会造成有很多个“根节点”。按理说 device tree既然是一个树,那么其只能有一个根节点,所有其他的节点都是派生于根节点的child node。其实Device TreeCompiler会对DTS的node进行合并,最终生成的DTB中只有一个root node.

device tree的基本单元是node。这些node被组织成树状结构,除了root node,每个node都只有一个parent。一个device tree文件中只能有一个root node。每个node中包含了若干的property/value来描述该node的一些特性。每个node用节点名字(node name)标识,节点名字的格式是node-name@unit-address。如果该node没有reg属性(后面会描述这个property),那么该节点名字中必须不能包括@和unit-address。unit-address的具体格式是和设备挂在那个bus上相关。例如对于cpu,其unit-address就是从0开始编址,依次加一。而具体的设备,例如以太网控制器,其unit-address就是寄存器地址。rootnode的node name是确定的,必须是“/”。

在一个树状结构的device tree中,如何引用一个node呢?要想唯一指定一个node必须使用full path,例如/node-name-1/node-name-2/node-name-N

2.3 dts组成结构示例

/ { "/" 表示root结点,该结点下有两个子结点node1和node2

node1 { 结点"node1"下又含有子结点,本例中为"child-node1" 和 "child-node2",各结点都有一系列属性

a-string-property = "Astring";属性是字符串

a-string-list-property = "firststring", "second string";字符串数组

a-byte-data-property = [0x01 0x23 0x340x56];二进制数组

child-node1 {

first-child-property;

second-child-property = <1>;Cells(由u32整数组成)

a-string-property = "Hello,world";

};

child-node2 {

};

};

node2 {

an-empty-property;属性为空

a-cell-property = <1 2 3 4>; /* each number (cell) is a uint32 */

child-node1 {

};

};

};

上述.dts文件并没有什么真实的用途,但它基本表征了一个DeviceTree源文件的结构。

2.4 dts语法

完整的Device Tree可以将一个PCB摆在你眼前,下面我们一起来看一下:

下面以一个最简单的machine为例来看如何写一个.dts文件。假设此machine的配置如下:
1个双核ARMCortex-A9 32位处理器;
         ARM的local bus上的内存映射区域分布了2个串口(分别位于0x101F1000 和 0x101F2000)、GPIO控制器(位于0x101F3000)、SPI控制器(位于0x10115000)、中断控制器(位于0x10140000)和一个external bus桥;
         External bus桥上又连接了SMC SMC91111 Ethernet(位于0x10100000)、I2C控制器(位于0x10160000)、64MB NOR Flash(位于0x30000000);
         External bus桥上连接的I2C控制器所对应的I2C总线上又连接了Maxim DS1338实时钟(I2C地址为0x58)。

其对应的.dts文件为:

/ {

compatible = "acme,coyotes-revenge";

#address-cells = <1>;  子结点需要一个cell描述地址

#size-cells = <1>;  子结点需要一个cell描述长度

interrupt-parent = <&intc>;

cpus {

#address-cells = <1>;

#size-cells = <0>;

cpu@0 {

compatible = "arm,cortex-a9";

reg = <0>;

};

cpu@1 {

compatible = "arm,cortex-a9";

reg = <1>;

};

};

serial@101f1000 {  串口

compatible = "arm,pl011";

reg = <0x101f1000 0x1000 >;

interrupts = < 1 0 >;

};

serial@101f2000 {  串口

compatible = "arm,pl011";

reg = <0x101f2000 0x1000 >;

interrupts = < 2 0 >;

};

gpio@101f3000 {  GPIO控制器

compatible = "arm,pl061";

reg = <0x101f3000 0x1000

0x101f4000 0x0010>;

interrupts = < 3 0 >;

};

intc: interrupt-controller@10140000 {  中断控制器

compatible = "arm,pl190";

reg = <0x10140000 0x1000 >;

interrupt-controller;

#interrupt-cells = <2>;

};

spi@10115000 {  spi控制器

compatible = "arm,pl022";

reg = <0x10115000 0x1000 >;  起始地址为0x10115000,长度为0x1000

interrupts = < 4 0 >;

};

external-bus {  external bus桥

#address-cells = <2>  子结点需要两个cell描述地址,片选

#size-cells = <1>;  子结点需要一个cell描述长度

ranges = <0 0  0x10100000   0x10000     // Chipselect 1, Ethernet  片选0 0,地址0x10100000 ,长度0x10000

1 0  0x10160000   0x10000     // Chipselect 2, i2c controller

2 0  0x30000000   0x1000000>; // Chipselect 3, NOR Flash

ethernet@0,0 {

compatible = "smc,smc91c111";

reg = <0 0 0x1000>;

interrupts = < 5 2 >;

};

i2c@1,0 {

compatible = "acme,a1234-i2c-bus";

#address-cells = <1>;  rtc需要一个cell描述地址

#size-cells = <0>;  rtc不需要0描述长度

reg = <1 0 0x1000>;

rtc@58 {

compatible = "maxim,ds1338";

reg = <58>;

interrupts = < 7 3 >;

};

};

flash@2,0 {

compatible = "samsung,k8f1315ebm", "cfi-flash";

reg = <2 0 0x4000000>;

};

};

};

注释不是太多,下面来详细分类解释:

2.4.1 compatible

上述.dts文件中,root结点"/"的compatible 属性compatible = "acme,coyotes-revenge";定义了系统的名称,它的组织形式为:<manufacturer>,<model>。Linux内核透过root结点"/"的compatible 属性即可判断它启动的是什么machine。
         在.dts文件的每个设备,都有一个compatible属性,compatible属性用户驱动和设备的绑定。compatible属性是一个字符串的列表,列表中的第一个字符串表征了结点代表的确切设备,形式为"<manufacturer>,<model>",其后的字符串表征可兼容的其他设备。可以说前面的是特指,后面的则涵盖更广的范围。

如在arch/arm/boot/dts/vexpress-v2m.dtsi中的Flash结点:

flash@0,00000000 {

compatible = "arm,vexpress-flash", "cfi-flash";

reg = <0 0x00000000 0x04000000>,

<1 0x00000000 0x04000000>;

bank-width = <4>;

};

compatible属性的第2个字符串"cfi-flash"明显比第1个字符串"arm,vexpress-flash"涵盖的范围更广。

2.4.2 name@unit-address

接下来root结点"/"的cpus子结点下面又包含2个cpu子结点,描述了此machine上的2个CPU,并且二者的compatible 属性为"arm,cortex-a9"。
         注意cpus和cpus的2个cpu子结点的命名,它们遵循的组织形式为:<name>[@<unit-address>],<>中的内容是必选项,[]中的则为可选项。name是一个ASCII字符串,用于描述结点对应的设备类型,如网卡适配器对应的结点name宜为ethernet,表示这个是网卡。如果一个结点描述的设备有地址,则应该给出@unit-address。多个相同类型设备结点的name可以一样,只要unit-address不同即可,如本例中含有cpu@0、cpu@1以及serial@101f0000与serial@101f2000这样的同名结点。设备的unit-address地址也经常在其对应结点的reg属性中给出。

2.4.3 reg address-cells size-cells

设备的地址特性根据一下几个属性来控制:

● reg

● #address-cells

● #size-cells

reg意为region,区域。格式为:

reg =<address1 length1 [address2 length2] [address3 length3]>;

父类的address-cells和size-cells决定了子类的相关属性要包含多少个cell,如果子节点有特殊需求的话,可以自己再定义,这样就可以摆脱父节点的控制。

address-cells决定了address1/2/3包含几个cell,size-cells决定了length1/2/3包含了几个cell,用上面的dts文件内容举例子说明:

例子2.4.3.1

root结点的#address-cells = <1>;和#size-cells = <1>;决定了serial、gpio、spi等结点的address和length字段的长度分别为1

serial@101f1000 {

compatible = "arm,pl011";

reg = <0x101f1000 0x1000 >;地址0x101f1000,长度 0x1000

interrupts = < 1 0 >;

};

例子2.4.3.2

i2c控制器模块下的rtc模块。因为I2C设备只是被分配在一个地址上,不需要其他任何空间,所以只需要一个address的cell就可以描述完整,不需要size-cells

/ {

compatible = "acme,coyotes-revenge";

#address-cells = <1>;  子结点需要一个cell描述地址

#size-cells = <1>;  子结点需要一个cell描述长度

interrupt-parent = <&intc>;

...

external-bus {

#address-cells = <2>

#size-cells = <1>;

...

i2c@1,0 {

compatible = "acme,a1234-i2c-bus";

#address-cells = <1>;重新写address-cells

#size-cells = <0>;重新写address-cells

reg = <1 0 0x1000>;

rtc@58 {

compatible ="maxim,ds1338";

reg = <58>;只需要一个address cell,不需要cell再描述长度

};

};

...

};

例子2.4.3.3

当需要描述的设备不是本地设备时,就需要描述一个从设备地址空间到CPU地址空间的映射关系,这里就需要用到ranges属性。还是以上边的external-bus举例

ranges属性为一个地址转换表。表中的每一行都包含了子地址、父地址、在自地址空间内的区域大小。他们的大小(包含的cell)分别由子节点的address-cells的值、父节点的address-cells的值和子节点的size-cells来决定。

/ {

compatible = "acme,coyotes-revenge";

#address-cells = <1>;  子结点需要一个cell描述地址

#size-cells = <1>;  子结点需要一个cell描述长度

interrupt-parent = <&intc>;

...

0 0 两个cell,由子节点external-bus的address-cells=<2>决定;

0x10100000 一个cell,由父节点(/)的address-cells=<1>决定;

0x10000 一个cell,由子节点external-bus的size-cells=<1>决定。

最终第一行说明的意思就是:片选0,偏移0(选中了网卡),被映射到CPU地址空间的0x10100000~0x10110000中,地址长度为0x10000。

external-bus {

#address-cells = <2>

#size-cells = <1>;

ranges = <00  0x10100000   0x10000     //Chipselect 1, Ethernet

1 0 0x10160000   0x10000     // Chipselect 2,i2c controller

2 0 0x30000000   0x1000000>;  // Chipselect 3, NORFlash

};

进阶例子2.4.3.4

pci@0x10180000 {

compatible ="arm,versatile-pci-hostbridge", "pci";

reg = <0x10180000 0x1000>;

interrupts = <8 0>;

bus-ranges = <0 0>;

#address-cells = <3>

#size-cells = <2>;

ranges = <0x42000000 0 0x800000000x80000000 0 0x20000000

0x02000000 0 0xa00000000xa0000000 0 0x10000000

0x01000000 0 0x000000000xb0000000 0 0x01000000>;

};

像之前描述过的本地总线一样,PCI地址空间与CPU地址空间是完全分离的,所以这里需要通过定义ranges属性进行地址转化。

#address-cells定义PCI使用3个cell,并且PCI的地址范围通过两个单位就可以解读。所以,首先的问题就是,为什么需要用3个32位的cell来描述一个PCI地址。

这三个cell分别代表物理地址高位、中位、低位:

1 phys.high cell : npt000ss bbbbbbbb dddddfff rrrrrrrr

2 phys.mid cell : hhhhhhh hhhhhhhh hhhhhhhh hhhhhhh

3 phys.low cell : llllllll llllllll llllllll llllllll

PCI地址为64位宽度,编码在phys.mid和phys.low中。真正重要的东西在于phys.high这一位空间中:

n:代表重申请空间标志(这里没有使用)

p:代表预读空间(缓存)标志

t:别名地址标志(这里没有使用)

ss:空间代码

00:设置空间

01:IO空间

10:32位存储空间

11:64位存储空间

bbbbbbbb: PCI总线号。PCI有可能是层次性架构,所以我们可能需要区分一些子-总线

ddddd:设备号,通常由初始化设备选择信号IDSEL连接时申请。

fff:功能序号,有些多功能PCI设备可能用到。

rrrrrrrr:注册号,在设置周期使用。

回头再看这个ranges分表代表了什么。

ranges =<0x42000000 0 0x80000000 0x80000000 0 0x20000000

0x02000000 0 0xa0000000 0xa0000000 00x10000000

0x01000000 0 0x00000000 0xb0000000 00x01000000>;

父节点address-cells为1,子节点address-cells为3,子节点size-cells为2。则第一行可以这样划分:

0x42000000 00x80000000 子节点地址| 0x80000000 父节点地址| 0 0x20000000 地址空间长度|

0x42000000为phys.high,第一高字节为01000010,则p为1,ss为10,即申请32位存储空间为缓存空间。phys.mid为0,phys.low为0x80000000,他们共同组成了PCI地址,即表示从PCI总线的0x80000000地址处申请出一个32位的存储空间作为缓存。后边的那个cell0x80000000 0 0x20000000代表到CPU空间后的参数,申请的地址被映射到CPU空间的0x80000000地址处,大小共计0x20000000(512MB)。

2.4.5 interrupt

描述中断连接需要四个属性:

1. interrupt-controller 一个空属性用来声明这个node接收中断信号;

2. #interrupt-cells 这是中断控制器节点的属性,用来标识这个控制器需要几个单位做中断描述符;

3. interrupt-parent 标识此设备节点属于哪一个中断控制器,如果没有设置这个属性,会自动依附父节点的;

4. interrupts 一个中断标识符列表,表示每一个中断输出信号。

如果有两个,第一个是中断号,第二个是中断类型,如高电平、低电平、边缘触发等触发特性。对于给定的中断控制器,应该仔细阅读相关文档来确定其中断标识该如何解析。

/ {

compatible = "acme,coyotes-revenge";

#address-cells = <1>;

#size-cells = <1>;

interrupt-parent = <&intc>; root结点指定中断控制器intc

...

intc: interrupt-controller@10140000 {

compatible = "arm,pl190";

reg = <0x10140000 0x1000 >;

interrupt-controller;  这个node接收中断信号

#interrupt-cells = <2>;  2个cell做中断描述符

};

对于ARM GIC中断控制器而言,#interrupt-cells为3,它3个cell的具体含义需要参考文档

kernel/Documentation/devicetree/bindings/arm/gic.txt

-#interrupt-cells : Specifies the number of cells needed to encode an

interrupt source.  The type shall be a <u32> and the valueshall be 3.

The 1st cell is the interrupt type; 0 for SPIinterrupts, 1 for PPI

interrupts.

The 2nd cell contains the interrupt numberfor the interrupt type.

SPI interrupts are in the range [0-987].  PPI interrupts are in the

range [0-15].

The 3rd cell is the flags, encoded asfollows:

bits[3:0] trigger type and level flags.

1= low-to-high edge triggered

2= high-to-low edge triggered

4= active high level-sensitive

8= active low level-sensitive

一个设备还可能用到多个中断号。对于ARM GIC而言,若某设备使用了SPI的168、169号2个中断,且都是高电平触发,则该设备结点的interrupts属性可定义为:

interrupts =<0 168 4>, <0 169 4>;

三、dts与驱动

●没有使用dts之前的bsp和driver

板级spec代码

#ifdefCONFIG_LEDS_CTL

structplatform_device s3c_device_leds_ctl = {

.name  = "leds",

.id             = -1,

};

#endif

driver

static structplatform_driver leds_driver = {

.probe = leds_probe,

.remove = leds_remove,

.suspend = leds_suspend,

.resume = leds_resume,

.driver = {

.name= DRIVER_NAME,//leds

.owner= THIS_MODULE,

},

};

●使用dts之后的bsp和driver

dts文件

&soc {

i2c@f9928000 { /* BLSP1 QUP6 */

status= "ok";

nfc-nci@76{

compatible = "brcm,bcm2079x";

...

};

driver

static structof_device_id bcm_match_table[] = {

{.compatible = "brcm,bcm2079x"},

{}

}

static structi2c_driver bcm2079x_driver = {

.id_table = bcm2079x_id,

.probe = bcm2079x_probe,

.remove = bcm2079x_remove,

.driver = {

.owner= THIS_MODULE,

.name= "bcm2079x-i2c",

.of_match_table= bcm_match_table,

},

};

四、具体案例

用第三节提到的nfc进行分析,里面有很多的内容可以去Document/devicetree/bindings查找

root@icesky_msm8992:/sys/bus/i2c/devices/6-0076# cat name

bcm2079x

&soc {

i2c@f9928000 {/* BLSP1 QUP6 */

status= "ok";

nfc-nci@76 {

compatible = "brcm,bcm2079x";匹配

reg = <0x76>;地址cell=0x76,没有长度描述cell

gpio控制器msm_gpio

qcom,wake-gpio =<&msm_gpio 29 0x00>; 29pin,0x00 -- unused

qcom,en-gpio =<&msm_gpio 30 0x00>;30pin

qcom,irq-gpio =<&msm_gpio 9 0x00>;9pin

qcom,clk-src = "BBCLK2";nfc时钟源,跟驱动有关

interrupt-parent =<&msm_gpio>;属于msm_gpio中断控制器

interrupts = <9 0>;中断标识符列表 nfc readinterrupt, gpio-clk-req interrupt

interrupt-names = "nfc_irq";中断名称字符串类型,与驱动有关kernel/drivers/of/irq.c

pinctrl-names ="nfc_active","nfc_suspend";pin ctrl字符串类型

pinctrl-0 = <&nfc_int_active&nfc_disable_active &nfc_wake_active>;见4.3节

pinctrl-1 = <&nfc_int_suspend&nfc_disable_suspend &nfc_wake_suspend>;

clocks = <&clock_rpm clk_bb_clk2_pin>;

clock-names = "brcm_nfc_clk";

};

};

};

4.1 gpio

上面的wake-gpio、en-gpio、irq-gpio与driver相关

structbcm2079x_dev {

...

unsigned int wake_gpio;

unsigned int en_gpio;

unsigned int irq_gpio;

...

};

4.2 interrupt

msm_gpio既是中断控制器,也是gpio控制器

gp: gp{

qcom,num-pins = <146>;

#qcom,pin-cells = <1>;

msm_gpio: msm_gpio {

compatible = "qcom,msm-tlmm-gp";

gpio-controller;可以作为gpio控制器

#gpio-cells = <2>;2个cell做gpio描述符,第一个是pin number,第二个是指定可选参数

interrupt-controller;接收中断信号

#interrupt-cells = <2>;2个cell做中断描述符,第一个是pin number,第二个是指定可选参数中断类型

qcom,direct-connect-irqs = <8>;8个GPIO可以直接连中断信号

num_irqs = <146>;146个pins可以作为中断源

};

};

4.3 pinctl

我们挑下nfc_wake_active查查dts里面是什么

pmx_nfc_wake_reg{

qcom,pins = <&gp 9>; gp的配置见4.2节 pin number == 9

qcom,pin-func = <0>; 为pin设置function

qcom,num-grp-pins = <1>;pin group number = 1,因为本例只有一个gp 9

label = "pmx_nfc_wak";pin group中的身份识别

nfc_wake_active:active {

drive-strength= <6>;信号强度 6MA

bias-pull-up;上拉引脚

output-low;输出模式low level

};

nfc_wake_suspend: suspend {

drive-strength= <6>;

bias-pull-down;/* pull down */

output-low;

};

};

4.4 clk

nfc-nci@76 {

...

clocks = <&clock_rpm clk_bb_clk2_pin>;#defineclk_bb_clk2_pin 0x498938e5

clock-names = "brcm_nfc_clk";drivers将使用该name去匹配

};

clock_rpm: qcom,rpmcc@fc401880 {

compatible ="qcom,rpmcc-8992";

reg = <0xfc401880 0x4>;

reg-names = "cc_base";

#clock-cells = <1>;     0 表示单一时钟输出,1表示多时钟

};

(0)

相关推荐

  • 一文搞定 Linux 设备树

    设备树是一种描述硬件的数据结构,它起源于OpenFirmware(OF). 在Linux 2.6中, ARM架构的板极硬件细节过多地被硬编码在arch/arm/plat-xxx和arch/arm/ma ...

  • JAVA数据结构——链表:引用赋值图解

    链表 一.链表的原理 二.深入理解引用赋值 1. p = q 2. p = q.next 3. p.next = q 4. p.next = q.next 一.链表的原理 元素(element):真实 ...

  • F1C100S添加SPI LCD液晶驱动

    https://www.cnblogs.com/listenscience/p/13619930.html在使用F1C100S的时候常常会使用小尺寸的液晶屏,比如市场上比较常见的1.14寸液晶屏,下面 ...

  • 经典实用的风机盘管入门知识

    一.风机盘管简介与特点: 风机盘管是中央空调理想的末端产品,风机盘管广泛应用于宾馆.办公楼.医院.商住.科研机构等场所.其工作原理是风机将室内空气或室外混合空气通过表冷器进行冷却或加热后送入室内,使室 ...

  • 基础的茶道入门知识!

    ◆ ◆ ◆ 了解中国茶叶,已经有几千年茶文化,确实了解起来比较难,很多新茶友不知道如何下手,建议大家从以下几个方面好好了解一下. 1 认识中国茶 茶道指的是泡茶规范,为发挥各类茶性优点,抑制不足之处, ...

  • 围棋入门知识—吃子方法:【抱吃】

    原创文章,版权归白小夕围棋公众号所有, 转载请先联系白夕, 否则一律按侵权处理,以每篇100元索取赔偿. 跟着白小夕 学不会围棋,也可以学会装逼 大家好,我是白夕. 今天,来学习围棋里的抱吃, 就像这 ...

  • 美股投资入门知识----散户须知的基础篇

    并把小熊猫[设为星标] 大家好,这段时间也是闲着,还给刚刚入门的一些新朋友,做一些知识的普及.这期我们说说,美股港股入门必备知识说明的第一篇,美股港股开户与入金常识篇 这里写一篇有关于美股港股投资入门 ...

  • 素描入门知识大全,收藏一文,享用一生!

    素描,每个想学画画的人必经的过程 现在美术培训的学生,正在练习素描基础 无论是专业的,非专业的绘画者 应该都对素描既爱又恨 今天给大家介绍下素描的一些常识性的东西 让大家更接触素描之前,更了解他 / ...

  • 占星课第一节 星座入门知识

    占星课第一节 星座入门知识

  • 摄影入门知识:如何设置相机光圈、快门、感光度?

    关于光圈.快门.感光度(ISO)的知识给大家讲过很多,但是还是有很多人在问我:光圈.快门.感光度是什么,该如何设置等等.今天我再给大家补充一些光圈.快门.感光度方面的知识,希望对大家有帮助. 一.什么 ...

  • 【书法入门】学习书法的入门知识

    【书法入门】学习书法的入门知识

  • 宋词入门知识

    宋词是中国古代文学皇冠上光辉夺目的巨钻,历来与唐诗并称双绝,都代表一代文学之胜. 唐诗的兴盛和发展,达到了古代诗歌史上的巅峰.词萌芽于隋唐之际,兴于晚唐五代而极盛于宋.广义来说,词本属诗之一体,然逐渐 ...