【转】SPI总线协议

时间:2022-09-03 12:29:27

SPI总线协议

概述


SPI(Serial Peripheral Interface)总线是主要应用于嵌入式系统内部通信的串行同步传输总线协议。通常为四线制的SPI总线支持全双工通信。SPI最初由Motorola在2000年提出,Motorola所定义的SPI标准为业界广泛引用,但不同半导体公司的实施细节可能有所不同,这些区别体现在寄存器设置、信号定义、数据格式等。业界没有统一的SPI标准,具体应用需要参考特定器件手册。

SPI协议特点包括主从模式、全双工通信、片选功能、模式错误标识及CPU中断、缓冲数据寄存器和可配置时钟相位极性等。SPI允许数据一位一位的传送,甚至允许暂停,因为SCK时钟线由主控设备控制,当没有时钟跳变时,从设备不采集或传送数据。也就是说,主设备通过对SCK时钟线的控制可以完成对通讯的控制。

应用


SPI以其简单高效应用于绝大多数SoC系统上,这些SoC通常同时支持作为主模式或从模式(二选一)。

FPGAs和其它专用芯片也广泛使用SPI传输数据。比如:

  • 传感器:温度、压力传感器等
  • 控制设备:音频编解码器等
  • 通信设备:USB、以太网设备等
  • 存储器:Flash、EEPROM等
  • RTC时钟
  • LCD设备
  • MMC和SD卡

在高性能系统中,FPGAs通常使用SPI连接主从设备,比如连接外部传感器,和应用SPI加载配置。相比于JTAG,SPI定位用于高速配置(初始化)板上设备;而JTAG的初衷是为控制设备以相对低的准确度扫描和检测板上IO,在严格要求的场合,JTAG协议支持改变时钟占空比以满足建立和保持时间的要求。因此,JTAG并不定位于高速数据传输的场合。

优点和缺点


优点

  • 支持全双工通信
  • Push-Pull驱动性能相比Open Drain信号完整性更好,支持高速应用(100MHz以上)
  • 协议支持字长不限于8bits,可根据应用特点灵活选择消息字长
  • 硬件连接简单
    • 只需要四根信号线(部分应用可以缩减到三根)
    • 相比I2C和SMbus节省上拉电阻
    • 相比I2C和SMbus不需要仲裁机制
    • 从设备使用主设备时钟,节约时钟要求
    • 从设备无需地址寻址
    • 无需收发器

缺点

  • 相比I2C两根线,SPI四根线更多
  • 没有寻址机制,只能靠设备片选(chip select)选择不同从设备
  • 没有数据流控制(但主设备可以通过延缓时钟边缘降低传输速度)
  • 没有从设备接收数据ACK,主设备对于发送成功与否不得而知
  • 典型应用只支持单主控
  • 没有定义数据校验机制
  • 没有统一的国际组织维护,变种多不利于不同厂商设备的互操作性(interoperability)
  • 相比于RS232、RS422、RS485和CAN,SPI传输距离短
  • 不支持热插拔
  • 中断操作只能通过额外的信号线,或类似USB 1.1 and 2.0的Periodic Polling实现

内部框图


本文主要参考三家公司SPI协议手册,其原理大同小异:

  1. SPI Block Guide V04.01 -Motorola
  2. KeyStone Architecture Serial Peripheral Interface (SPI) User Guide -Texas Instruments
  3. TN0897: ST SPI protocol -STMicroelectronics

图1表示Motorola定义SPI模块的内部框图,其主要构成包括状态/控制/数据寄存器(Status,Control and Data Registers)、移位寄存器(Shifter Logic)、波特率发生器(Baud Rate Generator)、主从控制逻辑(Master/Slave Control Logic)和端口控制逻辑(Port Control Logic)。

【转】SPI总线协议

图1. SPI模块框图(Motorola)

硬件基础


SPI总线定义两个及以上设备间的数据传输,提供时钟的设备为主设备(Master),接收时钟的设备为从设备(Slave)。

信号定义

SPI协议定义四根信号线,分别为:

  • SCK : Serial Clock 串行时钟
  • MOSI : Master Output, Slave Input 主发从收信号
  • MISO : Master Input, Slave Output 主收从发信号
  • SS : Slave Select 片选信号

其中MISO方向为从设备到主设备,其余三个信号均为主设备到从设备。

说明:

  1. 对于主设备,如果设置SS作为从设备的片选信号(最常用的场合),则它就不能用于多主设备应用的模式错误检测(参考SSOE和MODFEN寄存器设置,表1)
  2. SPI单个数据管脚支持双向模式。在双向模式下,主设备的MOSI,从设备的MISO作为双向IO(参考SPC0BIDIROE寄存器设置,表2)

电路连接

图2表示基本的SPI设备连接示意图。片选信号SS通常低电平有效。SPI数据传输原理是基于主从设备内部移位寄存器的数据交换。在主设备SCK的控制下,待传数据由各自设备的数据寄存器(Data Register)传输到移位寄存器(Shift Register),再通过MOSI和MISO信号线完成主从设备间的数据交换。

【转】SPI总线协议

图2. SPI主从模式传输示意图(电路)

主从设备间数据交换逻辑示意图如下图3所示:

【转】SPI总线协议

图3. SPI主从模式传输示意图(逻辑)

硬件拓扑

单个主设备和单个从设备的SPI连接比较简单,以上图2和图3表示的就是这种拓扑结构。
通过多个片选信号(SS)或菊花链方式(Daisy Chain Configuration),单个主设备可以同时控制多个不同从设备。

  • 片选方式

如图4示,每个从设备都需要单独的片选信号,主设备每次只能选择其中一个从设备进行通信。因为所有从设备的SCK、MOSI、MISO都是连在一起的,未被选中从设备的MISO要表现为高阻状态(Hi-Z)以避免数据传输错误。由于每个设备都需要单独的片选信号,如果需要的片选信号过多,可以使用译码器产生所有的片选信号。

【转】SPI总线协议
图4. 主设备以片选方式控制多个从设备

  • 菊花链方式

如图5示,数据信号经过主从设备所有的移位寄存器构成闭环。数据通过主设备发送(绿色线)经过从设备返回(蓝色线)到主设备。在这种方式下,片选和时钟同时接到所有从设备,通常用于移位寄存器和LED驱动器。注意,菊花链方式的主设备需要发送足够长的数据以确保数据送达到所有从设备。切记主设备所发送的第一个数据需(移位)到达菊花链中最后一个从设备。

菊花链式连接常用于仅需主设备发送数据而不需要接收返回数据的场合,如LED驱动器。在这种应用下,主设备MISO可以不连。如果需要接收从设备的返回数据,则需要连接主设备的MISO形成闭环。同样地,切记要发送足够多的接收指令以确保数据(移位)送达主设备。

【转】SPI总线协议

图5. 主设备以菊花链方式控制多个从设备

电源管理


Motorola在SPI Block Guide中定义以下三种SPI电源模式:

  • 运行模式 Run Mode
  • 等待模式 Wait Mode
  • 停止模式 Stop Mode

运行模式下,SPI工作处于正常工作状态。通过修改SPICR1寄存器的SPE位更改此模式:

0: 禁用SPI模块(进入低功耗状态)
1: 使能SPI模块

等待模式下,修改SPICR2寄存器的SPISWAI位:

0: 运行模式
1: 低功耗模式 SPI时钟停止运作

对于主设备,进入等待模式意味终止SPI总线上所有数据传输,唯有将SPISWAI 重新置为0方可恢复通信;对于从设备,进入等待模式后仍将与主设备保持同步,从设备数据的接收和发送还是正常的。

停止模式下,对于主设备,进入停止模式意味着所有总线上通信的终止;对于从设备,进入停止模式后数据的发送和接收还是正常的,仍然与主设备保持同步状态。

TI在SPI User Guide定义两种低功耗状态:

  • 全局低功耗模式 Global Low-Power Mode
  • 局部低功耗模式 Local Low-Power Mode

全局低功耗模式受系统控制,此模式下SPI时钟停止,处于完全不作为状态。
通过写SPI全局寄存器(SPIGCR1)可以是SPI模块进入局部低功耗模式。此模式下,所有寄存器可以正常访问,但SPI的状态机处于停摆状态,数据收发可能异常。软件设置时需要注意不要在收发数据时让SPI进入低功耗模式。

寄存器说明


Motorola定义的SPI寄存器包括:

  • SPI Control Register 1 (SPICR1)
  • SPI Control Register 2 (SPICR2)
  • SPI Baud Rate Register (SPIBR)
  • SPI Status Register (SPISR)
  • SPI Data Register (SPIDR)

其中除了状态寄存器SPISR为只读(Read-only),其它寄存器都是可读写的。通过往寄存器中写入不同的值,设置SPI模块的不同属性。

1. 控制寄存器1 SPICR1

【转】SPI总线协议

图6. 控制寄存器1 SPICR1

SPIE — SPI Interrupt Enable Bit
1 = SPI interrupts enabled
0 = SPI interrupts disabled

SPE — SPI System Enable Bit
1 = SPI enabled, port pins are dedicated to SPI functions
0 = SPI disabled (lower power consumption)

SPTIE — SPI Transmit Interrupt Enable
1 = SPTEF interrupt enabled
0 = SPTEF interrupt disabled

MSTR — SPI Master/Slave Mode Select Bit
1 = SPI is in Master mode
0 = SPI is in Slave mode

CPOL — SPI Clock Polarity Bit
1 = Active-low clocks selected. In idle state SCK is high
0 = Active-high clocks selected. In idle state SCK is low

CPHA — SPI Clock Phase Bit
1 = Sampling of data occurs at even edges (2,4,6,...,16) of the SCK clock
0 = Sampling of data occurs at odd edges (1,3,5,...,15) of the SCK clock

SSOE — Slave Select Output Enable
SSOE 用于主设备设置SS管脚功能,它和MODFEN组合决定主设备SS管脚功能。如表1所示其功能组合:

【转】SPI总线协议

表1. SS输入/输出选择

LSBFE — LSB-First Enable
1 = Data is transferred least significant bit first
0 = Data is transferred most significant bit first

2. 控制寄存器2 SPICR2

【转】SPI总线协议图7. 控制寄存器1 SPICR2

MODFEN — Mode Fault Enable Bit
1 = SS port pin with MODF feature
0 = SS port pin is not used by the SPI

BIDIROE — Output enable in the Bidirectional mode of operation
控制双向模式(Bidirectional Mode)下主设备的MOSI和从设备MISO的输出缓冲器
1 = Output buffer enabled
0 = Output buffer disabled

SPISWAI — SPI Stop in Wait Mode Bit
1 = Stop SPI clock generation when in wait mode
0 = SPI clock operates normally in wait mode

SPC0 — Serial Pin Control Bit 0
控制(单个)数据管脚是否配置为双向模式,与BIDIROE组合控制(单个)数据管脚同时支持收发功能(如下表2)

【转】SPI总线协议

表2. MOSI/MISO双向管脚配置

3. 波特率寄存器 SPIBR

【转】SPI总线协议图8. 波特率寄存器 SPIBR

SPPR2–SPPR0 — SPI Baud Rate Preselection Bits
SPR2–SPR0 — SPI Baud Rate Selection Bits

以上五个寄存器通过下面公式决定波特率除数因子(BaudRateDivisor),进而决定SCK时钟频率。

除数因子:(通过五个参数计算出来的除数因子不仅包括2^N,还包括4/6/10等总计64个组合)

【转】SPI总线协议

计算波特率

【转】SPI总线协议

举例,SPPR[2:0]设为101,SPR[2:0]设为000,计算得除数因子(5+1) * (2^1) = 12。如果系统时钟速率为25MHz,则SCK时钟速率 = 25MHz/12 = 2.0833MHz.

4. 状态寄存器 SPISR

【转】SPI总线协议

图9. 状态寄存器 SPISR

SPISR表征SPI传输状态,只可读,不可写。

SPIF — SPIF Interrupt Flag
数据byte写入SPI数据寄存器后,此位被置为1。读取数据寄存器后,此位清零。
1 = New data copied to SPIDR
0 = Transfer not yet complete

SPTEF — SPI Transmit Empty Interrupt Flag
1 = SPI Data register empty 表示发送数据寄存器为空,可以接收待发送数据
0 = SPI Data register not empty 此时忽略任何写入数据寄存器的指令

MODF — Mode Fault Flag
如表1,错误检测功能使能后,MODF表示检测到SPI模式错误。
1 = Mode fault has occurred.
0 = Mode fault has not occurred

根据Motorola的定义,SPI仅提供一种错误——即模式错误(Mode Fault Error)——的检测机制,通过SS管脚状态判断SPI总线上是否存在两个及以上的设备同时驱动SCK和MOSI。模式错误检测仅适用于主设备(前提是在寄存器中激活此功能)。对于从设备,SS总是作为片选信号的。
在发生模式错误后(MODF = 1),系统通过写入控制寄存器SPICR1(使设备由Master改为Slave模式,SCK、MISO和MOSI表现为高阻态以避免与总线上其它驱动设备冲突),随后系统自动将此bit置为零(MODF = 0)。

5. 数据寄存器 SPIDR

【转】SPI总线协议

图10. 数据寄存器 SPIDR

SPIDR作为SPI收发两用的寄存器,数据在写入SPIDR后进入待传输队列,队列中的数据字节在前面数据传输结束后立即进行传输。状态寄存器SPISR的SPTEF位表示数据寄存器可以接收新数据。数据寄存器接收数据完毕后将SPIF置为1。
如果SPIF已经置为1,但服务并未运行(not serviced),则下一个(第二个)接收的数据字节将暂存在移位寄存器中直到下次传输。数据寄存器中的数据字节不变。

如果SPIF已经置为1,并且移位寄存器中已经暂存数据(即第二个数据字节),并且SPIF服务在第三个数据字节传输前完成,则移位寄存器中的数据(即第二个数据字节 )正常写入数据寄存器,SPIF仍保持置位状态(高),如图11所示;

【转】SPI总线协议

图11. SPIF服务及时完成

如果SPIF已经置为1,并且移位寄存器中已经暂存数据(即第二个数据字节),并且SPIF服务在第三个数据字节传输后完成,则移位寄存器中的数据(即第二个数据字节 )遭破坏,不能正常写入到数据寄存器,SPIF仍保持置位状态(高),如图12所示 。

【转】SPI总线协议

图12. SPIF服务未及时完成

SPI传输模式


通过设置控制寄存器SPICR1中的CPOLCPHA位,将SPI可以分成四种传输模式。

CPOL,即Clock Polarity,决定时钟空闲时的电平为高或低。对于SPI数据传输格式没有显著影响。
1 = 时钟低电平时有效,空闲时为高
0 = 时钟高电平时有效,空闲时为低

CPHA,即Clock Phase,定义SPI数据传输的两种基本模式。
1 = 数据采样发生在时钟(SCK)偶数(2,4,6,...,16)边沿(包括上下边沿)
0 = 数据采样发生在时钟(SCK)奇数(1,3,5,...,15)边沿(包括上下边沿)

四种模式如下图13所示。先看第一列两张图(CPHA = 0),采样发生在第一个时钟跳变沿,即数据采样发生在SCK奇数边沿;再看第二列CPHA =1),采样发生在第二个时钟跳变沿,即数据采样发生在SCK偶数边沿第一行两张图(CPOL = 0),SCK空闲状态为低电平第二行两张图(CPOL = 1),SCK空闲状态为高电平

主从设备进行SPI通讯时,要确保它们的传输模式设置相同。对于某些场合,可能需要调整CPOL/CPHA设置以满足设备特定要求。

【转】SPI总线协议

图13. SPI四种传输模式

时序要求


具体时序要求参考器件手册。以下Motorola标准对CPHA = 0(图14)和CPHA =1(图15)不同设置时序的简要说明:

CPHA = 0

  • 有些器件在片选后数据立即出现在MOSI/MISO管脚,数据锁存于第一个时钟边沿
  • 片选SS先于SCK半个时钟有效
  • 在SCK的第二个时钟边沿,上个时钟边沿锁存的数据写入移位寄存器(MSB或LSB)
  • 以此类推,数据在奇数边沿锁存,在偶数边沿写入移位寄存器
  • 经过16个时钟边沿后,串行传输的数据全部写入(并行的)移位寄存器,完成主从设备的数据交换

【转】SPI总线协议

图14. SPI时钟模式(CPHA = 0)

CPHA = 1

  • 有些设备要求数据输出在SCK第一个时钟边沿之后,数据锁存于第二个时钟边沿
  • 片选SS先于SCK半个时钟有效
  • 在SCK的第三个时钟边沿,上个时钟边沿锁存的数据写入移位寄存器(MSB或LSB)
  • 以此类推,数据在偶数边沿锁存,在奇数边沿写入移位寄存器
  • 经过16个时钟边沿后,串行传输的数据全部写入(并行的)移位寄存器,完成主从设备的数据交换

【转】SPI总线协议

图15. SPI时钟模式(CPHA = 1)

SPI通信过程


简要说明STSpansion器件的SPI通讯过程。

1. STMicroelectronics

ST SPI规范定义,在系统启动后,主设备读取从设备8位SPI寄存器以确定从设备字长(16,24或32bit)及其它特性。每个帧(读/写)包括1个操作字节(Instruction Byte)和紧接着的1-3个数据字节(Data Byte)。

操作字节可能是指令字节全局状态字节。记住指令字节总是出现在(主从)设备的输入管脚(SDI),全局状态字节总是出现在(主从)设备的输出管脚(SDO)。

  • Command Byte 指令字节

【转】SPI总线协议

图16. 指令字节格式

指令字节前2位OC0/OC1指定SPI操作的四种类型,包括写操作、读操作、读和复位状态操作、读取设备信息操作;
指令字节后6位Ax指定操作对象(RAM/ROM)的地址。

  • Global Byte 全局状态字节

【转】SPI总线协议

图17. 全局状态字节格式

指示设备状态信息,如工作模式、通讯错误等。

如下图18读写操作数据帧格式。对于写操作,SDO输出全局变量字节之后紧接着地址寄存器中先前缓存的数据;对于读操作,全局变量字节后紧接着寻址待取的数据。

【转】SPI总线协议

图18. SPI读写操作(ST)

2. Spansion

以常见的SPI接口Flash为例。如图19所示,在CS#低有效后,基于操作模式,决定在SCK的上升或下降沿触发采样数据。8位指令字节后紧接着24位地址,寻址Flash内部存储块。随着Flash容量增大,可能需要更多的寻址位。比如Micron的N25Q等器件,需要使能4 Byte地址模式以支持容量在128Mbit以上的器件。(单个地址寻址对应1 Byte数据,则24位地址寻址最大2^24 = 16 M Byte = 128Mbit)。

【转】SPI总线协议

图19. SPI读操作(Spansion Flash)

复位和中断


复位后,寄存器值恢复初始状态(以上寄存器表下方所列出)。对于从设备,如果复位后不对SPIDR写入数据,它将输出随机数据或复位前从主设备接收到的数据;复位后SPIDR的数据全部清零。

SPI的中断向量和优先级因设备而异。中断请求由状态寄存器SPISR中MODF、SPIF和SPTEF位逻辑或产生。

协议分析


利用示波器逻辑分析仪的SPI协议分析功能(电气特性 & 译码),可以快速定位通信链路上出现的问题。示波器支持不同的触发方式,以Tektronix示波器为例,其支持SPI的触发方式包括:

  • SS触发,基于片选信号状态变化触发
  • SOF触发,根据时钟空闲时间确定Start Of a Frame触发
  • MOSI触发,基于MOSI上特定的数据格式触发
  • MISO触发,基于MISO上特定数据格式触发
  • MOSI/MISO触发,基于MOSI和MISO上特定数据格式触发

I2C & JTAG


SPI和I2C,JTAG对比参考表3:

【转】SPI总线协议

表3. SPI, I2C和JTAG协议概览

参考资料


1. Serial Peripheral Interface Bus -Wikipedia

2. SPI Block Guide V04.01 -Motorola

3. KeyStone Architecture User Guide: Serial Peripheral Interface, Literature Number: SPRUGP2A -Texas Instruments

4. TN0897: ST SPI Protocol -STMicroelectronics

5. Comparing Serial Interfaces -Spansion

6. Serial Peripheral Interface Tutorial -Sparkfun

7. Debugging Serial Buses in Embedded System Designs -Tektronix

 

【转】SPI总线协议的更多相关文章

  1. SPI总线协议及SPI时序图详解

    SPI,是英语Serial Peripheral Interface的缩写,顾名思义就是串行外围设备接口.SPI,是一种高速的,全双工,同步的通信总线,并且在芯片的管脚上只占用四根线,节约了芯片的管脚 ...

  2. SPI总线协议及SPI时序图详解【转】

    转自:https://www.cnblogs.com/adylee/p/5399742.html SPI,是英语Serial Peripheral Interface的缩写,顾名思义就是串行外围设备接 ...

  3. 关于I2C和SPI总线协议【转】

    关于I2C和SPI总线协议 IICvs SPI 现今,在低端数字通信应用领域,我们随处可见IIC (Inter-Integrated Circuit) 和 SPI (Serial Peripheral ...

  4. spi 总线协议记录

    摘抄至: http://blog.csdn.net/skyflying2012/article/details/11710801 概述: SPI, Serial Perripheral Interfa ...

  5. SPI总线协议理解

    1.什么是SPI: 是摩托罗拉公司设计的一种全双工通信.高速的.同步的串行外部设备通信协议. 2.SPI作用: 用于设备之间的数据交互. 3.SPI由什么构成: 1)MOSI:主设备输出从设备输入线, ...

  6. SPI总线协议介绍

    http://blog.csdn.net/ce123_zhouwei/article/details/6897293 https://www.cnblogs.com/yangguang-it/p/71 ...

  7. SPI、I2C、UART三种串行总线协议的区别

    第一个区别当然是名字: SPI(Serial Peripheral Interface:串行外设接口); I2C(INTER IC BUS) UART(Universal Asynchronous R ...

  8. SPI、I2C、UART三种串行总线协议的区别和SPI接口介绍(转)

    SPI.I2C.UART三种串行总线协议的区别 第一个区别当然是名字: SPI(Serial Peripheral Interface:串行外设接口); I2C(INTER IC BUS) UART( ...

  9. MSP430单片机的两种SPI总线实现方式

    MSP430单片机上的SPI总线的实现方式分为两种:硬件实现和软件实现. 二者的抽象层次不同,硬件实现方式下程序员只需要完成总线协议的寄存器层,即一字节(char,8位二进制)数据,而软件实现方式下程 ...

随机推荐

  1. Python简单爬虫入门三

    我们继续研究BeautifulSoup分类打印输出 Python简单爬虫入门一 Python简单爬虫入门二 前两部主要讲述我们如何用BeautifulSoup怎去抓取网页信息以及获取相应的图片标题等信 ...

  2. Linux命令行与命令

    Linux命令行与命令   作者:Vamei 出处:http://www.cnblogs.com/vamei 欢迎转载,也请保留这段声明.谢谢! Linux的命令是很重要的工具,也往往是初学者最大的瓶 ...

  3. 【读书笔记《Android游戏编程之从零开始》】15.游戏开发基础(剪切区域)

    剪切区域也称为可视区域,是由画布进行设置的:它指的是在画布上设置一块区域,当画布一旦设置了可视区域,那么除此区域外,绘制的任何内容都将看不到:可视区域可以是圆形.矩形等等. 画布提供了三种设置可视区域 ...

  4. 网站性能评分工具Yslow 使用教程

    Yslow 这个工具相信无论是搞前端的攻城师或者是搞网站的站长都了解,Yslow 可比谷歌的PageSpeed 有名多了:那个百分制下的评分数据总让国人着迷,看来应试教育造的孽太深了.Jeff 认为的 ...

  5. 20145227 《Java程序设计》第6周学习总结

    20145227 <Java程序设计>第6周学习总结 教材学习内容总结 第十章 输入/输出 10.1 InputStream与OutputStream 1.串流设计的概念 Java将输入/ ...

  6. 一张图让你学会LVM

    导读 随着科技的进步,人们不知不觉的就进入了大数据的时代,数据的不断增加我们发现我们的磁盘越来越不够用了,接下来就是令人头疼的事情--加硬盘,数据的备份与还原.LVM就是Linux下专门针对我们数据的 ...

  7. Android开发中在一个Activity中关闭另一个Activity

    比如有ActivityA, ActivityB,在ActivityB中关闭ActivityA 解决方案: 1. 在 ActivityA 里面设置一个静态的变量instance,初始化为this在 Ac ...

  8. 浅析微信小程序技术架构(原创)

    周末万里虎抽空体验了下微信小程序的DEMO,对小程序的开发有了一个基础的了解与认识,今天就来和大家分享一下我对小程序的看法. 从官方DEMO来看,小程序在技术架构上非常清晰易懂.JS负责业务逻辑的实现 ...

  9. Android100【申明:来源于网络】

    Android100[申明:来源于网络] 地址:http://www.android100.org/html/201406/11/23770.html

  10. 聊聊Python中的闭包和装饰器

    1. 闭包 首先我们明确一下函数的引用,如下所示: def test1(): print("--- in test1 func----") # 调用函数 test1() # 引用函 ...