UINIO-MCU-GD32F350RBT6是一款采用 LQFP64 封装的 GD32F350RBT6微控制器核心板,基于 ARM Cortex-M4 内核架构,主频高达108MHz
,拥有 128K
容量 Flash,以及16K
的 SRAM。而 UINIO-MCU-GD32F103C采用 LQFP48 封装的 GD32F103Cxxx 系列微控制器(包括GD32F103CBT6
、GD32F103C8T6
、GD32F103C6T6
、GD32F103C4T6
),基于ARM Cortex-M3 内核架构,主频达到108MHz
,拥有 16K ~ 128K
容量 Flash,以及6K ~ 20K
的 SRAM。
这里以 UINIO-MCU-GD32F350RBT6核心板作为例子,首先需要前往兆易创新的 GD32MCU 微控制器官方网站,把如下两个开发资源下载到本地计算机:
GD32F3x0_Firmware_Library_V2.2.1
。GigaDevice.GD32F3x0_DFP.3.0.2.pack
。然后,启动 Keil uVision5开发环境,开始导入或者在线安装GigaDevice.GD32F3x0_DFP.3.0.2.pack
支持包:
接下来,解压 GD32F3x0_Firmware_Library_V2.2.1
固件库,此时会得到如下一系列目录:
CMSIS
、标准外设库GD32F3x0_standard_peripheral
、USB文件系统库 GD32F3x0_usbfs_library
三个子目录。其中 Examples下面的每一个子目录,都对应着一种片上外设的示例程序,里面通常会包含有如下的源文件:
main.c
:主程序源文件。systick.h
:SysTick 精准延时头文件;systick.c
:SysTick 精准延时源文件;GD32f3x0.it.h
:中断处理程序头文件;GD32f3x0_it.c
:中断处理程序源文件(未使用中断,所有函数体为空);GD32f3x0_libopt.h
:通过预处理语句 #include
包含指定的外设库 .h
头文件(默认导入全部外设);而 Firmware 目录下面包含有GD32F350RBT6 固件库的核心源文件:
CMSIS
子目录包含有 ARM Cortex-M4内核的支持文件、启动代码、库引导文件,以及 GD32F3x0
的全局头文件和系统配置文件。GD32F3x0_standard_peripheral
子目录下的Include
包含了固件库所需要的头文件,而 Source
则包含有固件库所需的源文件。打开 GD32F3x0_Firmware_Library_V2.2.1
固件库下面的Template
目录,删掉除开 Keil_project
目录之外的其它文件与目录,然后将 Examples\GPIO\Running_led
内的全部源文件,拷贝至 Template
目录当中,从而获得如下的文件目录结构:
1 | Template |
鼠标双击 Template
目录下面的工程描述文件Project.uvproj
,启动 Keil uVision5。由于GD32F3x0_Firmware_Library_V2.2.1
当中的示例工程采用的是Keil uVision4建立和编译,因而此时会弹出下面的错误信息:
按下【确定】按钮忽略这些错误信息,依次选择顶部菜单栏上面的【Project-> Manage -> Migrate to Version 5 Format...】,把工程迁移成为Keil uVision5 兼容的格式:
此时会提示工程描述文件需要从 Keil uVision4 的Project.uvproj
保存为 Keil uVision5 的Project.uvprojx
,直接按下【确定】按钮即可:
在开始接下来的操作之前,需要先将 Keil uVision5工程的编译目标切换为 UINIO-MCU-GD32F350RBT6核心板所使用的型号【GD32F350】:
点击顶部工具栏上的【Options forTarget...】按钮,指定目标选项对话框里的【ARMCompiler】版本为 compiler version 5
:
注意:这里必须修改 Keil uVision5当中 ARM 编译器版本,否则会导致后续的编译操作出现错误,具体请参考 《ARM 调试工具UINIO-DAP-Link 应用详解》 一文的 添加ARM Compiler version 5 小节内容。
切换至对话框的【Output】选项卡,在勾选【Create HEXFile】的同时,把【Name of Executable】修改为Project.hex
(务必添加 .hex
后缀,否则默认烧录的是 .axf
文件):
再切换至对话框当中的【Debug】选项卡,此时需要将 UINIO-DAP-Link插入至计算机的 USB 接口,然后在下拉选择【CMSIS-DAPDebugger】之后,再按下右侧的【Settings】按钮:
此时会弹出调试器设置对话框,这里我们选择【UINIO-CMSIS-DAP】,并且将【MaxClock】配置为 10MHz
:
最后再切换至【Flash Download】选项卡,勾选【Reset andRun】,并且点击【Add】按钮添加片上 Flash 的编程算法:
完成上述配置步骤之后点击【OK】,回到 Keil uVision5的主界面,此时按下快捷键【F7】或者顶部工具栏上的【Build】按钮编译示例工程,再按下快捷键【F8】或者【Download】按钮将编译后得到的.hex
程序下载至 UINIO-MCU-GD32F350RBT6核心板运行,此时整个工程的目录文件结构如下所示,其中的 Out
目录保存着编译后产生的十六进制 .hex
文件:
1 | Template |
该示例程序会每间隔 4 秒的时间,循环切换UINIO-MCU-GD32F350RBT6 的四个 GPIO 引脚C2
、C10
、C11
、C12
的高低电平状态,此时通过万用表就可以测量出运行结果,从而方便的判断出程序是否下载成功,以及核心板运行是否存在有故障。
注意:DAPLink 是 ARM系列微控制器开发过程当中,程序下载与调试不可少的工具,相关资料和设计资源可以参考笔者之前撰写的《ARM 调试工具UINIO-DAP-Link 应用详解》 一文。
本节内容开始尝试自己动手搭建 Keil uVision5工程,首先新建一个名称为 Keil-GD32F350RBT6
的 KeiluVision5工程,并将其保存至同名的目录下面,然后再新建如下一系列子目录,并且将固件库里的源文件拷贝至对应的子目录:
README.md
文件。GD32F3x0_Firmware_Library_V2.2.1
当中 Firmware
目录下的全部内容(即CMSIS
、GD32F3x0_standard_peripheral
、GD32F3x0_usbfs_library
三个子目录)。GD32F3x0_Firmware_Library_V2.2.1
下面的Template
目录当中,除IAR_project
、Keil_project
、readme.txt
之外的文件(即main.c/h
、systick.c/h
、gd32f3x0_it.c/h
、gd32f3x0_libopt.h
七个源文件)。鼠标点击 Keil uVision5 顶部菜单栏上面的【FileExtensions, Books and Environment...】按钮:
在弹出的工程管理项对话框当中,分别将左侧的【ProjectTargets】命名为Keil-GD32F350RBT6
,而中间的【Groups】则分别建立如下几个分组,并且通过右侧的Files
向指定分组添加相应的源文件:
Keil-GD32F350RBT6\Firmware\CMSIS\GD\GD32F3x0\Source
目录下的 system_gd32f3x0.c
外设接入层源文件,以及Keil-GD32F350RBT6\Firmware\CMSIS\GD\GD32F3x0\Source\ARM
目录下的 startup_gd32f3x0.s
启动文件(添加对话框的文件类型要修改为 .s
)。Keil-GD32F350RBT6\Firmware\GD32F3x0_standard_peripheral\Source
目录下的 .c
源文件(其中的 gd32f3x0_rcu.c
和gd32f3x0_gpio.c
属于必须添加)。Keil-GD32F350RBT6\Documents
目录下新建的README.md
文件添加进去。Keil-GD32F350RBT6\Sources
目录下的main.c
、systick.c
、gd32f3x0_it.c
三个源文件。完成上述操作之后,在工程管理项对话框当中,各个分组下面的源文件情况如下图所示:
点击【OK】按钮关闭工程管理项对话框,此时Keil uVision5 左侧呈现的工程目录结构如下面所示:
为了避免工程搭建过程当中,直接拷贝官方固件库 Template
目录下的源文件,出现冗余代码导致编译错误的情况,接下来还需要对Source
目录进行一些清理工作。首先需要删除掉该目录下main.c
源文件里多余的内容,只需要保留如下所示的代码:
1 |
|
除此之外,还需要再移除掉 Source
目录下gd32f3x0_it.c
源文件里面,如下所示的无效代码片段:
1 | /*! |
点击 Keil uVision5 工具栏顶部的【Options fortarget】,在弹出的目标选项对话框当中,首先切换至【C/C++】选项卡,将【Define】输入框设置为USE_STDPERIPH_DRIVER,GD32F3X0,GD32F350
:
然后再点击对话框当中【Include Paths】输入框右侧的按钮,配置 ARM编译器分别包含 Keil-GD32F350RBT6工程目录下的如下路径:
.\Sources
.\Firmware\CMSIS
.\Firmware\CMSIS\GD\GD32F3x0\Include
.\Firmware\GD32F3x0_standard_peripheral\Include
接下来切换至【Target】选项卡,选择 ARM 编译器的版本为5,并勾选界面上 Keil uVision5自带的用于串口重定向的【Use MicroLIB】工具库:
最后切换到【Output】选项卡,将【Name of Executable】输入框设置为Keil-GD32F350RBT6.hex
,并且勾选 Create HEXFile 使得编译结果为十六进制 .hex
格式:
完成上述配置工作之后,关闭 Keil uVision5界面上的全部对话框,然后按下快捷键【F7】或者顶部工具栏上的【Build】按钮,将新建工程里的相关源文件编译为一个Keil-GD32F350RBT6.hex
文件:
1 | Build started: Project: Keil-GD32F350RBT6 |
如果编译结果显示 0 Error(s), 0 Warning(s)
,说明这个Keil uVision5工程已经搭建成功。接下来,就可以按下快捷键【F8】或者顶部工具栏上的【Download】按钮,把编译后得到的十六进制文件Keil-GD32F350RBT6.hex
,通过 UINIO-DAP-Link下载至 UINIO-MCU-GD32F350RBT6 核心板上面运行:
1 | Load "D:\\Workspace\\UINIO-MCU-GD32F350RBT6\\Keil-GD32F350RBT6\\Objects\\Keil-GD32F350RBT6.hex" |
注意:为了大家能够方便快速的搭建测试项目,该自定义工程已被保存到开源硬件项目UINIO-MCU-GD32F350RBT6的
Keil-GD32F350RBT6
目录里面。
鼠标依次选择 Keil uVision5 菜单栏上的 【Edit ->Configration... -> 】,将弹出窗口【Editor】选项卡下的Encoding
选择为 Chinese GB2312 (Simplified)
就可以支持中文注释:
注意:这种方式会导致 Keil uVision显示的源代码字体非常不美观,更佳的处理办法是利用Sublime 等文本编辑器提供的 ConvertToUTF8插件,将源代码文件全部转换为 UTF-8 格式的编码。
AStyle 是一款用于对C/C++ 源代码进行格式化的开源插件,鼠标点击 KeiluVision5 菜单栏上的【Tools -> Customize Tools Menu】:
在弹出的对话框当中进行如下的设置,其中的 Command就是 astyle.exe
可执行文件所在的路径:
D:\Software\Tech\AStyle\astyle.exe
"$E*.c" "$E*.h" --style=google --indent=spaces=2
。!E --style=google --indent=spaces=2
。完成上述步骤之后,就可以在 Keil uVision5的菜单栏上发现【Tools -> AStyle All】和【Tools -> AStyleFile】两条自定义菜单项:
GD32F350RBT6 是一款采用 Arm Cortex-M4 内核架构的 32位微控制器,工作频率为 108MHz
,工作电压范围在2.6V ~ 3.6V
之间,工作温度介于 -40°C ~ +85°C
范围。提供高达 128KB
的片上 Flash 闪存和16KB
的 SRAM内存,其它的片上资源情况可以参考下面表格:
资源名称 | 数量 | 资源名称 | 数量 |
---|---|---|---|
12 位 ADC | 1 个 | SPI | 2 个 |
12 位 DAC | 1 个 | I2C | 2 个 |
通用比较器 CMP | 2 个 | USART | 2 个 |
通用 16 位定时器 | 5 个 | I2S | 1 个 |
通用 32 位定时器 | 1 个 | HDMI-CEC | 1 个 |
基本定时器 | 1 个 | TSI | 1 个 |
PWM 高级定时器 | 1 个 | USBFS 全速 USB | 1 个 |
UINIO-MCU-GD32F350RBT6 采用的GD32F350RBT6 微控制器使用的是 LQFP64
封装形式,其具体 64 个引脚的功能分配可以参见下图:
ARM Cortex-M4 系列微控制器基于ARMv7 架构,其内核主要由下面一系列的功能单元构成:
GD32F350RBT6微控制器的整体系统架构如下面的框图所示,其中AHB(Advanced High performanceBus)高级高性能总线矩阵采用的是多层总线结构,支持多个主从设备之间实现并行通信,其中主设备包含有来自ARM Cortex-M4 内核架构的I-Code 指令总线
、D-Code 数据总线
、System 系统总线
,以及来自于内核外部的DMA 总线
:
0x 0000 0000 ~ 0x 1FFF FFFF
代码区域获取向量。除此之外,AHB总线矩阵的从设备包含有来自 Flash 存储控制器的IBUS 和 DBUS 总线、SRM控制器总线,以及 AHB1 和 AHB2总线:
ARM Cortex M4内核采用了哈佛结构,使用相互独立的总线来读取指令和操作数据。这些指令和数据都存储在一个大小为4GB
的相同地址空间(因为 ARMCortex M4 的地址总线宽度为 32位,所以其对应的地址范围为 2
的 32
次方等于4GB),但是处于不同的地址范围:
观察上面的表格可以发现 GD32F350RBT6 的片上外设地址空间被划分为 AHB1 和AHB2 总线、APB1 和APB2总线共四个部分,这些总线的最低地址被称为总线基地址,也就是挂载在该总线上第1个外设的地址,而每个外设的最低地址则被称为外设基地址,每个外设的地址范围内都分布着该外设所对应的寄存器,通过操作这些寄存器就可以达到控制外设的目的。
如果需要将 AHB 总线上的 GPIOA外设对应的 16 个引脚全部置为1
,那么就需要去配置端口输出控制寄存器GPIOx_OCTL
,通过查询用户手册可以知道其地址偏移量为0x14
:
由于 GPIOA 的外设基地址为0x4800 0000
,所以寄存器 GPIOA_OCTL
的地址计算方式如下所示:
1 | 0x4800 0000 + 0x0000 0014 = 0x4800 0014 |
换而言之,将寄存器 OCTL(0~15)
相应的位设置为 1
,就可以把对应的GPIOA(0~15)
控制为高电平。如果要让全部 16个引脚输出高电平,那么相应的 GPIOA_OCTL
寄存器的高 16位可以置为 0
而低 16 位置为 1
,即0000 0000 0000 0000 1111 1111 1111 1111
,转换为十六进制就是0x0000FFFF
:
1 | *(unsigned int*)(0x48000014) = 0x0000FFFF; // 将 GPIOA 外设对应的 16 个引脚全部输出高电平 |
像上面这样直接对寄存器地址进行操作会比较麻烦,下面可以通过宏定义#define
,为每一个寄存器地址都分配一个名称:
1 |
|
为了进一步简化代码,可以将指针类型 *
的声明合并到GPIOA_OCTL
的宏定义当中:
1 |
|
兆易创新官方固件库GD32F3x0_Firmware_Library_V2.2.1
当中标准外设库Firmware\GD32F3x0_standard_peripheral
目录下的Include\gd32f3x0_gpio.h
和Source\gd32f3x0_gpio.c
两个源文件,提供有一系列用于操作GPIO 的库函数:
其中的void gpio_port_write(uint32_t gpio_periph, uint16_t data)
函数可以用于向特定的 GPIO 端口写入状态值:
1 | gpio_port_write(GPIOB, 0xFFFF); |
该函数被定义在 Source\gd32f3x0_gpio.c
源文件当中,可以看到其函数体内调用了 GPIO_OCTL(gpio_periph)
函数:
1 | /*! |
而这个 GPIO_OCTL(gpio_periph)
函数又被预定义在了Include\gd32f3x0_gpio.h
头文件里面,其最终调用的是REG32(addr)
函数:
1 |
REG32(addr)
函数的定义位于官方固件库Firmware\CMSIS\GD\GD32F3x0\Include
目录下的gd32f3x0.h
头文件当中:
1 |
把前面寄存器 GPIOA_OCTL
的地址计算式0x4800 0000 + 0x0000 0014
作为 addr
参数代入之后,就会发现标准外设库底层也是在操作寄存器,只是在使用的时候更加直观简单:
1 |
注意:通过寄存器直接控制外设,性能开销更少,运行更加迅速,适用于片上资源有限,且对于实时性要求较高的场景。而使用标准外设库来操控外设,其优势主要体现在提升代码的开发效率以及可读性与可维护性。
使用 UINIO-MCU-GD32F350RBT6 核心板来控制 GPIO端口的输出,整体需要经历下面几个步骤:
开始编写代码之前,首先需要将一枚 4.7K
的电阻R1
与一枚 LED 发光二极管串联,然后再连接到UINIO-MCU-GD32F350RBT6 核心板的 GPIOB8
引脚,当该引脚输出高电平的时候 LED发光二极管就会点亮,而输出低电平的时候 LED发光二极管就会熄灭,具体的电路连接关系请参考下面的示意图:
由于 GD32F350RBT6的外设时钟资源默认情况下都是关闭的,所以在配置外设之前需要先开启其对应的时钟。
GPIOB
引脚分组被挂载到了 GD32F350RBT6微控制器的 AHB 总线下面,在用户手册的复位和时钟单元(RCU)
章节里,描述了 AHB总线使能寄存器 RCU_AHBEN
的地址偏移量为0x14
、复位值为 0x0000 0014
,可以按照 8位的字节、16 位的半字以及 32位的字进行访问:
而 AHB 总线使能寄存器RCU_AHBEN
位于复位和时钟单元 RCU外设的地址范围之内,由于 RCU 的外设基地址为0x4002 1000
,所以 RCU_AHB1EN
寄存器的实际地址计算过程如下面等式所示:
1 | RCU_AHBEN = RCU 的外设基地址 + AHB 总线使能寄存器偏移量 = 0x4002 1000 + 0x14 = 0x4002 1014 |
根据用户手册当中接下来的内容,可以发现 RCU_AHB1EN
寄存器的第 18
位 PBEN
就是 GPIOB时钟的使能位:
所以只需要往 RCU_AHB1EN
寄存器的第 18 位写入1
,其它位保持不变,就可以实现对 GPIOB外设时钟的使能,这里我们可以通过一个或运算和移位运算来完成:
1 | RCU_AHBEN |= (1 << 18) |
注意:上面等式要使能的是第几位,就向右移多少位。例如上面等式向第18 位写入
1
,所以就右移18
位。
接下来,着手配置 GD32F350RBT6 的 GPIO工作模式,这里具体可以划分为下面两个步骤:
GPIOx_CTL
配置为输入模式(默认)
/ 输出模式
/备用功能模式
/ 模拟模式
;GPIOx_PUD
配置为上拉模式
/ 下拉模式
/悬空模式(默认)
;已知 GPIOB 寄存器的基地址为0x4800 0400
,而端口控制寄存器 GPIOB_CTL
的地址偏移量为 0x00
:
从而就可以计算出 GPIOB 端口控制寄存器GPIOB_CTL
的实际地址为:
1 | GPIOB_CTL = 0x4800 0400 + 0x00 = 0x4800 0400 |
该寄存器通过两个位来进行控制,例如这里需要操作的是 Pin8
引脚,就是需要控制 GPIOB_CTL
寄存器的第 17 和 16位。通过将这两位配置为 01
,就可以将 GPIOB8端口配置为输出模式。此时向 GPIOB_CTL
寄存器写入的二进制数据为0000 0000 0000 0001 0000 0000 0000 0000
,转换为十六进制就是00010000
。为了确保其它位不会被修改,需要先将第 15 和第 14两位置零,然后再将其配置为 0
和 1
:
1 | GPIOB_CTL &= 0xFFFCFFFF; // 把第 17 和 16 位置为 00 |
除此之外,还可以采用下面的计算方式进行配置:
1 | GPIOB_CTL &= ~(0x03 << (2 * 8)); // 把第 17 和 16 位置为 00 |
注意:上面代码当中的数值
8
对应的是GPIOB8
,反之如果是GPIOB5
则可以将该值替换为5
。
将 GPIOB8引脚配置为输出模式之后,还需要再进一步通过端口上下拉寄存器GPIOB_PUD
将其进一步配置为悬空模式(默认值,即没有上下拉电阻):
同样已知 GPIOB 寄存器的基地址为0x4800 0400
,而端口上下拉寄存器 GPIOB_PUD
的地址偏移量为 0x0C
,从而就可以计算出其实际地址为:
1 | GPIOB_PUD = 0x4800 0400 + 0x0C = 0x4800 040C |
该寄存器同样通过 GPIOB_PUD
寄存器的第 17 和第 16两个位来进行控制:
使用时也依然需要先进行清零,然后再将其配置为 00
所代表的悬空模式:
1 | GPIOB_PUD &= ~(0x03 << (2 * 8)); // 将第 17 和 16 位清零 |
配置 UINIO-MCU-GD32F350RBT6 的 GPIO输出类型也可以划分为如下两个步骤:
GPIOx_OMODE
,也就是选择推挽输出还是开漏输出;GPIOx_OSPD
的输出速度等级,在这里我们选择 50MHz
的频率;GPIO的开漏输出模式需要外接上拉电阻,才能够输出高电平,不适用于当前的电路连接关系,在这里我们需要通过端口输出模式寄存器GPIOB_OMODE
,将其设置为推挽输出模式:
同样已知 GPIOB 的寄存器基地址为0x4800 0400
,而端口输出模式寄存器 GPIOB_OMODE
的地址偏移量为 0x04
,那么 GPIOB_OMODE
的准确寄存器地址为:
1 | GPIOB_OMODE = 0x4800 0400 + 0x04 = 0x4800 0404 |
根据上图的描述可知,向 GPIOB_OMODE
寄存器的第 8 位写入0
,就可以将其配置为推挽输出模式:
1 | GPIOB_OMODE &= ~(0x01 << 8) // 将 GPIOB_OMODE 的第 8 位置为 0 |
接下来,需要再将端口速度寄存器GPIOx_OSPD
的输出频率设置为 50MHz
:
根据前面的计算方法,已知 GPIOB 的寄存器基地址为0x4800 0400
,而端口速度寄存器 GPIOB_OSPD
的地址偏移量为 0x08
,则 GPIOB_OSPD
的准确寄存器地址,可以按照如下方式进行计算得到:
1 | GPIOB_OSPD = 0x4800 0400 + 0x08 = 0x4800 0408 |
根据上图描述的信息,可以向 GPIOB_OSPD
寄存器的第 17 和第 16 位写入 10
(复位值),就可以将其配置为2MHz
的输出速率:
1 | GPIOB_OSPD |= (0x02 << (2 * 8)); // 向第 17 和 16 位写入 10 |
而向 GPIOB_OSPD
寄存器的第 17 和 第 16 位写入01
,则可以将其配置为 10MHz
的输出速率:
1 | GPIOB_OSPD |= (0x01 << (2 * 8)); // 向第 17 和 16 位写入 10 |
如果向 GPIOB_OSPD
寄存器的第 17 和 第 16 位写入的是11
,则可以将其配置为 50MHz
的输出速率,也就是当前需要为 UINIO-MCU-GD32F350RBT6 的GPIOB
配置的目标频率:
1 | GPIOB_OSPD &= ~(0x03 << (2 * 8)); // 向第 17 和 16 位写入 11 |
注意:十六进制
0x03
的二进制形式为0000 0011
,十六进制0x02
的二进制形式为0000 0010
,十六进制0x01
的二进制形式为0000 0001
。
配置好 GPIOB8对应的端口时钟
、工作模式
、输出类型
之后,就可以通过使其输出高电平点亮LED 发光二极管,或者通过低电平熄灭 LED 发光二极管。
根据用户手册已知 GPIOB 的寄存器基地址为0x4800 0400
,而端口输出模式寄存器 GPIOB_OCTL
的地址偏移量为 0x14
:
那么端口输出控制寄存器 GPIOB_OCTL
的实际地址,就可以通过下面的等式计算得到:
1 | GPIOB_OCTL = 0x4800 0400 + 0x14 = 0x4800 0414 |
通过向上图当中 GPIOB_OCTL
寄存器的第 8 位OCTL8
位写入 1
或者0
,就可以控制相应的 GPIO引脚输出高电平或者低电平:
1 | GPIOB_OCTL &= ~ (0x01 << 8); // 输出低电平 |
除此之外,我们还可以通过端口位操作寄存器GPIOB_BOP
来操作 GPIO 端口的状态。根据用户手册已知GPIOB 的寄存器基地址为0x4800 0400
,而端口输出模式寄存器 GPIOB_BOP
的地址偏移量为 0x18
:
那么端口输出控制寄存器 GPIOB_BOP
的实际地址,就可以通过下面的计算过程获得:
1 | GPIOB_BOP = 0x4800 0400 + 0x18 = 0x4800 0418 |
观察可以发现 GPIOB_BOP
寄存器的高 16 位和低 16位的每一位,都分别对应着一个 GPIO 引脚。其中低十六位\(CR_{0 \sim 15}\) 是置 1
位,而高十六位 \(BOP_{0 \sim15}\) 则属于清 0
位:
GPIOB_BOP
寄存器的高十六位 \(CR_{0 \sim 15}\):置为 1
输出低电平,置 0
电平状态不改变;GPIOB_BOP
寄存器的低十六位 \(BOP_{0 \sim 15}\):置为 1
输出高电平,置 0
电平状态不改变;1 | GPIOB_BOP |= (0x01 << (8 + 16)); // 输出低电平 |
在 Keil-GD32F350RBT6 工程的 Driver
目录下建立一个名为 LED
的子目录,然后分别新建LED.h
和 LED.c
两个源文件,并且在main.c
里包含 LED.h
头文件,全部的示例代码内容如下面所示,即UINIO-MCU-GD32F350RBT6 工程 Examples
目录下的 1-LED-Register
工程:
1 | /*========== LED.h ==========*/ |
1 | /*========== LED.c ==========*/ |
1 | /*========== main.c ==========*/ |
本节内容将采用兆易创新官方提供的标准外设固件库GD32F3x0_Firmware_Library_V2.2.1
来完成点亮 LED的实验,这通常需要经历如下四个步骤:
rcu_periph_clock_enable()
固件库函数使能 GPIO端口对应的外设时钟:1 | void rcu_periph_clock_enable(rcu_periph_enum periph); |
gpio_mode_set()
函数配置 GPIO端口的工作模式以及设置上下拉电阻状态:1 | void gpio_mode_set(uint32_t gpio_periph, uint32_t mode, uint32_t pull_up_down, uint32_t pin); |
gpio_output_options_set()
函数配置指定 GPIO引脚的输出类型与速率:1 | `void gpio_output_options_set(uint32_t gpio_periph, uint8_t otype, uint32_t speed, uint32_t pin); |
gpio_bit_set/write()
指定 GPIO引脚的电平状态:1 | void gpio_bit_set/write(uint32_t gpio_periph, uint32_t pin) |
官方固件库 Firmware\GD32F3x0_standard_peripheral\Include
目录下的头文件 gd32f3x0_rcu.h
里,定义了一个专门用于使能外设时钟的库函数:
1 | void rcu_periph_clock_enable(rcu_periph_enum periph) |
这个函数的 periph
参数是一个rcu_periph_enum
枚举类型的变量,其具体的定义如下面所示:
1 | /* peripheral clock enable */ |
观察可以发现,如果向 rcu_periph_clock_enable()
函数传入上述枚举类型变量当中的枚举值RCU_GPIOB
,就可以使能 GPIOB对应的外设时钟:
1 | rcu_periph_clock_enable(RCU_GPIOB); |
类似的,固件库Firmware\GD32F3x0_standard_peripheral\Include
目录下的头文件 gd32f3x0_gpio.h
里定义了一个用于设置GPIO 工作模式的函数:
1 | /* set GPIO mode */ |
该函数的四个参数,分别用于设置 GPIO 分组
、配置工作模式
、选择上下拉状态
、指定 GPIO 引脚
,具体参数选项请参考下面的源代码片断:
1 | /* GPIOx(x=A,B,C,D,F) definitions */ |
例如现在要配置 GPIOB8引脚为悬空输出模式,则只需要向gpio_mode_set()
函数传入相应的参数即可:
1 | gpio_mode_set(GPIOB, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, GPIO_PIN_8); |
固件库 Firmware\GD32F3x0_standard_peripheral\Include
目录下的 gd32f3x0_gpio.h
头文件里面,同样定义有一个用于设置GPIO 输出类型和速率的库函数:
1 | void gpio_output_options_set(uint32_t gpio_periph, uint8_t otype, uint32_t speed, uint32_t pin); |
这个函数的四个参数,则是分别用于设置 GPIO 分组
、配置输出类型
、最大输出速率
,具体的参数选项同样请参考下面的源代码片断:
1 | /* GPIO output type */ |
例如当前要配置 GPIOB8引脚为推挽输出方式,其最大输出速率为50MHz
,则只需要向 gpio_output_options_set()
函数传入下面的参数即可:
1 | gpio_output_options_set(GPIOB, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_8); |
固件库的 gd32f3x0_gpio.h
头文件里,存在着下面三个可以用于定义 GPIO引脚电平状态的函数:
1 | /* set GPIO pin bit */ |
其中 gpio_bit_set()
和 gpio_bit_reset()
函数用于指定 GPIO 引脚为固定的高电平状态:
1 | gpio_bit_set(GPIOB, GPIO_PIN_8); // 指定 GPIOB8 引脚为高电平 |
而 gpio_bit_write()
函数则可以用来灵活的设置 GPIO引脚为高电平或者低电平状态:
1 | gpio_bit_write(GPIOB, GPIO_PIN_8, 0); // 让 GPIOB8 引脚输出低电平 |
接下来,将 Keil-GD32F350RBT6 示例工程里的LED.h
和 LED.c
以及 main.c
替换为使用固件库的版本,全部的示例代码内容如下面所示,即UINIO-MCU-GD32F350RBT6 工程 Examples
目录下的 2-LED-Library
工程:
1 | /*========== UINIO_LED.h ==========*/ |
1 | /*========== UINIO_LED.c ==========*/ |
1 | /*========== main.c ==========*/ |
在开启进一步的标准固件库学习之前,首先需要了解Keil-GD32F350RBT6 工程的启动顺序,其中Firmware\CMSIS\GD\GD32F3x0\Source\ARM
目录下的startup_gd32f3x0.s
源文件是 GD32F350RBT6微控制器上电复位之后,执行的第一段程序(由汇编语言编写),该程序主要完成了如下几项工作:
在接下来的内容当中,将会根据执行顺序依次探讨startup_gd32f3x0.s
当中各个代码块的功能与用途。
栈主要用于存放局部变量
、函数调用
、函数形式参数
,其由高向低生长,且容量不能超过片上SRAM 存储器的容量大小。
1 | ; <h> Stack Configuration |
上面的汇编代码,开辟了一个大小为 0X00000400
(1KB) 名称为STACK
的栈,其中 NOINIT
表示不初始化,READWRITE
表示可读可写,ALIGN=3
表示 \(2^3 = 8\) 字节对齐。最后的__initial_sp
表示栈的结束地址,也就是栈顶地址。
堆主要用于完成动态内存分配,其由低向高生长,例如malloc()
函数申请的内存就位于在堆上面。
1 | ; <h> Heap Configuration |
上面的汇编代码,开辟了一个大小为 0X00000400
(1KB) 名称为HEAP
的堆,同样的 NOINIT
表示不初始化,READWRITE
表示可读可写,ALIGN=3
表示 \(2^3 = 8\) 字节对齐。
除此之外,__heap_base
表示堆的起始地址,而__heap_limit
表示堆的结束地址。后续的PRESERVE8
表示保留 8 字节对齐,而 THUMB
表示兼容 THUMB 指令集。
向量表是一个 32 位 WORD
字数组,其按照 4 字节进行边界对齐,从片上 Flash的零地址开始进行放置,这个数组保存着一系列程序的入口地址,当GD32F350RBT6微控制器处于不同的预定义状态时,就会通过查找向量表,进入执行对应地址的程序:
1 | ; /* reset Vector Mapped to at Address 0 */ |
上述汇编代码中的 __Vectors
表示向量表的起始地址,而 __Vectors_End
表示向量表的结束地址。除此之外,其中的 DCD
指令用于分配和初始化一个或者多个以字Word
为单位的内存空间,并且以 4 字节进行对齐。
复位处理程序是 GD32F350RBT6上电之后首个要运行的程序,其首先会调用 SystemInit
函数初始化系统时钟,然后再调用 C 库函数 __main
进入用户定义的主函数 main()
:
SystemInit()
是一个 ARM 标准库函数,定义在Keil-GD32F350RBT6 工程Firmware\CMSIS\GD\GD32F3x0\Source
目录下的system_gd32f3x0.c
当中(即 CMSIS Cortex-M4外设接入层源文件),主要用于初始化各种系统时钟。__main
是一个标准 C库函数,主要用于初始化用户堆栈,并且会在最后调用自定义的main()
函数,这也就是 main()
总是作为Keil uVision5 工程入口函数的原因所在。1 | AREA |.text|, CODE, READONLY |
注意:上述源文件当中的第一句代码,用于定义一个名称为
.text
的只读代码段区域。
接下来的代码片段,定义了一系列的异常处理程序和外部中断处理程序,而这些程序的完整实现则保存在外部的.c
源文件当中。当出现相关异常或者发生指定外部中断的时候,程序的执行流程就会跳转至这里指定的各种服务程序当中:
1 | ;/* dummy Exception Handlers */ |
注意:上述汇编代码当中的
B .
语句表示进入了一个无限循环,即通俗意义上的死循环。
接着判断当前 Keil uVision5 工程是否启用有__MICROLIB
库,如果有启用就赋予栈顶地址__initial_sp
、堆起始地址__heap_base
、堆结束地址__heap_limit
。如果没有启用,则会使用双段存储器模式,并且由用户来初始化堆栈空间:
1 | ALIGN |
注意:上述代码当中的
END
是一个汇编程序结束标记。
前面已经介绍过,由汇编语言编写的系统启动文件startup_gd32f3x0.s
调用了Keil-GD32F350RBT6 工程的Firmware\CMSIS\GD\GD32F3x0\Source\system_gd32f3x0.c
源文件当中,由 C 语言编写的系统初始化函数SystemInit()
:
1 | /*! |
可以看到该函数最终调用的是同样定义在这个源文件里的system_clock_config()
方法:
1 | /*! |
由于在 system_gd32f3x0.c
源文件的开头位置,存在着如下针对 GDF350系列微控制器的宏定义:
1 |
所以 system_clock_config()
方法最终实际调用的是该源文件中的函数system_clock_108m_hxtal()
,这个函数的具体定义如下所示:
1 |
|
锁相环(PLL,Phase LockingLoop)是一种反馈控制电路,其工作过程当中,当输出信号频率与输入信号频率相同时,可以使输出电压与输入电压保持固定的相位差,就像输入/输出电压的相位被锁住了一样,所以这种电路被称为锁相环。GD32F350RBT6内部的 PLL 主要用于根据特定的外部晶振信号来生成其它频率的信号。
观察可以发现,上述代码使能了 GD32F350RBT6 内部的 PLL锁相坏,由于当前 UINIO-MCU-GD32F350RBT6核心板的外部贴片晶振频率为8MHz
,所以高速外部晶体振荡器时钟HXTAL = 8MHz
,这样锁相环的输出频率可以按照如下方式进行计算:
\[PLL = \frac{HXTAL}{2} \times 27 = \frac{8MHz}{2} \times 27 = 108 MHz\]
上述代码选择了锁相环的输出作为系统时钟SYSCLK
,并且将高级高性能总线(AHB,AdvancedHigh-performance Bus)时钟配置为了与系统时钟的频率相等:
\[AHB = SYSCLK = 108 MHz\]
而两条高级外设总线(APB,AdvancedPeripheral Bus)时钟频率分别为 AHB 总线时钟的二分之一:
\[\begin{cases}APB1 = \frac{AHB}{2} = \frac{108MHz}{2} = 54MHz \\APB2 = \frac{AHB}{2} = \frac{108MHz}{2} = 54MHz\end{cases}\]
SysTick 定时器是一个拥有自动重装载能力的 24位向下计数器,所有 ARM Cortex-M4内核微控制器都具备该定时器,从而能够方便的在不同型号微控制器之间进行代码移植。当设定SysTick定时器的初始值并且使能之后,每经过一个系统时钟周期,定时器的计数值就会减去1
,当减至 0
的时候,SysTick就会自动重新装载初始值,并且继续开始计数,同时置位内部的COUNTFLAG
标志位,并且触发中断(如果使能有相应的定时器中断)。
观察 GD32F350RBT6微控制器时钟树可以发现,108MHz
频率的 AHB总线时钟 CK_AHB
,在经过 8 分频之后,默认作为了 SysTick系统定时器的时钟源。
标准固件库 Firmware\CMSIS\core_cm4.h
源文件中的SysTick_Type
结构体类型,定义了系统滴答定时器 SysTick相关的寄存器:
1 | /** \brief Structure type to access the System Timer (SysTick). |
该源文件中的 SysTick_Config()
函数,则是用于对上述SysTick相关的寄存器进行配置,在初始化和启动系统滴答定时器的同时,产生周期性的中断。概而言之,其主要完成了下面四个步骤的工作:
LOAD
重载寄存器的初始值;(1 << 4) - 1 = 15
,即优先级为最低;VAL
寄存器,装载 SysTick 的计数值;CTRL
寄存器,使能 SysTick的时钟源、中断、以及外设本身;1 | /** \brief System Tick Configuration |
Keil-GD32F350RBT6 示例工程 Sources
目录下提供的 systick.c
源文件,其中的systick_config()
方法就封装并且调用了上面的SysTick_Config()
函数,在使能 SysTick中断服务程序与定时器的同时,以系统时钟频率的千分之一SystemCoreClock / 1000U
作为 SysTick滴答定时器配置参数,也就是每 1 秒计数一千次,每一次 1毫秒(如果修改为 SystemCoreClock / 1000000U
则可以实现微秒级的延时)。
而 systick.c
源文件当中提供的另一个函数delay_1ms()
,则是以 count
参数(单位为毫秒)进行定时计数,当 volatile
关键字修饰的全局变量 delay
被自减至零的时候,就会自动退出该函数的执行。
1 | /* the systick configuration file */ |
除此之外,上面 systick.c
代码中定义的delay_decrement()
函数,则会被Keil-GD32F350RBT6 工程下Sources/gd32f3x0_it.h/c
源文件内的 SysTick 中断服务程序SysTick_Handler()
调用,具体调用代码如下所示:
1 | /*! |
当每一次进入 SysTick系统滴答定时器中断的时候,上面这个函数就会被调用一次,从而就完成了一次对于delay
变量的自减。
接下来,将前面 LCD 示例工程当中的main.c
源文件修改为如下的代码,使得 LED发光二极管可以每间隔 1 秒钟循环进行闪烁:
1 | /*========== main.c ==========*/ |
SysTick 系统滴答定时器的 counter
从 reload
值往下递减到零的时候,CTRL
寄存器相应的位就会被置为1
,而读取该位的时候,其值又会自动被清零,所以利用这个特点就能够以非常简短的代码,实现类似于官方SysTic 示例的定时器延时功能:
1 | /*========== SysTick.h ==========*/ |
1 | /*========== SysTick.c ==========*/ |
这里可以修改前面的 main.c
源文件,通过自定义的UINIO_SysTick_Delay_us()
和UINIO_SysTick_Delay_ms()
函数来进行延时,从而实现相同的 LED间隔 1 秒循环闪烁的效果:
1 | /*========== main.c ==========*/ |
注意:本节内容涉及的全部源代码,已经保存在UINIO-MCU-GD32F350RBT6 核心板工程
Examples
目录下的3-Systick
。
Keil-GD32F350RBT6 示例工程在Firmware\GD32F3x0_standard_peripheral\Source\gd32f3x0_misc.c
源文件内提供有一个名为 systick_clksource_set()
的库函数,可以用于修改 SysTick的时钟源,其功能与参数说明如下面表格所示:
可以看到,该库函数可以用于选择 SysTick系统滴答定时器的时钟源,可以选择的参数有如下两个:
SYSTICK_CLKSOURCE_HCLK
:系统滴答定时器时钟源来自 AHB时钟;SYSTICK_CLKSOURCE_HCLK_DIV8
: 系统滴答定时器时钟源来自AHB 时钟 8 分频(默认);1 | /*! |
嵌入式开发过程当中,经常需要进行位操作(即对一个比特位进行读写),早期的STC51 系列单片机可以通过关键字 sbit
实现位操作,但是 ARM Cortex-M4架构的微控制器并不存在类似语法,而是通过提供位带别名区到位带区的映射来实现对比特位的操作。
ARM Cortex-M4存储映射当中包含有位带别名区(Bit BandAlias)和位带区(Bit BandRegion)两个区域,通过将位带别名区(Bit BandAlias)当中的每 1 个 Word
字映射到位带区(Bit Band Region)里的Bit
位(ARM 体系结构中 1个字的长度为 32位),这样操作位带别名区当中的字,就等于操作位带区相应的位,具体原理可以参照下面示意图:
基于 ARM Cortex-M4 架构的GD32F350RBT6微控制器,分别在两个区域实现了位带功能(即从位带别名区到位带区的映射):
0x44000000 ~ 0x42000000
地址范围属于位带别名区,而最低的0x40100000 ~ 0x40000000
区别则属于位带区。0x24000000 ~ 0x22000000
地址范围属于位带别名区,而最低的0x20100000 ~ 0x20000000
区别则属于位带区。下面的公式展示了位带别名区域当中的每 1个字,如何对应到位带区域的相应位上面:
1 | 映射到位带区目标位的别名区的字地址 = 位带别名区起始地址 + (位带区目标位所在字节的地址偏移量 × 32) + (目标位在对应字节当中的位置 × 4) |
根据上面的公式,位带区目标位的序号为 number
(取值范围0 <= number <= 31
,具体由待操作的目标寄存器决定),则该比特位在别名区的对应地址为:
1 | 目标位映射到外设别名区的地址 = 0x42000000 + (位带区目标位所在字节的地址 - 0x40000000) * 8 * 4 + (number * 4); |
注意:上述公式当中,因为 1 个字节有 8位,所以需要乘以
8
,而 1 个位膨胀之后对应着 4个字节,所以需要再乘以4
。
接下来,可以将上述的两个公式合并,成为一个用于将位带区地址address
和位序号 bit_number
转换为位带别名区地址的 BITBAND()
宏定义函数:
1 |
上述宏定义语句当中的 address & 0xF0000000
用于取出4
或者 2
,并且以此来判断当前操作的是 SRAM还是外设别名区:
4
,加上 0X0200 0000
之后等于外设别名区的起始地址0X4200 0000
;2
,加上 0X0200 0000
之后等于SRAM 别名区的起始地址 0X2200 0000
;而上述宏定义语句当中 address & 0x00FF FFFF
得到的结果,与减去 0X2000 0000
或者0X4000 0000
得到的结果相同,而后续的<< 5
以及 << 2
则分别起到了乘以32
和乘以 4
的作用(即两种计算方式获得的二进制、十进制、十六进制结果完全相同):
乘法与位运算的对应关系 | |||
---|---|---|---|
10 * 2 = 10 << 1 | 10 * 4 = 10 << 2 | 10 * 8 = 10 << 3 | 10 * 16 = 10 << 4 |
10 * 32 = 10 << 5 | 10 * 64 = 10 << 6 | 10 * 108 = 10 << 7 | 10 * 256 = 10 << 8 |
除法与位运算的对应关系 | |||
---|---|---|---|
10 / 2 = 10 >> 1 | 10 / 4 = 10 >> 2 | 10 / 8 = 10 >> 3 | 10 / 16 = 10 >> 4 |
10 / 32 = 10 >> 5 | 10 / 64 = 10 >> 6 | 10 / 108 = 10 >> 7 | 10 / 256 = 10 >> 8 |
最后,就可以通过指针操作位带别名区的地址,进而实现对于位带区相应比特位的操作:
1 |
由于 GD32F350RBT6 微控制器的GPIOA ~ GPIOF
基地址定义如下面列表所示:
0x4800 0000
;0x4800 0400
;0x4800 0800
;0x4800 0C00
;0x4800 1400
;则可以将上述 GPIO 接口所对应的端口输出控制寄存器GPIOx_OCTL
以及端口输入状态寄存器GPIOx_ISTAT
地址,封装为如下的宏定义语句:
1 | /* 端口输出控制寄存器 GPIOx_OCTL 地址 */ |
上述代码当中的 GPIOx
已经被定义在固件库的gd32f3x0_gpio.h
头文件当中,编译的时候已经由 KeiluVision5自动包含相关路径。接下来的时间,就可以基于上面列出的寄存器地址,进一步将它们封装为控制GPIO 输入与输出的宏定义函数:
1 | /* 控制 GPIOA 的输入与输出 */ |
把上述的宏定义代码保存至 Drivers/BitBand
目录下的BitBand.h
头文件里:
1 | /*========== BitBand.h ==========*/ |
继续修改之前的 LED 闪烁示例工程 main.c
源文件,在包含BitBand.h
头文件的同时,通过调用宏定义函数GPIOB_Out(8)
修改 GPIOB8引脚的电平状态:
1 | /*========== main.c ==========*/ |
除此之外,也可以将位带操作相关的宏定义代码,更加直观的声明在main.c
源文件当中:
1 | /*========== main.c ==========*/ |
微动开关或者轻触按键是通过内部的触点
与弹片
来实现导通与截止,将其连接至GD32F350RBT6 的 GPIO 引脚,就可以通过检测其按下之后GPIO 引脚获取的电平状态,来判断当前是处于按下还是松开的情况:
当按键在被按下或者松开的时候,会由于触点上弹片的弹性作用,发生5ms ~ 10ms
机械抖动,为了避免 GPIO得到错误的状态,必须考虑采取一定的措施去消除这种抖动所带来的干扰:
首先,将一枚轻触按键 SW1
连接到UINIO-MCU-GD32F350RBT6 的 GPIOB9引脚,其中一端连接至 3V3
引脚,而另一端经过位号为R3
的 10KΩ
下拉电阻之后连接至GND
引脚:
然后,使用固件库提供的工具函数,把 GPIOB9配置为带下拉电阻的输入模式,通过检测该引脚的电平状态,就可以判断按键SW1
是否被按下(按键松开为低电平,按键按下为高电平)。
如前所述,使用 GPIO端口的输入输出功能,通常会需要经历下面三个步骤:
void rcu_periph_clock_enable(rcu_periph_enum periph);
固件库函数启用 GPIO 端口对应的外设时钟。void gpio_mode_set(uint32_t gpio_periph, uint32_t mode, uint32_t pull_up_down, uint32_t pin);
固件库函数配置 GPIO 端口的工作模式(输入模式GPIO_MODE_INPUT
、输出模式GPIO_MODE_OUTPUT
、备用功能模式GPIO_MODE_AF
、模拟模式GPIO_MODE_ANALOG
),以及设置上下拉电阻状态(悬空无上下拉GPIO_PUPD_NONE
、带上拉电阻GPIO_PUPD_PULLUP
、带下拉电阻GPIO_PUPD_PULLDOWN
)。void gpio_bit_toggle(uint32_t gpio_periph, uint32_t pin);
固件库函数翻转 LED 对应 GPIO 引脚的电平状态。注意:本节内容所涉及的全部测试代码,已保存在UINIO-MCU-GD32F350RBT6 核心板开源项目
Examples
目录下的 5-Key 工程当中。
1 | /*========== Key.h ==========*/ |
1 | /*========== Key.c ==========*/ |
1 | /*========== main.c ==========*/ |
通用同步/异步收发器(USART,UniversalSynchronous/Asynchronous ReceiverTransmitter)是一种基于数据帧的串行数据通信方式,每一个数据帧都会以1 个起始位
开始,并且以 1个停止位
结束,其数据帧的基本格式如下面示意图所示:
0
,用于通知接收端数据即将开始发送。5 ~ 8
位长度,按照由 LSB(最低有效位)到MSB(最高有效位)的顺序发送。1
,用于标记数据帧传输完毕。注意:空闲帧与停止位一样均为高电平,如果USART连接断开,则下拉为低电平,从而成为断开帧。
USART串行接口可以工作在单工(单向通信)、半双工(双向分时通信)、全双工(双向通信)模式下。每个USART 通信设备之间的 波特率(单位为bit/s
,即每秒钟传送的比特位数)、数据位、停止位、奇偶校验位必须保持一致。
将 UINIO-MCU-GD32F350RBT6 核心板与另一款 UINIO系列开源硬件 UINIO-USB-UART串口调试器 ,参照下图的线路相互进行连接(即UINIO-MCU-GD32F350RBT6 核心板的 GPIOA9
和GPIOA10
分别连接至 UINIO-USB-UART串口调试器的 RXD
和 TXD
引脚),并且将后者的Type-C 接口通过 USB 线缆连接至计算机,从而建立起与串行通信上位机软件的USART 连接,进而可以查看到后续实验代码所打印出的测试数据。
使用 GD32F350RBT6 的片上 USART外设进行通信,需要经历下面六个步骤:
rcu_periph_clock_enable()
。gpio_af_set()
。gpio_mode_set()
。gpio_output_options_set
。usart_deinit()
,并且配置其工作参数usart_deinit()
、usart_baudrate_set()
、usart_parity_config()
、usart_word_length_set()
、usart_stop_bit_set()
。usart_enable()
及其发送功能usart_transmit_config()
。注意:本节内容所涉及的全部测试代码,已保存在UINIO-MCU-GD32F350RBT6 核心板开源项目
Examples
目录下的 6-USART 工程当中。
1 |
|
1 |
|
1 | /*========== main.c ==========*/ |
GD32F350RBT6 微控制器所采用的 ARM Cortex-M4内核架构集成有嵌套式矢量型中断控制器(NVIC,NestedVectored Interrupt Controller),主要用于管理和处理中断:
外部中断/事件控制器(EXTI,External Interrupt/EventController)负责检测来自于中断源的中断请求,并且通知微控制器进行处理。其包含有24个相互独立的边沿检测电路(每个边沿检测电路都可以独立进行配置与屏蔽),能够在微控制器内核当中产生中断请求以及唤醒事件。每一个中断都拥有4 位的中断优先级配置位,可以提供 16个中断优先等级,并且这些中断都拥有着上升沿、下降沿、任意边沿三种触发方式:
上升沿
、下降沿
、任意边沿
。EXTI 中断的触发源可以来自于GPIOA/B/C/F (0~15)
引脚,以及LVD
(低电压检测)、RTC
(实时时钟)、CEC
(HDMI的 CEC控制器)、CMP
(比较器)、USB
、USART
等片上外设:
注意:上述表格当中 EXTI中断线与触发源的对应关系非常重要。
接下来的实验里,首先需要将一枚轻触按键 SW2
连接到UINIO-MCU-GD32F350RBT6 核心板的 GPIOA0引脚,其中一端连接至 3V3
,而另外一端经过位号为R5
的 10KΩ
下拉电阻之后连接至GND
。然后再把 LED3
的一端通过限流电阻R4
连接至 GPIOB8 引脚,另外一端连接到GND
引脚:
最后,再将 UINIO-MCU-GD32F350RBT6 的GPIOA9 和 GPIOA10 分别连接至UINIO-USB-UART 串口调试器的 RXD
和TXD
引脚,以便于通过上位机软件观察 USART串口输出的调试数据。
使用 GD32F350RBT6 微控制器的 EXTI外部中断功能,通常需要经历下面一系列步骤:
rcu_periph_clock_enable()
使能 GPIO 引脚和 CGFCMP系统配置外设时钟。nvic_priority_group_set()
配置优先级分组。nvic_irq_enable()
使能 NVIC中断,并且配置抢占优先级和响应优先级。syscfg_exti_line_config()
将中断线与 GPIO引脚进行连接。exti_init()
设置中断线、中断模式、触发类型。exti_interrupt_enable()
,并且清除中断标志位exti_interrupt_flag_clear()
。startup_gd32f3x0.s
启动文件当中定义好名称,且参数和返回值皆为 void
的中断服务函数(每次中断执行完毕之后都需要清除一下中断标志位)。注意:本节内容所涉及的全部测试代码,已保存在UINIO-MCU-GD32F350RBT6 核心板开源项目
Examples
目录下的 7-EXTI-Key工程当中。
1 | /*========== EXTI-Key.h ==========*/ |
注意:上述代码当中的中断线 0 和 1的中断服务函数名称
EXTI0_1_IRQHandler
已经被定义在startup_gd32f3x0.s
启动文件当中。
1 | /*========== EXTI-Key.c ==========*/ |
1 | /*========== main.c ==========*/ |
GD32F350RBT6微控制器的定时器是一个可编程的无符号计数器,支持输入捕获
与输出比较
,可以按照功能特性被划分为六种类型:
TIMER0
);TIMER1
和TIMER2
);TIMER13
);TIMER14
);TIMER15
和TIMER16
);TIMER5
);也就是 1 个 16位高级定时器(TIMER0
),1 个 32位通用定时器(TIMER1
),5 个 16位通用定时器(TIMER2
、TIMER13 ~ TIMER16
),1个 16 位基本定时器(TIMER5
)。
高级定时器(TIMER0)属于可编程的四通道定时器,包含有16 位无符号计数器,支持输入捕获与输出比较。可以用于产生PWM信号控制电机(包含有死区时间插入模块)以及进行电源管理,其主要特性如下表所示:
高级定时器 TIMER0 特性 | 功能描述 |
---|---|
总通道数 | 4 通道 |
计数器宽度 | TIMER0 是 16位 |
时钟源可选 | 内部时钟、内部触发、外部输入、外部触发 |
多种计数模式 | 向上计数、向下计数、中央计数 |
正交编码器接口 | 用于追踪运动和分辨旋转方向和位置 |
霍尔传感器接口 | 可以用于控制三相电机 |
可编程的预分频器 | 16 位(运行时可以被改变) |
每个通道可配置 | 输入捕获模式、输出比较模式、可编程的 PWM模式、单脉冲模式 |
可编程的死区时间 | 支持 |
自动重装载功能 | 支持 |
可编程的计数器重复功能 | 支持 |
中止输入功能 | 支持 |
中断输出和 DMA 请求 | 更新事件、触发事件、比较/捕获事件、换相事件、中止事件 |
多个定时器的菊链 | 使得一个定时器,能够同时启动多个定时器 |
定时器的同步 | 允许被选择的定时器在同一个时钟周期开始计数 |
定时器主-从管理 | 支持 |
下面的结构框图提供了高级定时器(TIMER0)的内部配置细节:
通用定时器 L0(TIMER1,TIMER2)同样属于可编程的四通道定时器,包含有16 位无符号计数器,支持输入捕获与输出比较。可以用于产生PWM 信号控制电机以及进行电源管理,其主要特性如下表所示:
高级定时器 TIMER1, TIMER2 特性 | 功能描述 |
---|---|
总通道数 | 4 通道 |
计数器宽度 | TIMER2 是 16位,TIMER1 是 32 位 |
时钟源可选 | 内部时钟、内部触发、外部输入、外部触发 |
多种计数模式 | 向上计数、向下计数、中央计数 |
正交编码器接口 | 用于追踪运动和分辨旋转方向和位置 |
霍尔传感器接口 | 可以用于控制三相电机 |
可编程的预分频器 | 16 位(运行时可以被改变) |
每个通道可配置 | 输入捕获模式、输出比较模式、可编程的 PWM模式、单脉冲模式 |
自动重装载功能 | 支持 |
中断输出和 DMA 请求 | 更新事件、触发事件、比较/捕获事件 |
多个定时器的菊链 | 使得一个定时器,能够同时启动多个定时器 |
定时器的同步 | 允许被选择的定时器在同一个时钟周期开始计数 |
定时器主-从管理 | 支持 |
下面的结构框图提供了通用定时器 L0(TIMER1,TIMER2)的内部配置细节:
通用定时器L2(TIMER13)属于可编程的单通道定时器,包含有16 位无符号计数器,支持输入捕获与输出比较。可以用于产生PWM 信号控制电机以及进行电源管理,其主要特性如下表所示:
高级定时器 TIMER13 特性 | 功能描述 |
---|---|
总通道数 | 1 通道 |
计数器宽度 | TIMER13 是 16位 |
时钟源可选 | 内部时钟 |
计数模式 | 向上计数 |
可编程的预分频器 | 16 位(运行时可以被改变) |
每个通道可配置 | 输入捕获模式、输出比较模式、可编程的 PWM模式 |
自动重装载功能 | 支持 |
中断输出 | 更新事件、比较/捕获事件 |
下面的结构框图提供了通用定时器L2(TIMER13)的内部配置细节:
通用定时器L3(TIMER14)属于可编程的两通道定时器,包含有16 位无符号计数器,支持输入捕获与输出比较。可以用于产生PWM信号控制电机(包含有死区时间插入模块)以及进行电源管理,其主要特性如下表所示:
高级定时器 TIMER14 特性 | 功能描述 |
---|---|
总通道数 | 2 通道 |
计数器宽度 | TIMER14 是 16位 |
时钟源可选 | 内部时钟、内部触发、外部输入 |
计数模式 | 向上计数 |
可编程的预分频器 | 16 位(运行时可以被改变) |
每个通道可配置 | 输入捕获模式、输出比较模式、可编程的 PWM模式、单脉冲模式 |
可编程的死区时间 | 支持 |
自动重装载功能 | 支持 |
可编程的计数器重复功能 | 支持 |
中止输入功能 | 支持 |
中断输出和 DMA 请求 | 更新事件、比较/捕获事件、换相事件、中止事件 |
多个定时器的菊链 | 使得一个定时器,能够同时启动多个定时器 |
定时器的同步 | 使得一个定时器,能够同时启动多个定时器 |
定时器主-从管理 | 支持 |
下面的结构框图提供了通用定时器L3(TIMER14)的内部配置细节:
通用定时器 L4(TIMER15,TIMER16)属于可编程的单通道定时器,包含有16 位无符号计数器,支持输入捕获与输出比较。可以用于产生PWM信号控制电机(包含有死区时间插入模块)以及进行电源管理,其主要特性如下表所示:
高级定时器 TIMER15, TIMER16 特性 | 功能描述 |
---|---|
总通道数 | 单通道 |
计数器宽度 | TIMER15 和TIMER16 都是 16 位 |
时钟源可选 | 内部时钟 |
计数模式 | 向上计数 |
可编程的预分频器 | 16 位(运行时可以被改变) |
每个通道可配置 | 输入捕获模式、输出比较模式、可编程的 PWM模式、单脉冲模式 |
可编程的死区时间 | 支持 |
自动重装载功能 | 支持 |
可编程的计数器重复功能 | 支持 |
中止输入功能 | 支持 |
中断输出和 DMA 请求 | 更新事件、比较/捕获事件、换相事件、中止事件 |
下面的结构框图提供了通用定时器 L4(TIMER15,TIMER16)的内部配置细节:
基本定时器(TIMER5)包含有 16位无符号计数器,支持输入捕获与输出比较。可以用于通用定时器,产生DMA 请求,以及为 DAC 数模转换提供时钟,其主要特性如下表所示:
基本定时器 TIMER5 特性 | 功能描述 |
---|---|
计数器宽度 | TIMER5 是 16位 |
时钟源可选 | 内部时钟 |
计数模式 | 向上计数 |
可编程的预分频器 | 16 位(运行时可以被改变) |
自动重装载功能 | 支持 |
中断输出和 DMA 请求 | 更新事件 |
下面的结构框图提供了基本定时器(TIMER5)的内部配置细节:
本章节内容,将会利用基本定时器 TIMER5
以及其关联的定时器中断,来实现让 LED 每隔 1秒不间断进行闪烁的实验。其中,定时器时钟和运行参数的配置,是两个比较重要的知识点,需要大家在实验过程当中特别留意。
观察下面定时器相关的时钟树,可以发现如果 APB总线的时钟分频系数为1
,那么定时器时钟频率就会与 AHB总线保持一致。否则,定时器的时钟频率会被设定为 APB总线频率的 2 倍:
可以看到,系统时钟 CK_SYS
在经过AHB 预分频器之后,可以得到 AHB 总线时钟CK_AHB
。而这个 CK_AHB
再经过 APB1 和APB2 预分频器之后,就可以得到定时器时钟CK_TIMERx
,具体请参考下面的计算公式:
\[CK_{TIMERx} = \frac{CK_{AHB}}{APB_{x预分频值} \div 2}\]
由于固件库 system_gd32f3x0.c
源文件的system_clock_config()
函数当中,已经将APB1 和 APB2 的预分频值设定为2
:
1 | /* APB2 = AHB/2 */ |
根据上面的计算公式,就可以知道定时器时钟CK_TIMERx
与 AHB 总线时钟CK_AHB
的时钟频率值相等:
\[CK_{TIMERx} = \frac{CK_{AHB}}{2 \div 2} = CK_{AHB} = 108MHz\]
官方固件库 gd32f3x0_timer.h
头文件当中定义的结构体变量timer_parameter_struct
,可以用于配置定时器的相关工作参数:
1 | /* constants definitions */ |
在下面的列表里,展示了这些参数的具体功能与用途:
0 ~ 65535
。TIMER_COUNTER_EDGE
、TIMER_COUNTER_CENTER_DOWN
、TIMER_COUNTER_CENTER_UP
、TIMER_COUNTER_CENTER_BOTH
。TIMER_COUNTER_UP
和 TIMER_COUNTER_DOWN
。0 ~ 65535
,当计数器达到周期值的时候,计数值将会清零,可以配合计数器时钟频率计算出中断时间。TIMER_CKDIV_DIV1
、TIMER_CKDIV_DIV2
、TIMER_CKDIV_DIV4
,主要用于输入捕获场景。0 ~ 255
。类似于前面 《通过 GPIO 固件库控制LED》 章节的实验电路,这里同样将 4.7K
限流电阻R1
与 LED 发光二极管串联之后,再连接到UINIO-MCU-GD32F350RBT6 核心板的 GPIOB8
引脚(高电平点亮,低电平熄灭):
除此之外,还需要再将 UINIO-MCU-GD32F350RBT6 核心板的GPIOA9 和 GPIOA10 引脚,分别连接至UINIO-USB-UART 串口调试器的 RXD
和TXD
引脚,这样就可以完成实验电路的搭建。
本节内容的实验,主要基于 16 位的基本定时器TIMER5
来实现 LED 每间隔 1秒进行闪烁的效果,完成该功能大致需要经历下面六个步骤:
CK_TIMERx = CK_AHB = 108MHz
,所以本示例缺省该步骤。timer_parameter_struct
结构体的成员属性,然后调用timer_init()
初始化定时器。nvic_irq_enable()
设置定时器中断的优先级。timer_interrupt_enable()
使能定时器更新中断事件。timer_enable()
函数使能定时器自身。TIMER5_DAC_IRQHandler()
,该函数名称已在启动文件startup_gd32f3x0.s
进行过声明。注意:本节内容所涉及的全部测试代码,已保存在UINIO-MCU-GD32F350RBT6 核心板开源项目
Examples
目录下的 8-Timer-LED工程当中。
1 | /*========== TIMER_LED.h ==========*/ |
1 | /*========== TIMER_LED.c ==========*/ |
1 | /*========== main.c ==========*/ |
脉冲宽度调制(PWM,Pulse-widthmodulation)是一种通过将电平信号分散为离散形式,从而达到调整电压和频率,乃至于平均功率的目的。
这项技术可以用于动态控制 LED亮度乃至于电机转速,其主要涉及到如下三个重要的参数:
GD32F350RBT6 微控制器的 TIMER1
是一个通用定时器,拥有四路 PWM 通道,其中的每一路通道都对应着1 个 GPIO 引脚(需要进行复用设置)。通过下面的表格,可以发现GPIOA5
引脚的复用功能 AF2
,对应的就是TIMER1
定时器的 CH0
通道:
注意:GPIO 的复用功能可以通过固件库函数
void gpio_af_set(uint32_t gpio_periph, uint32_t alt_func_num, uint32_t pin)
进行设置。
根据下面通用定时器 TIMER1
的结构框图,可以观察到该定时器各个通道时钟信号的来龙去脉。其中带有层叠效果的框图,表示其对应有影子寄存器:
注意:影子寄存器可以让指令重复使用相同的寄存器编码,但是在不同模式下,这些编码对应的是不同的物理寄存器。
相比于之前基本定时器的实验,本实验需要将定时器配置函数UINIO_PWM_Config()
的时钟分频值修改为108
,从而使得分频后的定时器时钟频率等于:
\[分频后的时钟频率 PSC_{CLK} = \frac{定时器时钟频率 108MHz}{预分频值108} =1MHz\]
再根据下面的公式,就可以计算得到此时 PWM 脉冲宽度调制信号的输出频率为100Hz
:
\[PWM 输出频率 = \frac{分频后的时钟频率 1MHz}{周期值 10000 微秒} = 100Hz\]
注意:该脉冲频率远高于肉眼可以鉴别出的
50Hz
临界闪烁频率,所以不会导致 LED发生明显的闪烁现象,可以呈现出比较完美的呼吸灯效果。
类似于之前 《基本定时器 TIMER5与中断》 章节的实验电路,这里同样需要将 4.7K
限流电阻R1
与 LED发光二极管进行串联,有所不同之处在于这里需要将其连接至UINIO-MCU-GD32F350RBT6 核心板的 GPIOA5
引脚,然后由通用定时器 TIMER1
的通道0
输出 PWM 脉冲信号:
除此之外,依然需要把 UINIO-MCU-GD32F350RBT6 核心板的GPIOA9 和 GPIOA10 引脚,分别连接至UINIO-USB-UART 串口调试器的 RXD
和TXD
引脚,从而能够使用串口上位机软件,查看到当前 LED的亮灭状态调试信息。
本实验通过 PWM 输出脉冲波来实现 LED的呼吸灯效果,大致上需要经历如下一系列的配置过程:
gpio_af_set()
配置 PWM 功能对应 GPIO引脚的复用功能。timer_init()
配置 PWM 定时器参数。timer_channel_output_config()
配置 PWM输出通道参数。timer_channel_output_pulse_value_config()
函数将定时器 TIMER1
通道输出的脉冲值置为0
。timer_channel_output_mode_config()
配置定时器输出通道的比较模式为 PWM 模式 0。timer_channel_output_shadow_config()
失能定时器输出通道的比较影子寄存器。timer_auto_reload_shadow_enable()
使能定时器自动重载影子寄存器。timer_enable()
使能 PWM 相关的定时器。timer_channel_output_pulse_value_config()
函数,通过动态设定脉冲值(介于 0 ~ 65535
范围)实现 LED的呼吸灯效果。1 | /*========== PWM_LED.h ==========*/ |
1 | /*========== PWM_LED.h ==========*/ |
1 | /*========== main.c ==========*/ |
直接存储器存取(DMA,Direct MemoryAccess)主要运用在不占用内核计算资源的情况下,进行数据的传递(外设 → 存储器
、存储器 → 外设
、存储器 → 存储器
)。GD32F350RBT6只拥有一个 DMA 控制器,其拥有 7个通道,每个通道都用于处理各个外设的存储器访问请求,这些外设包括有ADC、SPI、I2C、USART、DAC、I2S以及定时器。
观察上面的 DMA 功能结构框图,可以发现 DMA控制器主要由如下四个部分组成:
本节内容的实验,需要通过 USART 输出 DMA传输过来的数据信息,所以依然要把 UINIO-MCU-GD32F350RBT6核心板与另外一款 UINIO 系列开源硬件 UINIO-USB-UART串口调试器 ,参照下图的线路进行相互连接:
也就是把 UINIO-MCU-GD32F350RBT6 核心板的GPIOA9
和 GPIOA10
引脚,分别连接至UINIO-USB-UART 串口调试器的 RXD
和TXD
引脚,然后将后者的 Type-C 接口通过 USB线缆连接到计算机,进而可以借助 COMTransmit等串口调试助手软件,查看到 DMA 传输过来的各种数据和日志信息。
当使用 DMA进行数据传输时,会首先从源地址读取数据,然后再将读取的数据存储到目的地址,使用时通常需要遵循如下步骤:
rcu_periph_clock_enable(RCU_DMA)
使能 DMA外设时钟。dma_parameter_struct
。dma_init()
。dma_circulation_enable/disable()
和dma_memory_to_memory_enable/disable()
配置 DMA相关模式。dma_interrupt_enable()
使能 DMA 中断。dma_channel_enable()
使能 DMA 通道本身。1 | /*========== gd32f3x0_it.c ==========*/ |
1 | /*========== main.c ==========*/ |
.md
或者.markdown
扩展名,可以被 Pandoc等预处理工具渲染为指定 CSS 样式的 HTML页面。除了使用 VSCode、Sublime等编辑器进行撰写,还可以采用 Markdown 在线编辑器,或者借用Markdown在线表格生成器 辅助生成内容。笔者日常开发设计工作当中,经常需要使用到 Markdown来撰写各类技术笔记,以及项目的 README.md
文档。不同于网络上其它琳琅满目的 Markdown在线教程,这篇文章会在介绍相关语法特性的同时,侧重于体现Markdown 语法与 HTML元素之间的映射关系,从而更加清晰的呈现其底层的转换逻辑,便于大家结合自定义的CSS 样式与 HTML标签,创造出更加丰富多彩的 Markdown 文本内容。
下面表格当中的 Markdown 基本元素,是作者 John Gruber最初设计的元素,几乎所有的 Markdown 预处理工具都支持它们。
Markdown 基本元素 | Markdown 语法 |
---|---|
标题(Heading) | # 标题层级 1 |
粗体(Bold) | **粗体文本内容** |
斜体(Italic) | *斜体文本内容* |
引用块(Blockquote) | > 引用的内容 |
有序列表(Ordered List) | 1. 第 1 条有序列表项; 2. 第 2条有序列表项; 3. 第 3 条有序列表项; |
无序列表(Unordered List) | - 这是一条无序列表项; |
代码(Code) | `行内代码` |
分隔线(Horizontal Rule) | --- |
链接(Link) | [链接名称](链接地址 "链接标题") |
图片(Image) | ![图片替代文本](图片地址 "图片标题") |
而下面表格当中的 Markdown 扩展元素,则是由各种Markdown 预处理工具自行扩展而来,使用时需要特别注意其兼容性。
Markdown 扩展元素 | Markdown 语法 | ||
---|---|---|---|
表格(Table) |
| ||
代码块(Fenced Code Block) |
| ||
☀ 脚注(Footnote) |
| ||
☀ 标题自定义 ID(Heading ID) |
| ||
☀ 定义列表(Definition List) |
| ||
删除线(Strikethrough) |
| ||
任务列表(Task List) |
|
注意:上述表格当中使用 ☀ 标注的脚注、标题自定义ID、定义列表,在大部分 Markdown预处理工具当中存在有兼容性问题,使用时需要特别注意。
Markdown 通过在内容的前面使用 #
号来添加标题,其中 #
的数量代表了标题的层级。例如 3 个 #
号就表示创建了一个三级标题 <h3>
。
Markdown 语法 | HTML 语句 | 效果预览 | ||||
---|---|---|---|---|---|---|
|
| 标题层级 1 | ||||
|
| 标题层级 2 | ||||
|
| 标题层级 3 | ||||
|
| 标题层级 4 | ||||
|
| 标题层级 5 | ||||
|
| 标题层级 6 |
注意:最佳实践是在
#
号与标题之间使用【空格】进行分隔,从而能够规避一些兼容性方面的问题。
Markdown使用一个或者多个的空行来实现段落的效果。
Markdown 语法 | HTML 语句 | 效果预览 | ||||
---|---|---|---|---|---|---|
|
| 这是第 1 个段落。 这是第 2 个段落。 这是第 3 个段落。 |
Markdown在内容的末尾添加两个或者多个空格,然后再按下回车键,就可以创建出一个换行效果。
Markdown 语法 | HTML 语句 | 效果预览 | ||||
---|---|---|---|---|---|---|
|
| 这是第 1 行内容。 |
注意:某些 Markdown编辑器的格式化工具,会自动清除内容末尾的空格,从而导致换行不成功,所以推荐使用段落来实现类似换行的效果。
Markdown通过粗体和斜体来实现强调的效果。其中在内容的前后,分别添加两个星号**
或者两条下划线__
,就可以实现粗体的效果。
Markdown 语法 | HTML 语句 | 效果预览 | ||||
---|---|---|---|---|---|---|
|
| 使用星号的粗体内容。 | ||||
|
| 使用下划线的粗体内容。 |
除此之外在内容的前后,还可以分别添加一个星号*
或者一条下划线_
,从而实现出斜体的效果。
Markdown 语法 | HTML 语句 | 效果预览 | ||||
---|---|---|---|---|---|---|
|
| 使用星号的斜体内容。 | ||||
|
| 使用下划线的斜体内容。 |
如果需要同时运用粗体加上斜体的效果来强调内容,那么可以在该内容前后分别添加三个星号***
或者三条下划线___
,并且保留一个空格。
Markdown 语法 | HTML 语句 | 效果预览 | ||||
---|---|---|---|---|---|---|
|
| 使用星号的粗体加斜体内容。 | ||||
|
| 使用下划线的 粗体加斜体内容 。 |
注意:某些 Markdown编辑器的格式化工具,会自动把
_内容_
转换为*内容*
、__内容__
转换为**内容**
、***内容***
转换为**_内容_**
,所以这里推荐遵循如下规则来使用 Markdown的强调语法:
- 粗体 使用
**内容**
语法;- 斜体 使用
*内容*
语法;- 粗体加斜体 使用
**_内容_**
语法(注意左右两侧需要保留 1 个空格);
Markdown 通过在内容段落的前面添加 >
符号来实现引用效果。
Markdown 语法 | HTML 语句 | 效果预览 | ||||
---|---|---|---|---|---|---|
|
|
|
通过使用一个内容为空的 >
引用,就可以实现对引用内容的换行效果:
Markdown 语法 | HTML 语句 | 效果预览 | ||||
---|---|---|---|---|---|---|
|
|
|
通过重复使用 > 内容
还可以实现对于引用内容的嵌套显示:
Markdown 语法 | HTML 语句 | 效果预览 | ||||
---|---|---|---|---|---|---|
|
|
|
除此之外,还可以在 Markdown的引用当中嵌套无序列表和有序列表:
Markdown 语法 | HTML 语句 | 效果预览 | ||||
---|---|---|---|---|---|---|
|
|
|
1 | > 这是一条引用内容: |
1 | <blockquote> |
Markdown 可以使用- 列表项内容
(推荐使用)、* 列表项内容
、+ 列表项内容
语法来渲染无序列表:
Markdown 语法 | HTML 语句 | 效果预览 | ||||
---|---|---|---|---|---|---|
|
|
|
除此之外,Markdown 还可以通过序数. 列表内容
语法来渲染有序列表:
Markdown 语法 | HTML 语句 | 效果预览 | ||||
---|---|---|---|---|---|---|
|
|
|
如需需要在列表当中插入其它内容(包括图片
、代码块
、其它列表
、换行
、引用
),则需要将该内容缩进一个制表符或者四个空格:
Markdown 语法 | HTML 语句 | 效果预览 | ||||
---|---|---|---|---|---|---|
|
|
|
Markdown 使用一个反引号 `语法来展示行内的代码片断:
Markdown 语法 | HTML 语句 | 效果预览 | ||||
---|---|---|---|---|---|---|
|
| 这是一条行内代码片断 |
如果需要在一个行内的代码片断当中,展示反引号内容,则可以将其包裹在两个反引号`` 当中进行转义。
Markdown 语法 | HTML 语句 | 效果预览 | ||||
---|---|---|---|---|---|---|
|
| 一行内容 |
除此之外,Markdown支持通过三个反引号```(推荐使用)或者波浪号 ~~~来展示块级的代码片段:
1 | ` ` ` |
如果在第一个 ``` 或 ~~~后面,添加当前代码片断所使用的编程语言名称(例如下面例子使用的 C语言),则可以启用相应的语法高亮:
1 | ` ` ` C |
注意:上面代码为了避免错误渲染,在 ` 与 `之间添加了额外的空格,实际使用时需要去除掉这些空格。
Markdown通过在单独的一行上面,使用三个或者多个星号***
、破折号---
、下划线___
(推荐使用)就可以渲染出分隔线:
Markdown 语法 | HTML 语句 | 效果预览 | ||||
---|---|---|---|---|---|---|
|
|
Markdown 当中可以使用[链接名称](链接地址 "链接标题")
格式的语法添加一个超级链接:
Markdown 语法 | HTML 语句 | 效果预览 | ||||
---|---|---|---|---|---|---|
|
| 链接名称 |
注意:
链接标题
是鼠标在链接上悬停时显示的信息,链接名称
是链接实际渲染时显示的内容,链接地址
则是需要跳转到的目标URL 地址。
使用尖括号 <>
语法,可以方便的将URL 地址或者 E-Mail地址转换为链接。
Markdown 语法 | HTML 语句 | 效果预览 | ||||
---|---|---|---|---|---|---|
|
| http://www.uinio.comuinika@outlook.com |
Markdown 里可以通过![图片替代文本](图片地址 "图片标题")
格式语法插入一张图片:
Markdown 语法 | HTML 语句 | 效果预览 | ||||
---|---|---|---|---|---|---|
|
|
注意:
图片替代文本
是图片资源缺失时显示的信息,图片地址
是图片的 URL地址,图片标题
则是鼠标悬停时显示的信息。
如果需要为图片添加一个 URL链接,则只需要将上述的图片语法嵌入至链接语法内部即可:
Markdown 语法 | HTML 语句 | 效果预览 | ||||
---|---|---|---|---|---|---|
|
|
Markdown 当中可以通过使用连字符---
和管道符 |
来构建表格。
Markdown 语法 | HTML 语句 | 效果预览 | ||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
|
通过向 Markdown表格当中连字符的左右两侧添加 :
冒号,就可以控制表格当中文本的左、中心、右对齐(实质是向表格的<th>
、<td>
标签添加了align="left/center/right"
属性)。
Markdown 语法 | HTML 语句 | 效果预览 | ||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
|
注意:如果需要在表格当中显示管道符
|
,为了避免语法冲突,则需要改为直接使用 HTML 实体|
。
Markdown 当中可以使用反斜杠\
来转义下面列表当中的这些字符。
\ | ` | * | _ | # |
---|---|---|---|---|
{ } | [ ] | ( ) | + | - |
. | ! | | |
注意:对于 Markdown 当中出现的
<
和&
两个特殊符号,就需要使用其对应的HTML 实体形式<
和&
才能够正常显示。
Markdown 可以基于减号-
、方括号[ ]
、字母 x
创建出一个可进行勾选的任务列表。
Markdown 语法 | HTML 语句 | 效果预览 | ||||
---|---|---|---|---|---|---|
|
|
|
Markdown可以通过向指定内容的左右两侧,分别添加两个波浪号~~
,从而在这些内容上面显示一条删除线:
Markdown 语法 | HTML 语句 | 效果预览 | ||||
---|---|---|---|---|---|---|
|
|
|
v0.8.24
。除了 Solidity 的各种常用语言特性之外,还会介绍一系列 Web 3.0开发过程当中,所经常使用的第三方开源项目。其中 Hardhat是一个用于编译、部署、测试、调试以太坊应用的开发环境,而 Ganache则是一款用于开发测试 dApps(DecentralizedApplications)的本地区块链应用。除此之外,OpenZeppelin的 Contract则是一款用于开发安全智能合约的库,提供有 ERC20 和ERC721的标准实现,以及灵活的的权限方案,乃至于各种常用的工具组件。
Web 3.0 术语 | 解释 |
---|---|
区块 | 区块包含有大量捆绑的交易,以其作为最小单位在所有节点当中进行分发,如果两个交易相互矛盾,那么排在第二位的交易会被拒绝,不会成为区块的一部分。 |
区块链 | 区块链就是指区块按照时间形成的线性序列,区块每间隔一段时间就会被添加到链上面,其本质上就类似于一个公共的事务型数据库。 |
以太坊虚拟机 | 以太坊虚拟机(EVM,EthereumVirtual Machine)是以太坊智能合约的运行环境。 |
以太坊账户 | 以太坊账户主要分为两种:外部账户(由公私钥对控制,地址由公钥确定)、合约账户(由与账户一起存储的代码控制,地址在合约创建时被确定)。 |
以太坊账户余额 | 以太坊账户余额的最小单位是Wei (\(1 ETH = 10^{18}wei\))),余额会因为发生以太币的交易而改变。 |
交易 | 交易可以视为帐户之间相互发送的消息,每笔交易都会消耗一定数量的Gas(由交易的发起人支付)。 |
Hardhat是一款编译、部署、测试和调试以太坊应用的开发工具,可以用于实现智能合约与dApps 开发过程当中的自动化任务,但是 Hardhat最核心的地方依然是编译、运行、测试智能合约。
1 | npm install --save-dev hardhat |
注意:Hardhat 需要运行在 NodeJS 基础之上,所以在安装 Hardhat之前需要先行安装 NodeJS,并且将安装目录填写至
PATH
环境变量当中。
通过上面的语句,可以在一个 npm 工程当中快速的安装Hardhat,然后在工程目录里执行npx hardhat
,就可以快速查看当前可用的命令与任务:
1 | λ npx hardhat |
通过运行 npx hardhat init
可以初始化出一个基本的 Hardhat工程目录结构:
contracts
目录:用于存放 .sol
智能合约scripts
目录:用于存放任务脚本。test
目录:用于存放测试文件。hardhat.config.js
文件:Hardhat 配置文件。在工程目录运行 npx hardhat compile
命令,可以编译contracts
目录下的智能合约(例如该工程当中的contracts/Lock.sol
文件):
1 | λ npx hardhat compile |
然后再运行 npx hardhat test
命令,可以执行contracts
目录下的测试脚本文件(例如本工程当中的test/Lock.js
文件):
1 | λ npx hardhat test |
继续运行 npx hardhat run scripts/deploy.js
命令,就可以执行 scripts
目录下的 Hardhat任务脚本(例如本工程当中的 scripts/deploy.js
文件),此时Hardhat 会将智能合约部署到执行命令时,自动启动的 Hardhat Network本地测试网络服务当中:
1 | λ npx hardhat run scripts/deploy.js |
除此之外,也可以通过手动运行 npx hardhat node
命令,启动该本地测试网络服务的同时,还会生成一系列测试用账户:
1 | λ npx hardhat node |
注意:Hardhat 内置的 Hardhat Network是一个为开发而设计的本地以太坊网络。
通过 npx hardhat node
启动 Hardhat Network本地测试网络服务之后,就会向外暴露一个 JSON-RPC 服务接口http://127.0.0.1:8545/
,把区块链钱包等应用连接至该接口就可以使用。此时如果需要将上面的Lock.sol
智能合约,部署到上述这个已经启动了的测试网络,则需要再添加上一个--network localhost
参数:
1 | λ npx hardhat run scripts/deploy.js --network localhost |
通过向 Hardhat 项目当中的 .sol
智能合约里引入console.sol
,就可以愉快的在项目当中使用console.log();
日志打印方法,从而能够更加便捷的在 HardhatNetwork 控制台查看到智能合约打印的调试信息:
1 | import "hardhat/console.sol"; |
web3.js是以太坊官方开源社区提供的一个 JavaScript 库,允许通过HTTP、IPC、WebSocket 与本地或者远程的以太坊 EVM区块链节点进行各种交互,可以通过下面的命令将其安装在 Hardhat工程当中:
1 | npm install --save-dev web3 |
除此之外,也可以通过在 Hardhat 项目当中安装插件的形式,将 Web3.js无缝整合到到工程当中:
1 | npm install --save-dev @nomicfoundation/hardhat-web3-v4 |
通过在 Hardhat 当中编写 script
脚本,就可以借助 Web3.js 与 Hardhat本地的测试网络进行交互,具体步骤请参考下面的示例代码:
1 | const { Web3 } = require("web3"); |
Solidity 将 Web 3.0当中的智能合约视为面向对象编程当中的类,每一份智能合约可以包含状态变量
、函数
、函数修饰器
、事件
、错误
、结构体类型
、枚举类型
的声明,并且智能合约之间也可以相互进行继承。
// SPDX-License-Identifier: MIT
称为 SPDX许可标识符,用于声明当前 Solidity 源代码基于 MIT开源协议编写。pragma solidity >=0.8.24 <0.9.0;
称为版本编译指示,用于声明当前代码所要使用的 Solidity编译器版本(大于或等于 0.8.24
但是低于 0.9.0
的版本)。1 | // SPDX-License-Identifier: MIT |
注意:访问 Solidity智能合约当中的状态变量(例如上面的
data
状态变量),通常不需要添加this
关键字,通过变量名称就可以直接进行访问。
状态变量是指其值被永久地存储在合约存储中的变量。
1 | // SPDX-License-Identifier: MIT |
函数 function
用于接受参数并且返回变量,即可以在智能合约 contract
的内部定义,也可以在智能合约的外部定义。
1 | // SPDX-License-Identifier: MIT |
函数修饰器 modifier
可以用于以声明的方式修改函数的语义。
1 | // SPDX-License-Identifier: MIT |
注意:修饰器与函数一样也可以被重载。
事件 event
可以用于方便的调用以太坊虚拟机 EVM 的日志功能。
1 | // SPDX-License-Identifier: MIT |
结构体类型 struct
是一种可以把多个具有关联关系的变量,组合在一起的自定义数据类型。当声明并且定义好一个结构体变量之后,就可以通过成员访问操作符.
访问结构体的成员:
1 | // SPDX-License-Identifier: MIT |
枚举可用来创建由一定数量的'常量值'构成的自定义类型
1 | // SPDX-License-Identifier: MIT |
错误 error
可以用于为系统异常定义描述性的名称和信息,其 Gas开销要比使用字符串更加便宜。
1 | // SPDX-License-Identifier: MIT |
Solidity 支持 C 语言风格的单行与多行注释:
1 | // 这是一条 单行注释 |
除此之外,Solidity 还支持 NatSpec 风格的注释,也就是 ///
和 /** ... */
,主要用于函数声明和定义相关的语句上面:
1 | // SPDX-License-Identifier: MIT |
Solidity当中的变量按照作用域可以划分为状态变量(StateVariable)、局部变量(LocalVariable)、全局变量(Global Variable)三种类型:
状态变量是用于将数据保存在区块链上的变量,智能合约当中的函数都可以进行访问,所消耗的Gas 比较高:
1 | // SPDX-License-Identifier: MIT |
局部变量只在函数执行期间有效,存储在内存当中,不会上链,所消耗的Gas 比较低:
1 | // SPDX-License-Identifier: MIT |
全局变量基本都是 Solidity预留的关键字,可以在函数当中不声明直接进行使用,具体请叁考官方文档中的《单位和全局变量》:
1 | // SPDX-License-Identifier: MIT |
常量 constant
必须在声明的同时进行初始化,后续不能再进行修改。
1 | // SPDX-License-Identifier: MIT |
不变量 immutable
可以在声明的时候,或者构造函数(非普通函数)当中进行初始化,使用起来将会更加便利。
1 | // SPDX-License-Identifier: MIT |
Solidity 同样提供有 if else
条件判断语句和for
、while
、do while
循环控制语句,以及 continue
、break
关键字和三元操作符。
1 | // SPDX-License-Identifier: MIT |
1 | // SPDX-License-Identifier: MIT |
1 | // SPDX-License-Identifier: MIT |
1 | // SPDX-License-Identifier: MIT |
1 | // SPDX-License-Identifier: MIT |
对数值类型的变量进行赋值时候,直接传递的是数值本身。
Solidity 当中布尔类型 bool
可取的值只有true
和 false
两个:
1 | // SPDX-License-Identifier: MIT |
int
和 uint
分别表示有符号和无符号的整型变量(uint
和 int
本质上分别是 uint256
和int256
的别名)。int8
到 int256
以及uint8
到 uint256
可以用于表示从 8 位到256位,以八位作为步长递增的有符号或者无符号整型变量。1 | // SPDX-License-Identifier: MIT |
地址类型是 Solidity提供的一种特殊数据类型,主要用于保存以太坊地址,并且拥有一系列的成员变量:
address
: 用于保存 20 字节的太坊地址,;address payable
: 保存太坊地址的同时,还拥有额外的transfer()
和 send()
方法;1 | // SPDX-License-Identifier: MIT |
注意:上述两种地址类型进行转换时,
address payable
可以自动转换为address
,而address
则需要通过payable(<address>)
,才能被强制转换为address payable
。
枚举类型 enum
用于为从 0
开始计数的uint
类型数据分配名称(最大不能超过256
),从而提高代码的可读性:
1 | // SPDX-License-Identifier: MIT |
对引用类型变量进行赋值的时候,实际上传递的是地址指针。
Solidity的数组可以在声明时指定长度(数组元素类型[长度]
),也可以动态调整长度(数组元素类型[]
):
1 | // SPDX-License-Identifier: MIT |
1 | uint[] memory number = new uint[](3); |
注意:Solidity判别数组元素类型的时候,总是会以第 1个元素的数据类型作为判定依据。
定长字节数组bytes1
、bytes2
、bytes3
...bytes32
用于表达从 1 至32 长度的字节序列。
1 | // SPDX-License-Identifier: MIT |
变长字节数组 bytes
和变长 UTF-8编码字符串 string
本质上是一种特殊的数组。
bytes
类似于bytes1[]
,但是由于采用了紧打包,存储空间占用相对较少,更加节省Gas 费用;string
与 bytes
相同,不过不允许通过长度或者索引来进行访问;1 | // SPDX-License-Identifier: MIT |
注意:
bytes
和string
类型都提供有一个concat()
函数,用于连接两个字符串,该函数会分别返回bytes
或string
类型的memory
存储位置数组。
Solidity 可以通过结构体 struct
来自定义数据类型,其中的元素既可以是数值类型,也可以是引用类型:
1 | // SPDX-License-Identifier: MIT |
Solidity 的映射类型使用语法mapping(键类型 键名称 => 值类型 值名称)
,其中键和值的名称都可以被省略,映射的值只能在函数内进行修改:
1 | // SPDX-License-Identifier: MIT |
Solidity 当中映射的存储位置必须为storage
,向映射新增键值对的语法为映射名称[键] = 值
:
1 | // SPDX-License-Identifier: MIT |
可以将引用类型的数组、结构体、映射存储位置,分别指定为storage
、memory
、calldata
,不同存储类型所耗费的Gas 成本不同:
storage
:智能合当中的状态变量都默认为storage
类型,存储在链上面,消耗 Gas 较多。memory
:函数当中的参数和临时变量都属于memory
类型,主要存储在内存当中,不会上链,消耗 Gas较少。calldata
:类似于 memory存储在内存且不会上链,区别在于存储位置的变量不能被修改,消耗 Gas较少。不同于 JavaScript,在 Solidity 当中不存在 未定义
或者空
值的概念,而且新声明的变量总是被指定为其所属数据类型的默认值。
名称 | 值类型 | 默认值 |
---|---|---|
布尔类型 | boolean | false |
字符串类型 | string | "" |
整型 | int | 0 |
无符号整型 | uint | 0 |
枚举类型 | enum | 首个元素 |
地址类型 | address | 0x0000000000000000000000000000000000000000 |
函数类型 | function | 空白函数 |
名称 | 引用类型 | 默认值 |
---|---|---|
映射 | mapping | 所有元素都是其所属数据类型的默认值; |
结构体 | struct | 所有成员都是其所属数据类型的默认值; |
数组 | array | 动态数组默认为[] ,定长数组为元素所属数据类型的默认值; |
Solidity 提供了一个 delete
操作符,可以将指定的变换恢复为初始值:
1 | // SPDX-License-Identifier: MIT |
Solidity当中的函数可以接收参数,并且返回相应的处理结果,其基本的定义形式为:
1 | function 函数名称(参数类型 _参数名称1, 参数类型 _参数名称2) internal|external|public|private pure|view|payable returns(返回值类型 返回值名称1, 返回值类型 返回值名称2){ |
1 | // SPDX-License-Identifier: MIT |
当然,也可以显式的在 Solidity 当中使用 return
关键字返回值:
1 | function 函数名称(参数类型 _参数名称1, 参数类型 _参数名称2) internal|external|public|private pure|view|payable returns(返回值类型 返回值名称1, 返回值类型 返回值名称2){ |
1 | // SPDX-License-Identifier: MIT |
除此之外,Solidity函数返回值的读取,可以采用解构的方式,一次性读取全部或者部分的返回值:
1 | 变量类型 _变量名称1; |
1 | // SPDX-License-Identifier: MIT |
声明为 view
的函数,可以读取状态,但是不能修改状态,这里的状态是指:
selfdestruct
;view
或者 pure
的函数;1 | // SPDX-License-Identifier: MIT |
声明为 pure
的函数,即不能读取状态,也不能修改状态,而这里的状态则是指:
address(this).balance
或者<address>.balance
。block
、tx
、msg
当中的成员(除 msg.sig
和 msg.data
之外)。pure
的函数。1 | // SPDX-License-Identifier: MIT |
注意:由于被声明为
pure
和view
的函数不能修改状态变量,因而调用时也就无需被收取 Gas费用。
每一份 Solidity 智能合约都可以定义一个 constructor
构造函数,该函数会在智能合约部署的时候自动被执行一次,因而可以用于初始化一些参数:
1 | // SPDX-License-Identifier: MIT |
Solidity 提供的 modifier
修饰器语法,能够以声明的方式来改变一些函数的行为,例如在执行函数之前自动进行一个检查:
1 | // SPDX-License-Identifier: MIT |
注意:函数修饰器提供的占位符语句
_
用于表示添加了修饰符的函数主体被插入的位置。
public
的状态变量:编译器会自动为其生成 Getter
函数,从而允许其它智能合约读取其值。除此之外,同一个合约当中使用时,通过this.x
外部访问时也会调用 Getter
函数,而通过x
直接内部访问则会直接从存储获取变量值。 由于没有生成Setter
函数,所以其它智能合约无法修改其值。internal
的状态变量:只能从其所定义的智能合约,或者派生出的智能合约当中进行访问,这也是状态变量的默认的可见性。private
的状态变量:类似于内部变量,但是在派生出的智能合约当中不可以访问。external
的函数:只能被其它智能合约或者交易调用,不能从智能合约内部被调用(无法通过ext()
调用,但是可以通过 this.ext()
调用)。public
的函数:可以被任何智能合约或者交易调用。internal
的函数:只能在当前智能合约内部或者派生的智能合约当中访问,不能从智能合约的外部进行访问。private
的函数:只能在被定义的智能合约内部进行访问,无论是外部还是派生的智能合约都无法进行访问。Solidity 当中事件 event
的本质是以太坊虚拟机 EVM日志功能的抽象,
1 | event 事件名称(事件变量类型 事件变量名称); |
下面的示例代码,每次调用 transfer()
函数进行转账的时候,都会触发 Transfer
事件,并且记录对应的变量:
1 | // SPDX-License-Identifier: MIT |
注意:上面代码当中出现的
indexed
关键字,可以将变量保存在以太坊虚拟机 EVM 日志的topics
当中,从而可以方便的在后续进行检索。
以太坊虚拟机 EVM 会使用日志 Log
来存储 Solidity事件,每一条 Log 日志都记录着 topics
主题和data
数据两个部分:
Topics
:用于描述事件,只能容纳 32个字节,且只能保存最多三个 indexed
参数;Data
:用于保存没有被标注为indexed
的参数,可以存储任意大小的数据;Solidity 可以使用 error()
方法定义一个不带参数的异常:
1 | // SPDX-License-Identifier: MIT |
除此之外,也可以使用 error()
方法定义一个携带有参数的异常:
1 | // SPDX-License-Identifier: MIT |
通常情况下,error()
必须搭配回退命令revert
进行使用。
1 | // SPDX-License-Identifier: MIT |
除此之外,一些较早版本的 Solidity 还会使用已经废弃了的require()
方法来处理异常,其缺点在于 Gas费用会伴随异常描述字符串长度的增加而增加。
1 | require(异常检查条件,"异常描述信息"); |
而另外一个 assert()
方法则不能抛出自定义的异常信息,只能直接抛出默认的异常错误:
1 | assert(异常检查条件); |
Solidity 当中的智能合约可以通过 is
关键字来继承其它合约,从而扩展其功能。子合约可以继承父合约当中internal
和 public
的函数、状态变量以及事件。
1 | // SPDX-License-Identifier: MIT |
注意:Solidity只能实现单继承,即一个子合约只能直接继承自一个父合约。
Solidity 支持 import
模块化导入,下面的一语句用于全局导入,可以将 filename
导入路径源文件中的全局符号引入到当前源文件,但是会污染当前Solidity 源文件的命名空间,并不建议使用:
1 | import "filename"; |
下面的导入语句将 filename
当中的全局符号,导入到了一个新的命名空间 symbolName
当中,从而有效避免了命名空间的污染:
1 | import * as symbolName from "filename"; |
上述的语句,可以简化的写为如下的形式:
1 | import "filename" as symbolName; |
如果导入源文件当中的命名符号存在冲突,则可以在导入的时候对其进行重命名:
1 | import { symbol1 as alias, symbol2 } from "filename"; |
OpenZeppelin 是一家成立于2015 年的区块链技术企业,其推出的 contracts
是一款是用于开发安全智能合约的开源 Solidity库,其主要提供了以下三方面的功能:
可以通过下面的 npm
命令快速安装OpenZeppelin 的 contracts
库:
1 | npm install @openzeppelin/contracts |
OpenZeppelin 提供的大多数特性,都需要通过 Solidity的 is
关键字,以继承的方式来进行使用:
1 | // contracts/MyNFT.sol |
除此之外,还可以通过 Solidity 的 overrides
来重写 OpenZeppelin当中提供的功能,例如希望改变 AccessControl
中的revokeRole()
方法:
1 | pragma solidity ^0.8.20; |
有时候会想继承某一部分 OpenZeppelin当中的功能,并非完全的重写它们,此时就需要用使用到 solidity 的super
关键字:
1 | pragma solidity ^0.8.20; |
OpenZeppelin 将发布智能合约的账户称为owner
,其提供了 Ownerable.sol
来管理智能合约当中的所有权。
1 | pragma solidity ^0.8.20; |
注意:示例代码当中的
onlyOwner
关键字是由 Openzeppelin 当中的Ownerable.sol
所提供的。
Ownerable.sol
主要提供了如下两个功能函数:
transferOwnership()
将智能合约的所有权转移给另外一个账户;renounceOwnership()
放弃智能合约的所有权关系;除此之外,OpenZeppelin 还提供了AccessControl.sol
来基于角色进行访问控制(即定义多个角色,并且每个角色对应一组操作权限)。其使用非常简单,对于每个定义的角色都会创建一个角色标识符,用于授权、撤销、检查账户是否拥有该角色。
下面是一个基于 ERC20 Token 使用 AccessControl.sol
的例子,它定义了一个名为 minter
的角色,该角色允许账户创建新的 token
。
1 | pragma solidity ^0.8.20; |
OpenZeppelin 提供的 AccessControl.sol
亮点在于需要细粒度权限控制的场景,这可以通过定义多个角色来实现。通过这样的拆分,可以实现比Ownerable.sol
提供的简单所有权控制,层级要更多的访问控制。请注意,如果需要的话,同一个账户可以拥有多个不同的角色。
注意:限制系统中每个组件能做的事情被称为最小权限原则。
接下来定义一个 burner
角色来扩展上面的 ERC20 token示例,并且通过使用 onlyRole
修饰符来允许账户销毁token
。
1 | pragma solidity ^0.8.20; |
上面的代码当中,使用了内部函数 _setupRole()
来分配角色,除此之外还可以使用以下的工具函数来管理角色:
hasRole()
:判断角色。grantRole()
:授予角色。revokeRole()
:回收角色。除此之外,OpenZeppelin 提供的AccessControl.sol
当中,还包含有一个称为DEFAULT_ADMIN_ROLE
的特殊角色,它是所有角色的默认管理员,拥有该角色的账户可以去管理其它的角色,除非手工调用_setRoleAdmin()
内部函数来指定一个新的管理员。
1 | pragma solidity ^0.8.0; |
除此之外,AccessControl.sol
还提供了如下两个工具函数:
getRoleMember()
:返回某个角色当中账户的地址;getRoleMemberCount()
:返回某个角色当中账户的数量;1 | // 返回某个角色当中账户的数量 |
代币(Token)是指区块链上,各种可以通过智能合约来调用、交易、创建、销毁的虚拟资产,其中ERC721 是以太坊上用于非同质化代币(NFT,Non FungibleToken)的标准,OpenZeppelin 针对 ERC721标准提供了大量的接口方法,下面的代码可以用于构建一个 ERC721代币智能合约:
1 | pragma solidity ^0.8.20; |
在上面的示例代码当中,新的 NFT 可以通过执行如下代码来进行生成:
1 | > gameItem.awardItem(playerAddress, "http://uinio.com/NFT.json") |
并且每个物品的所有者和元数据都可以通过如下的方式进行查询:
1 | > gameItem.ownerOf(5) |
最终,获得的 tokenURI
就是一个如下所示的 JSON格式数据:
1 | { |
OpenZeppelin 在 Finance 目录下提供了PaymentSplitter(只存在于 Contracts库的 4.x
版本)和 VestingWallet(存在于Contracts 库的 4.x
和 5.x
版本)两个财务相关的智能合约:
PaymentSplitter
智能合约:通常用于管理和分配资金,可以允许将资金分割并发送到多个地址,通常基于预定义的分配规则或比例。通常用于众筹、团队资金分配或任何需要按照特定比例分割资金的场景。VestingWallet
智能合约:则是一种特殊的钱包,用于管理资产的逐步解锁或归属。它通常用于确保代币或资金在一定时间段内逐步释放给接收者,而不是立即全部可用。通常用于激励计划、团队代币锁定或者任何需要时间限制的资金释放场景。概括起来,PaymentSplitter
与 VestingWallet
两者的区别主要体现在如下四个方面:
PaymentSplitter
旨在分割和分配资金,而 VestingWallet
旨在逐步解锁和释放资金。PaymentSplitter
更适用于一次性的资金分配场景,而 VestingWallet
更适用于需要长期管理和逐步释放资金的场景。PaymentSplitter
主要关注资金的即时分配,而 VestingWallet
关注资金的时间锁定和逐步解锁。OpenZeppelin 的 PaymentSplitter智能合约库允许将一个以太坊地址收到的付款按照指定的份额(Shares)进行分割,并将这些部分按指定的份额值发送给收款人。这个合约非常适合用于在多个团队成员、投资者或合作伙伴之间分配资金的情况。
PaymentSplitter 提供的方法 | 功能描述 |
---|---|
constructor(payees, shares_) | 构造函数,数组payees (收款人)当中的每个账户,都会获得shares_ (份额)数组中匹配位置的份额值。 |
receive() | 接收 ETH 以太币(会被记录至PaymentReceived 事件)。 |
totalShares() | 获取收款人 payees 持有的全部份额。 |
totalReleased() | 获取已经释放的 ETH 以太币总额。 |
totalReleased(token) | 获取已经释放的 token 代币总额。 |
shares(account) | 获取指定地址账户持有的份额值。 |
released(account) | 获取已释放给指定地址收款人的 ETH以太币数量。 |
released(token, account) | 获取已释放给指定地址收款人的token 代币数量。 |
payee(index) | 获取收款人数组 payees 指定index 索引的收款人的账户地址。 |
releasable(account) | 获取指定账户地址的收款人,当前可以释放的ETH 以太币数量。 |
releasable(token, account) | 获取指定账户地址的收款人,当前可以释放的token 代币数量。 |
release(account) | 根据持有的份额比例和之前的提款历史,向指定账户地址的收款人释放ETH 以太币。 |
release(token, account) | 根据持有的份额比例和之前的提款历史,向指定账户地址的收款人释放token 代币。 |
PaymentSplitter 提供的事件 | 功能描述 |
---|---|
PayeeAdded(account, shares) | 收款人添加事件,需要指定其账户地址account 以及所占份额 shares 。 |
PaymentReceived(from, amount) | 智能合约收款事件,向 from 地址收取 amount 数额 ETH 以太币的事件。 |
PaymentReleased(to, amount) | 受益人提款事件,即向 to 地址支付 amount 数额 ETH 以太币的事件。 |
ERC20PaymentReleased(token, to, amount) | 受益人提款事件,即向 to 地址支付 amount 数额 token 代币的事件。 |
注意:上述表格当中的
token
是一个IERC20 代币智能合约的地址。
1 | // SPDX-License-Identifier: MIT |
OpenZeppelin 的 VestingWallet智能合约库,主要用于实现代币的逐步发放功能。这里的Vesting
是一种归属权兑现机制,用于在一定时间内将代币token
发放给特定的受益人。换而言之,就是在一定时间期限内,代币逐渐可用或者可提取的过程。
VestingWallet 提供的方法 | 功能描述 |
---|---|
constructor(beneficiary, startTimestamp, durationSeconds) | 默认将智能合约的发送方设置为初始所有者,其中beneficiary 为受益人,startTimestamp 为开始时间戳,durationSeconds 为归属权存续时间。 |
receive() | 用于接收 ETH 以太币。 |
start() | 获取开始时间戳。 |
end() | 获取结束时间戳。 |
duration() | 获取归属权存续时间。 |
released() | 已被释放的 ETH 以太币数量。 |
released(address token) | 已被释放的 token 代币数量。 |
releasable() | 可以释放的 ETH 以太币数量。 |
releasable(address token) | 可以释放的 token 代币数量。 |
release() | 释放已归属的 ETH 以太币。 |
release(token) | 释放已归属的 token 代币。 |
vestedAmount(timestamp) | 已归属的 ETH以太币数量,默认实现为一个线性的释放曲线。 |
vestedAmount(token, timestamp) | 已归属的 token 代币数量,默认实现为一个线性的释放曲线。 |
_vestingSchedule(totalAllocation, timestamp) | 归属权公式的虚拟实现,返回值为已经释放的金额。 |
VestingWallet 提供的事件 | 功能描述 |
---|---|
EtherReleased(amount) | 以太币 ETH 被释放事件。 |
ERC20Released(token, amount) | 代币 token 被释放事件。 |
注意:上述表格当中的
token
是一个IERC20 代币智能合约的地址。
OpenZeppelin 的 Contracts 库在其finance
目录下的 VestingWallet.sol
智能合约当中提供了如下源代码:
1 | // SPDX-License-Identifier: MIT |
133MHz
,片上内置有 264KB
容量的SRAM 内存,并且能够外接高达 16MB
容量的片外 Flash 闪存(通过 QSPI总线连接),内部还集成有 DMA 控制器,以及 30 个 GPIO引脚(其中 4 个可用作模拟输入)。除此之外,片上还拥有 2 个UART 控制器、2 个 SPI 控制器、2 个I²C 控制器、16 个 PWM 通道,以及 2个可编程 PIO(Programmable I/O)块,并且支持USB 1.1 主机和设备模式。UINIO-MCU-RP2040是一款基于 RP2040 的开发板,板载 Flash 采用更为小巧的WSON8
封装,添加 SOD123
封装的肖特基势垒二极管防止正负级反接,同时增加用于全局异步复位的RESET 按钮,并且引出了官方 Pico 开发板所没有的GPIO23
和 GPIO24
两个引脚资源。除此之外,由于模数转换引脚内部集成有连接至IOVDD
的反向二极管,所以采用 FET 场效应管DMG1012T 防止 RP2040 未上电时,这些引脚上施加的电压通过ADC3
引脚泄露至 3.3V
电源网络。
树莓派基金会于 2021 年初推出的RP2040 是一款基于台积电 40nm
工艺的低成本、高性能微控制器产品,采用了高达 133MHz
主频的双核心 ARM Cortex-M0+ 内核架构,拥有多达 30个多功能 GPIO 引脚(其中 4个可以用作模拟输入),片上载有 264kB
的静态随机存储器 SRAM。除此之外,通过 QSPI
总线还可以支持高达 16MB
的片外 Flash闪存,下图展示了 RP2040 芯片各个功能引脚的分布:
而接下来的表格,则描述了上图当中 RP2040各个引脚的具体功能:
引脚名称 | 功能描述 |
---|---|
GPIOx | 通用数字输入输出引脚,可以将多个内部外设映射至GPIO。 |
GPIOx/ADCy | 具有模数转换功能的通用数字输入输出引脚,用于采集电压信号。 |
QSPIx | 用于连接 SPI、Dual-SPI、Quad-SPI 接口的Flash 存储芯片,如果未连接,则也可以复用为可编程的 GPIO 引脚。 |
USB_DM 和USB_DP | USB控制器引脚,支持全速的设备(Device)模式,以及全速/低速的主机(Host)模式,必须分别串接27Ω 的终端电阻。 |
XIN 和XOUT | 用于连接 12MHz 频率的晶体振荡器。 |
RUN | 全局异步复位引脚(低电平复位,高电平运行),如果不需要外部复位,则该引脚可以连接至IOVDD 。 |
SWCLK 和SWDIO | SW 串行调试引脚,用于调试和下载固件。 |
TESTEN | 工厂调试模式引脚,需要接入GND 使用。 |
GND | 外部接地引脚。 |
IOVDD | GPIO 的数字电源引脚,额定电压介于1.8V ~ 3.3V 范围。 |
USB_VDD | 内部 USB 全速 PHY 电源引脚,额定电压为3.3V 。 |
ADC_AVDD | 模数转换器电源引脚,额定工作电压为3.3V 。 |
VREG_VIN | RP2040内核稳压器电源输入引脚,额定电压介于1.8V ~ 3.3V 范围。 |
VREG_VOUT | RP2040内核稳压器电源输出引脚,额定电压为1.1V ,最大输出电流为 100mA 。 |
DVDD | 数字核心电源引脚,额定电压为1.1V ,可以连接至上面的 VREG_VOUT 。 |
下面展示了 RP2040微控制器芯片内部的系统结构框图:
264kB
容量 SRAM 分布在 6 个独立的 Bank区块,可以通过专用的 AHB 总线进行访问;2
个 UART、2
个SPI、2
个 I²C总线控制器,以及 16
条 PWM 通道;Host
和 Device
模式的 USB 1.1控制器以及用于物理信号转换的 PHY(PhysicalLayer)接口;UINIO-MCU-RP2040的最小系统主要由电源、Flash存储器、晶振、输入输出四个部分构成,接下来的内容将会分别进行讨论。
UINIO-MCU-RP2040 采用 北京圣邦微电子推出的 SGM2019-3.3YN5G低压差线性稳压芯片,采用 SOT-23-5
封装,能够提供最大300mA
的输出电流(此时压差为400mV
),输入电压范围为2.5V ~ 5.5V
,输出电压为 3.3V
,下图是官方提供的SGM2019-3.3YN5G 的典型应用电路:
圣邦微的 SGM2019-3.3YN5G
相比于微盟电子的ME6211C33M5G
线性稳压芯片,其最大的特点在于提供了一个EN
输入使能引脚,UINIO-MCU-RP2040已经将该引脚连接至杜邦排针,并且与核心板的 GND
相毗邻,可以方便的使用跳线帽禁用电源输入,当然也可以用于逻辑控制核心板的运行与停止。下面的表格,提供了SGM2019-3.3YN5G
全部引脚的功能说明:
引脚编号 | 引脚名称 | 功能描述 |
---|---|---|
1 | IN | 稳压输入引脚2.5V ~ 5.5V ,需要连接 1uF 的接地电容。 |
2 | GND | 接地引脚。 |
3 | EN | 输入使能引脚,低电平时可以将输入电流降低至10nA ,通常将其连接至输入电压引脚 IN 。 |
4 | BP/FB | 参考噪声旁路(仅限固定电压版本)。旁路采用低漏0.01μF 陶瓷电容,降低输出噪声。 |
5 | OUT | 3.3V 稳压输出引脚。 |
注意:树莓派 RP2040需要使用到两种不同的工作电压,其中
3.3V
主要用于输入输出,而1.1V
则是用于数字核心。由于芯片内部已经集成有3.3V
转1.1V
的 LDO 低压差线性稳压器,所以硬件电路当中不需要再考虑1.1V
电压的供电问题,直接把 VREG_VOUT 与DVDD 连接起来即可。
除此之外,电源设计当中另外一个需要关注的方面在于RP2040电源引脚的去耦电容,它们在电路当中可以提供如下两个基本功能:
UINIO-MCU-RP2040 采用官方推荐的容值分别为0.1uF
(有效滤除 10MHz
以下的电源纹波)和2.2uF
(有效滤除 20MHz
以上的高频纹波)的贴片陶瓷电容器(0402封装)作为去耦电容,并且将它们全部放置在靠近 RP2040芯片电源引脚的位置:
除此之外,由于 RP2040 需要通过SGM2019-3.3YN5G
线性稳压器,将输入到 VREG_IN
引脚的 3.3V
电压转换为 VREG_OUT
输出的1.1V
电压(最大输出电流为100mA
),所以这里需要将 VREG_OUT
连接至数字核心的 1.1V
电源输入引脚DVDD
,此时依然分别需要添加相应的去耦电容。
RP2040 微控制器运行的固件程序代码都被保存外部的Flash 存储器当中,UINIO-MCU-RP2040 核心板采用 台湾华邦电子推出的 W25Q128JVP
型 Flash 存储器,封装形式为更加小巧的WSON8
,选型容量为 128Mbit
(即16MB
),也就是 RP2040微控制器可以支持的最大存储容量:
QSPI_SS
片选引脚连接的 1.5kΩ
电阻为连接到3.3V
电源的上拉电阻,虽然QSPI_SS
引脚自动默认为上拉,但是在 RP2040上电的某个瞬间,无法确保其始终的处于高电平状态,所以这里增加了一枚上拉电阻器来确保该片选引脚始终处于上拉状态。除此之外,在靠近Flash 存储芯片的电源引脚位置,同样也添加了一枚 0.1uF
的去耦电容。
注意: 由于连接 Flash 存储器的 QSPI总线频率较高,需要采用尽可能短的 PCB走线距离,从而确保信号的完整性,并减少周边电路带来的串扰。
相较于官方的 Raspberry Pi Pico开发板只拥有一枚【BOOT】按键,为了方便日常开发使用,UINIO-MCU-RP2040核心板同时提供了【BOOT】和【REST】两枚按键,其原理图与功能说明分别如下所示:
1kΩ
电阻连接至Flash 存储芯片的 SPI 片选引脚,用于失能 Flash 片选信号,从而选择强制从USB 启动。此时 RP2040 会呈现为 USB大容量存储设备,可以用于直接复制下载固件。RUN
引脚通过10kΩ
上拉电阻钳位在高电平,从而保持核心板处于正常运行状态。而该按键可以将全局异步复位引脚RUN
下拉为低电平状态,从而配合【BOOT】按键进入下载引导模式。注意:按键并联的
0.1uF
电容用于滤除被按下时产生的抖动信号,实际应用时可以选择不进行贴装。
虽然 RP2040拥有内部的时钟源,但是其工作状态容易受到电源电压和温度的影响,因此官方建议使用一个更加稳定和精确的外部时钟源。RP2040微控制器的外部时钟源可以通过如下两种方式进行提供:
3.3V
方波信号的时钟源连接至 RP2040 的XIN
引脚;XIN
和 XOUT
引脚之间加入12MHz
晶体振荡器(首选);UINIO-MCU-RP2040选用的是外置石英晶振方案,该款石英晶振的负载电容为11pF
。晶振的负载电容是指与该晶振并联的全部有效电容的总和,可以将其视为晶振电路上串联的一枚电容器,其主要作用是稳定晶振的谐振频率
和输出幅度
,根据两个电容器并联之后总电容的计算公式:
\[C_{负载电容} = \frac{C_{对地电容1} \times C_{对地电容2}}{C_{对地电容1} +C_{对地电容2}} + C_{PCB 杂散电容}\]
由于 \(C_{对地电容1}\) 与 \(C_{对地电容2}\) 两枚并联电容的容值相等,而\(C_{PCB 杂散电容}\) 的容值通常选取在3pF ~ 5pF
范围,从而可以得到晶振两枚并联的 \(C_{对地电容}\) 的容值计算公式:
\[C_{对地电容} = (C_{负载电容} - C_{PCB 杂散电容}) \times 2\]
这里选择 \(C_{PCB 杂散电容}\)为典型值 5pF
,而负载电容 \(C_{负载电容}\) 为11pF
,从而就可以计算得到两枚接地电容的容值分别为:
\[C_{对地电容} = (11pF - 5pF) \times 2 = 12pF\]
RP2040 微控制器提供有 USB_DM
和USB_DP
两个引脚(无需额外的上拉和下拉),用于全速(FS,FullSpeed)或者低速(LS,Low Speed)的 USB 通信,即可以作为USB Host(主机),也可以作为 USB Device(设备)。虽然 RP2040 的全速 USB通信速率被限制为 12Mbps
兆位/秒,但是为了满足 USB的阻抗规范,依然需要分别串联 27Ω
的终端电阻,并且尽量靠近芯片放置。同时走线需要尽可能的遵循90Ω
的 USB差分阻抗规范,并且走线下方尽量保持一个完整的接地平面。
自从 USB Type-C 标准开始,USB 增加了 CC1
和CC2
两个配置通道(Configuration Channel),当其串联上5.1kΩ
下拉电阻的时候,表明UINIO-MCU-RP2040 当前已经被配置为上行接口(UFP,Upstream Facing Port)用电端,从而提升USB Type-C 与传统 USB 接口的电源兼容性。
128×64
分辨率 SSD1315 驱动的0.96 英寸 OLED 显示屏,160×80
分辨率ST7735 驱动的 0.96 英寸 LCD显示屏,240×240
分辨率 ST7789 驱动的 1.3英寸 LCD 显示屏。以及采用相同驱动芯片,但是分辨率分别为240×320
与 240×280
的 2.4 英寸以及 1.69 英寸LCD 显示屏。所有屏幕全部板载有 0.5mm
间距的FPC 柔性排线连接器,同时还引出 2.54mm
间距的直插排针,便于通过杜邦线快速搭建实验电路。之前由我设计制作并且开源出来的 UINIO-MCU-ESP32C3和 UINIO-MCU-ESP32S3两款核心板,分别基于乐鑫科技的 ESP32-C3 (RISC-V) 与ESP32-S3 (Xtensa) 微控制器(更多玩法可以参考之前撰写的《基于 UINIO-MCU-ESP32的 Arduino 进阶教程》一文)。而本篇文章就会采用这两款核心板,以及乐鑫官方的Arduino-ESP32 板级支持包,结合 U8G2 和 TFT_eSPI两款开源显示库,帮助大家快速上手 UINIO-Monitor 系列里的5 款显示屏。
UINIO-Monitor 系列显示屏幕当中的 0.96 英寸OLED(有机发光二极管,Organic Light-Emitting Diode)显示屏,分辨率为128 × 64
像素,使用 I²C总线进行通信,驱动集成电路采用的是香港晶门半导体(SolomonSystech)的 SSD1315(可以同时兼容SSD1306)。
注意:如果焊接上丝印为
0x78
的电阻R20,就会把 I²C 从设备的地址配置为0x78
。相应的,如果焊接上0x7A
丝印的电阻R19,则表示从设备地址为0x7A
。当使用Arduino-ESP32 和 U8G2库进行通信时,需要焊接上 R20,而 R19位置留空。
该屏幕模组采用了日本特瑞仕(TOREX)的XC6206P332MR 低压差线性稳压芯片,可以同时兼容3.3V
与 5V
两种工作电压。屏幕在全亮状态下的工作电流约为25mA
,而全部熄灭黑屏状态下的待机电流约为1.5mA
。正是由于该屏幕工作电流较小,为了防止正负极反接导致稳压芯片损坏,所以串接了一枚型号为1N5819 的肖特基二极管(额定正向电流为1A
)作为防反接设计,具体电路设计可以参考如下的原理图(鼠标双击可以放大):
开始上手实践之前,需要把 UINIO-Monitor 上 0.96 英寸OLED 显示屏的SCK
、SDA
、GND
、VCC
引脚,分别与 UINIO-MCU-ESP32S3 核心板的GPIO16
、GPIO17
、5V
、GND
引脚进行连接,后续 U8G2库相关的示例代码都将会沿用这个连接关系:
注意:为了文章撰写与阅读的方便直观,UINIO-Monitor当中的 0.96 英寸 OLED 显示屏,在后续 U8G2库相关章节的内容里全部直接简称为 UINIO-Monitor。
U8G2是一款运行在嵌入式设备上的 Arduino 单色显示库,可以通过 ArduinoIDE 的【库管理器】直接进行安装。U8G2 库包含有文字
、位图
、线/框/圆
的绘制方法,并且可以支持多种字体,显示内容时需要使用到微控制器的 RAM作为缓冲区。除此之外,U8G2 库还内嵌有一个小巧的U8x8库,该库只能输出文本内容,并且只能显示固定像素大小的字体,不过显示内容时无需再使用微控制器的RAM 存储器作为缓冲区。关于两个库的更多介绍,可以参考 《U8g2Reference Manual》 和 《U8x8Reference Manual》 两份官方文档。
使用 U8G2库的第一步是要根据当前使用的屏幕规格与总线通信方式,选择对应的u8g2()
构造函数,从而实例化出相应的 u8g2
对象。本文以 UINIO-Monitor 当中 0.96 英寸 OLED显示屏所需要使用到的 U8G2_SSD1306_128X64_NONAME_F_HW_I2C
硬件 I²C 类型和 U8G2_SSD1306_128X64_NONAME_F_SW_I2C
软件I²C 类型为例进行讨论:
1 | /* 采用 SSD1306 驱动芯片,分辨率为 128*X*64,通信方式为软件 I²C 总线 */ |
注意:硬件 I²C 相比于软件 I²C总线的显示刷新频率更高,渲染动画效果的时候更加顺滑。
事实上,U8G2 库的 Arduino C++构造函数 u8g2()
,其返回值类型都遵循着统一的命名规则:
前缀 | 屏幕驱动芯片型号 | 分辨率 | 生产品牌 | 缓冲区大小 | 通信方式 |
---|---|---|---|---|---|
U8G2 | SSD1306 | 128X64 | NONAME | F | HW_I2C |
U8G2 | SSD1306 | 128X64 | NONAME | F | SW_I2C |
接下来的三个表格,分别展示了上述表格当中缓冲区大小、通信方式、显示旋转方向的具体参数信息:
缓冲区大小 | 功能描述 |
---|---|
1 | 占用 1 页的微控制器 RAM 作为缓冲区。 |
2 | 占用 2 页的微控制器 RAM作为缓冲区(可以获得更快的显示刷新速度)。 |
F | 在微控制器 RAM当中保存完整的显示帧(推荐在 RAM 存储空间足够大的场景下使用)。 |
显示旋转方向 | 功能描述 |
---|---|
U8G2_R0 | 不旋转,横向显示。 |
U8G2_R1 | 顺时针 90° 度旋转。 |
U8G2_R2 | 顺时针 180° 度旋转。 |
U8G2_R3 | 顺时针 270° 度旋转。 |
U8G2_MIRROR | 不旋转,横向显示,但是内容会被镜像。 |
通信方式 | 功能描述 |
---|---|
4W_SW_SPI | 四线制(Clock\Data\CS\DC )的软件模拟SPI。 |
4W_HW_SPI | 四线制(Clock\Data\CS\DC )的硬件SPI。 |
2ND_4W_HW_SPI | 第 2 个四线制的硬件 SPI。 |
3W_SW_SPI | 三线制(Clock\Data\CS )的软件模拟SPI。 |
SW_I2C | 软件模拟的 I²C 总线通信。 |
HW_I2C | 硬件 I²C 总线通信。 |
2ND_HW_I2C | 第 2 个硬件 I²C 通信总线。 |
6800 | 采用 6800 协议的 8位并行接口。 |
8080 | 采用 8080 协议的 8位并行接口。 |
注意:如果当前没有连接重置输入引脚,那么就可以将构造函数中的
reset
参数,直接填写为U8X8_PIN_NONE
。
采用 u8g2()
构造函数创建 u8g2
类的时候,需要传入一系列的参数,下面表格就展示了这些参数的具体信息:
引脚参数 | 数据手册名称 | 功能描述 |
---|---|---|
clock | SCL / SCLK ... | SPI 或者 I²C 总线的时钟线。 |
data | SDA / MOSI / SDIN ... | SPI 或者 I²C 总线的数据线。 |
d0 ... d7 | D0 ... D7 | 并行接口的数据线。 |
cs | CS | 片选信号线。 |
dc | D/C / A0 / RS, ... | 数据/命令选择线。 |
enable | 8080:WR / 6800:E | 8080 接口的 Write 写入线,6800 接口的 Enable 使能线。 |
reset | - | 重置信号线。 |
U8G2 库默认使用 8 位显示模式(即256 色),如果需要使用 16 位显示模式,则必须在u8g2.h
头文件当中添加如下注释:
1 |
注意:16 位显示模式下,保存 U8G2像素坐标的数据类型也会从 8 位变换为 16 位。
接下来,就会通过 Arduino C++ 和U8G2 库,结合 UINIO-MCU-ESP32S3 和UINIO-Monitor 实现一个显示Hello UinIO.com!
字符串的示例:
1 |
|
U8G2 所包含的 U8x8库无需占用微控制器的 RAM存储空间,可以用于直接显示一些文本信息。但是需要注意 u8x8()
构造函数的参数构成,与 u8g2()
构造函数并不相同:
1 | U8X8_SSD1306_128X64_NONAME_SW_I2C u8x8(/* clock=*/16, /* data=*/17, /* reset=*/U8X8_PIN_NONE); |
U8x8 库的 Arduino C++ 构造函数u8x8()
,其返回值类型都遵循着如下的命名规则:
前缀 | 屏幕驱动芯片型号 | 分辨率 | 生产品牌 | 通信方式 |
---|---|---|---|---|
U8G2 | SSD1306 | 128X64 | NONAME | HW_I2C |
... | ... ... | ... ... | ... ... | SW_I2C |
观察可以发现,除了没有缓冲区大小设置相关的参数之外,u8x8()
构造函数的返回类型命名方式,与 U8G2 库的u8g2()
构造函数基本保持一致。接下来同样可以通过Arduino C++ 和 U8x8 库,基于UINIO-MCU-ESP32S3 和 UINIO-Monitor实现一个 Hello UinIO.com!
字符串显示的示例:
1 |
|
u8g2
类的 begin()
函数用于简化 Arduino环境下的显示设置步骤,该函数在底层会依次调用initDisplay()
、clearDisplay()
、setPowerSave()
三个函数:
1 | bool begin(void) |
begin()
函数还可以用于绑定按键检测事件(最高可以绑定 6个按键),如果没有连接相应的按键,则对应的参数可以设置为U8X8_PIN_NONE
:
1 | bool begin( |
除了 begin()
函数之外,u8g2
类还提供有如下的屏幕显示初始化函数:
API 方法 | 功能描述 |
---|---|
void setBusClock(uint32_t clock_speed); | 设置总线通信的时钟频率,I²C 总线可以尝试200000 或者 400000 ,SPI 总线可以尝试1000000 或者 8000000 。 |
void setContrast(uint8_t value) | 设置显示对比度,取值范围从0 ~ 255 。 |
U8G2 库使用的是点阵字体,使用时需要通过setFont()
函数配置当前所要显示的字体,其中字体名称u8g2_font_字体类型与字符集
的最后两个字符定义了字体的类型和字符集:
字体名称 | 助记词 | 字体类型 |
---|---|---|
u8g2_xxx_tx | Transparent | 具有可变宽度的透明字体。 |
u8g2_xxx_mx | Monospace | 等宽字体。 |
u8g2_xxx_hx | Height | 具有可变宽度和共同高度的字体。 |
u8g2_xxx_8x | 8x8 | 位于 8x8 盒子当中的等宽字体。 |
字体名称 | 助记词 | 字符集 |
---|---|---|
u8g2_xxx_xe | Extended | 包含 Unicode 编码 32 ~ 701 的字符。 |
u8g2_xxx_xf | Full | 包含 Unicode 编码 32 ~ 255 的字符。 |
u8g2_xxx_xr | Restricted | 包含 Unicode 编码 32 ~ 127 的字符。 |
u8g2_xxx_xu | Uppercase | 只包含有数字和大写字母。 |
u8g2_xxx_xn | Numbers | 包含日期和时间表达的数值与额外字符。 |
u8g2_xxx_x_something | - | 特殊字体。 |
注意:U8G2库不支持直接设置字体的大小,而是通过选用不同尺寸的字体来完成字体大小的控制。
如果需要通过 U8G2 库显示中文,则必须在 begin()
调用之后,print()
调用之前执行下面的方法,从而使能 UTF8编码字符的显示输出,具体说明请参见下表所示:
API 方法 | 功能描述 |
---|---|
void enableUTF8Print(void) | 使能 UTF8 显示支持,从而可以通过u8g2.print() 打印中文; |
void disableUTF8Print(void) | 失能 UTF8 显示支持,默认状态。 |
目前 U8G2 库已经包含了中文的文泉驿字体,可以同时支持12
、13
、14
、15
、16
像素大小的字体:
u8g2_font_wqy(12~16)_t_chinese1
:只包含 U8G2官方提供的小字符集。u8g2_font_wqy(12~16)_t_chinese2
:只包含 U8G2官方提供的小字符集。u8g2_font_wqy(12~16)_t_chinese3
:只包含 U8G2官方提供的小字符集。u8g2_font_wqy(12~16)_t_gb2312
:包含有完整的 GB2312中文简体字符集。u8g2_font_wqy(12~16)_t_gb2312a
:仅包含 GB2312 的01
、02
和 16 ~ 55
以及部分08
区编码,没有包含全角标点符号。u8g2_font_wqy(12~16)_t_gb2312b
:仅包含 GB2312 的1 ~ 55
区编码,其中 10 ~ 15
属于空区,相比于gb2312a
会多出一些额外的符号。注意:使用上述字体时,只需要将
(12~16)
部分替换为当前所需的像素大小即可。
除此之外,U8G2 库还可以支持 GNU 的 Unifont点阵黑中文字体,不过这些字体的美观程度明显逊色于文泉驿字体:
u8g2_font_unifont_t_chinese1
:包含 U8G2官方提供的小字符集。u8g2_font_unifont_t_chinese2
:包含 U8G2官方提供的小字符集。u8g2_font_unifont_t_chinese3
:包含 U8G2官方提供的小字符集。下面的示例代码,就将会分别使用 u8g2_font_wqy16_t_gb2312
和 u8g2_font_wqy13_t_gb2312
两种字体,在UINIO-Monitor 上面显示 "Hello UinIO.com!"
和 "你好,电子技术博客!"
两组字符串内容:
1 |
|
除了上面介绍的方法之外,U8G2库还额外提供有如下几个字体显示相关的工具函数:
API 方法 | 功能描述 |
---|---|
u8g2_uint_t getMaxCharHeight(void) | 返回指定点阵字体里,最大的字体高度。 |
u8g2_uint_t getMaxCharWidth(void) | 返回指定点阵字体里,最大的字体宽度。 |
void setDrawColor(uint8_t color) | 参数 color 为 0 表示字体不亮背景亮,为 1 表示背景不亮字体亮(默认)。 |
显示坐标系统是 U8G2库当中比较重要的概念,运用显示相关的函数时,需要特别关注其显示起始的坐标。当使用u8g2
类的 print()
函数显示内容时,需要先运用setCursor()
函数设置显示内容在 x
轴与y
轴的起始像素坐标位置:
API 方法 | 功能描述 |
---|---|
void setCursor(u8g2_uint_t x, u8g2_uint_t y) | 设置显示内容的起始像素坐标位置。 |
void home(void) | 将光标放置到屏幕的左上角。 |
void clear(void) | 清除屏幕和缓冲区上的内容,并且将光标放置到左上角。 |
U8G2 库将屏幕的左上角作为坐标原点(0, 0)
,显示内容将会沿着起始坐标位置分别向上和向右进行输出,例如下图左侧的代码分别将显示的起始坐标设置为x = 0
与y = 15
,最终渲染显示出来的结果如下面右图所示:
U8G2 库提供有 clearBuffer()
和sendBuffer()
这组屏幕显示刷新的方法(刷新速度比较快,但是RAM 空间占用较大):
API 方法 | 功能描述 |
---|---|
void clearBuffer(void) | 清除微控制器 RAM帧缓冲区当中的所有内容。 |
void sendBuffer(void) | 将微控制器 RAM帧缓冲区当中的内容发送至屏幕进行显示。 |
显示缓冲区操作相关的代码,都必须放置到 clearBuffer()
和sendBuffer()
函数之间的区域:
1 | void loop(void) { |
除此之外,U8G2 库还提供了 firstPage()
与 nextPage()
来刷新屏幕显示内容(消耗的 RAM空间相对较小):
API 方法 | 功能描述 |
---|---|
void firstPage(void) | 该命令是内容渲染循环的一部分,需要与nextPage() 配合使用。 |
uint8_t nextPage(void) | 该命令是内容渲染循环的一部分,需要与firstPage() 配合使用。 |
使用时即可以采用 do...while()
循环的方式来组合调用firstPage()
与 nextPage()
函数:
1 | u8g2.firstPage(); |
也可以把 firstPage()
放置到 Arduino 草图代码的setup()
函数当中,而 nextPage()
函数放置到loop()
循环的内部:
1 | void setup() { |
除了之前示例代码当中使用过的 print()
和drawStr()
之外,U8G2库还提供有如下一系列可以用于显示内容输出的方法:
API 方法 | 功能描述 |
---|---|
u8g2_uint_t drawStr(u8g2_uint_t x, u8g2_uint_t y, const char *s) | 在指定的坐标位置绘制字符串(不能绘制编码大于或等于256 的字符),使用前必须指定字体。 |
u8g2_uint_t drawStrX2(u8g2_uint_t x, u8g2_uint_t y, const char *s) | 功能同上,只是绘制的字体大小加倍。 |
u8g2_uint_t drawUTF8(u8g2_uint_t x, u8g2_uint_t y, const char *s) | 绘制一个编码为 UTF-8的字符串(中文),该函数能够绘制编码值大于 127 的字符。 |
u8g2_uint_t drawUTF8X2(u8g2_uint_t x, u8g2_uint_t y, const char *s) | 功能同上,只是绘制的字体大小加倍。 |
u8g2_uint_t drawGlyph(u8g2_uint_t x, u8g2_uint_t y, uint16_t encoding) | 在指定的坐标位置绘制图像字符,需要配合特殊的图像字体一起使用。 |
u8g2_uint_t drawGlyphX2(u8g2_uint_t x, u8g2_uint_t y, uint16_t encoding) | 功能同上,只是绘制的字体大小加倍。 |
void print(...) | 向当前的光标位置(通过setCursor() 设置)写入指定字体(通过 setFont() 设置)的文本(需要调用 enableUTF8Print() 使能 UTF-8编码)。 |
接下来的示例代码,就会分别采用上面表格当中介绍的各种工具函数,测试输出各种显示内容:
1 |
|
XBM(X-Bitmap)是一种通用的图像文件格式,可以通过一个16 进制数组来表示二进制图像。U8G2 库提供的drawXBM()
函数,可以直接用来绘制单色位图(图片在使用之前需要进行单值化处理和取模):
API 方法 | 功能描述 |
---|---|
void drawXBM(u8g2_uint_t x, u8g2_uint_t y, u8g2_uint_t w, u8g2_uint_t h, const uint8_t *bitmap) | 绘制 XBM 格式的位图,参数 x 和 y 表示位图的左上角,而 w 与 h 表示位图的宽高,参数 bitmap 表示取模之后得到的单色位图数组。 |
注意:通常会将
bitmap
数组变量定义为PROGMEM
类型,表示将其存储在 Flash存储器当中,便于保存一些较大的位图数据,并且节省微控制器 RAM的存储空间。
drawXBM()
中的单色位图数组参数bitmap
,可以通过取模工具软件 PCtoLCD2002获取,具体操作步骤如下面列表所示:
128*64
分辨率。.bmp
单色位图格式。u8g2
类的drawXBM()
函数显示位图。注意:可以采用更为方便的在线工具 image-to-bitmap-array进行取模操作。
首先使用 Windows操作系统自带的画图工具打开目标图片,然后点击顶部工具栏的【重新调整大小】,在弹出的对话框中选择【像素】,再将水平和垂直高度分别设置为64
个像素:
完成位图尺寸的调整之后,鼠标依次点击 Windows画图工具顶部菜单栏的【文件 → 另存为 → BMP 图片】:
在接下来弹出的【保存为】对话框当中,选择保存类型为【单色位图】的.bmp
文件:
接着打开 PCtoLCD2002取模软件,点击顶部工具栏上的【字模生成和液晶面板选项】按钮,在弹出的【字模选项】对话框当中进行如下设置:
最后,鼠标再次点击顶部工具栏上的【打开一个 BMP图像】按钮,将刚才得到的 .bmp
单色位图文件导入,再点击【生成字模】按钮,就会在界面的底部区域得到U8G2 库绘图所需的 XBM 数组:
把这里得到的位图数组赋值给下面示例代码的 Hank
变量,然后调用 drawXBM()
函数就可以进行位图的显示:
1 |
|
将上述代码下载到 UINIO-MCU-ESP32S3核心板执行之后,显示到 UINIO-Monitor 的 OLED屏幕内容如下面所示:
除了支持把位图转换为 XBM 数组之外,PCtoLCD2002还能够把字符转换为 XBM 数组。首先在打开 PCtoLCD2002取模软件之后,选择顶部菜单栏上的【模式 → 字符模式】:
接下来,依然需要点击顶部工具栏上的【字模生成和液晶面板选项】按钮,在弹出的【字模选项】对话框当中进行如下设置:
然后,选择字体为 楷体
,每一个字的宽度与高度都设置为64
个像素,并且在中间的输入框填写汉字成都
,点击【生成字模】按钮:
最后,把上述步骤得到的两个 XBM 数组,分别赋予如下示例代码当中的Chengdu
和 Du
两个变量,再分别调用drawXBM()
函数就可以完成显示:
1 |
|
这里同样将上述代码下载到 UINIO-MCU-ESP32S3核心板运行,此时 UINIO-Monitor 的 OLED屏幕显示结果如下面所示:
U8G2 库提供了 drawBox()
和drawFrame()
两个函数用于矩形的绘制:
矩形绘制 API | 功能描述 |
---|---|
void drawBox(u8g2_uint_t x, u8g2_uint_t y, u8g2_uint_t w, u8g2_uint_t h) | 绘制一个实心的矩形,参数x 和 y 表示矩形左上角的起始位置,而 w 和h 分别表示其宽度与高度。 |
void drawFrame(u8g2_uint_t x, u8g2_uint_t y, u8g2_uint_t w, u8g2_uint_t h) | 绘制一个空心的矩形,参数x 和 y 表示矩形左上角的起始位置,而 w 和h 分别表示其宽度与高度。 |
下面的示例代码会在 UINIO-Monitor屏幕的左右两侧,分别绘制一个实心矩形和一个空心矩形:
1 |
|
U8G2 库提供了 drawCircle()
和drawDisc()
两个函数用于圆形的绘制:
圆形绘制 API | 功能描述 |
---|---|
void drawCircle(u8g2_uint_t x0, u8g2_uint_t y0, u8g2_uint_t rad, uint8_t opt = U8G2_DRAW_ALL) | 以 (x0, y0) 位置为圆心,绘制一个半径为 rad 的空心圆,参数 opt 用于指定只绘制圆形的哪些部分。 |
void drawDisc(u8g2_uint_t x0, u8g2_uint_t y0, u8g2_uint_t rad, uint8_t opt = U8G2_DRAW_ALL) | 以 (x0, y0) 位置为圆心,绘制一个半径为 rad 的实心圆,参数 opt 用于指定只绘制圆形的哪些部分。 |
下面的示例代码会在 UINIO-Monitor屏幕的左右两侧,分别绘制一个实心圆形和一个空心圆形:
1 |
|
U8G2 库提供了 drawEllipse()
和drawFilledEllipse()
两个函数用于椭圆形的绘制:
椭圆形绘制 API | 功能描述 |
---|---|
void drawEllipse(u8g2_uint_t x0, u8g2_uint_t y0, u8g2_uint_t rx, u8g2_uint_t ry, uint8_t opt) | 以 (x0, y0) 作为圆心,位置绘制水平半径为 rx ,垂直半径为 ry 的空心椭圆(8 位显示模式下,两者取值必须小于512)。 |
void drawFilledEllipse(u8g2_uint_t x0, u8g2_uint_t y0, u8g2_uint_t rx, u8g2_uint_t ry, uint8_t opt) | 以 (x0, y0) 作为圆心,位置绘制水平半径为 rx ,垂直半径为 ry 的实心椭圆(8 位显示模式下,两者取值必须小于512)。 |
下面的示例代码会在 UINIO-Monitor屏幕的左右两侧,分别绘制一个实心椭圆形和一个空心椭圆形:
1 |
|
U8G2 库提供了 drawHLine()
和drawVLine()
以及 drawLine()
三个函数来绘制直线:
直线绘制 API | 功能描述 |
---|---|
void drawHLine(u8g2_uint_t x, u8g2_uint_t y, u8g2_uint_t w) | 基于 (x, y) 位置从左至右绘制一条长度为 w 像素的水平直线。 |
void drawVLine(u8g2_uint_t x, u8g2_uint_t y, u8g2_uint_t h) | 基于 (x, y) 位置从下至上绘制一条长度为 w 像素的垂直直线。 |
void drawLine(u8g2_uint_t x0, u8g2_uint_t y0, u8g2_uint_t x1, u8g2_uint_t y1) | 基于两个像素点的位置绘制一条直线,参数(x0, y0) 是第 1 个点的坐标,而 (x1, y1) 则是第2 个点的坐标。 |
下面的示例代码会在 UINIO-Monitor屏幕上面,绘制呈现米字形交错的 1 条水平直线和 1条垂直直线,以及 2 条斜线(类似于英国国旗的图案):
1 |
|
U8G2 库提供了 drawPixel()
函数来绘制一个像素点:
像素点绘制 API | 功能描述 |
---|---|
void drawPixel(u8g2_uint_t x, u8g2_uint_t y) | 在 (x, y) 位置绘制一个像素点。 |
下面的示例代码会在 UINIO-Monitor 屏幕当中,每间隔 8个像素绘制一个点,最终形成一条水平的虚线效果:
1 |
|
U8G2 库提供了 drawRBox()
和drawRFrame()
两个函数用于圆角矩形的绘制:
直线绘制 API | 功能描述 |
---|---|
void drawRBox(u8g2_uint_t x, u8g2_uint_t y, u8g2_uint_t w, u8g2_uint_t h, u8g2_uint_t r) | 以 (x, y) 位置作为左上角,绘制一个宽高度分别为 w 和 h 的圆角实心矩形,圆角的半径为 r 。 |
void drawRFrame(u8g2_uint_t x, u8g2_uint_t y, u8g2_uint_t w, u8g2_uint_t h, u8g2_uint_t r) | 以 (x, y) 位置作为左上角,绘制一个宽高度分别为 w 和 h 的圆角空心矩形,圆角的半径为 r 。 |
下面的示例代码会在 UINIO-Monitor屏幕的左右两侧,分别绘制一个实心和一个空心的圆角矩形:
1 |
|
U8G2 库提供了 drawTriangle()
函数用于绘制实心的三角形:
直线绘制 API | 功能描述 |
---|---|
void drawTriangle(int16_t x0, int16_t y0, int16_t x1, int16_t y1, int16_t x2, int16_t y2) | 分别以(x0, y0) 、(x1, y1) 、(x2, y2) 作为顶点绘制一个实心的三角形。 |
下面的示例代码,分别以屏幕顶部中间点 (64, 0)
、屏幕左下角(0, 64)
、屏幕右下角 (128, 64)
作为顶点,绘制出了一个实心的三角形:
1 |
|
MUI 是一款基于 U8G2库的单色图形用户界面库,提供了诸如事件处理
、用户界面绘图
、丰富的预定义用户元素
、静态菜单定义
等特性。详细信息可以参考 U8G2 库作者提供的 《MUI手册》和 《MUI 参考》两份文档。
UINIO-Monitor 里的 2.4英寸显示屏幕,采用了 320 × 240
分辨率的薄膜晶体管(TFT,Thin FilmTransistor)屏幕材质,总线通信方式为SPI,驱动芯片型号是台湾矽创电子(Sitronix)的ST7789,属于本系列当中显示尺寸最大的屏幕:
UINIO-Monitor 里的 1.3英寸显示屏幕,采用了 240 × 240
分辨率的薄膜晶体管(TFT,Thin FilmTransistor)屏幕材质,总线通信方式为SPI,驱动芯片型号是台湾矽创电子(Sitronix)的ST7789:
UINIO-Monitor 里的 1.69英寸圆角显示屏幕,采用了 280 × 240
分辨率的薄膜晶体管(TFT,Thin FilmTransistor)屏幕材质,总线通信方式为SPI,驱动芯片型号是台湾矽创电子(Sitronix)的ST7789:
UINIO-Monitor 里的 0.96英寸显示屏幕,采用了 160 × 80
分辨率的薄膜晶体管(TFT,Thin FilmTransistor)屏幕材质,总线通信方式为SPI,驱动芯片型号是台湾矽创电子(Sitronix)的ST7735:
由于 UINIO-Monitor 系列的 TFT屏幕都采用了台湾矽创电子(Sitronix)的主控方案,因而原理图设计方面基本上大同小异,不过建议线性稳压芯片采用带反接保护的德州仪器LP2992IM5-3.3,虽然价格相对于国产微盟的ME6211C33M5G 更贵,不过一分钱一分货,总比烧坏了成本更高的 TFT屏幕要强:
同样在开始上手实践之前,需要把 UINIO-Monitor 当中TFT 显示屏的BLK
、CS
、D/C
、RST
、SCL
、SDA
、GND
、VCC
引脚,分别与 UINIO-MCU-ESP32S3 核心板的3V3
、GPIO15
、GPIO16
、GPIO17
、GPIO18
、GPIO19
、GND
、5V
引脚进行连接,后续 TFT_eSPI库相关的示例代码都将会沿用这个连接关系,下面的连接示意图以280 × 240
分辨率的 1.69英寸圆角显示屏幕为例:
TFT_eSPI是一款可以运行在 32 位微控制器上的 TFT屏幕图形与字体显示库,本文撰写时的最新版本为 v2.5.0
,相关的API 函数可以参考 《TFT_eSPI库用户手册》,该库对于如下一系列微控制器进行了专门的性能优化:
RP2040
微控制器。ESP8266
、ESP32
、ESP32-S2
、ESP32-C3
、ESP32-S3
微控制器。STM32F1xx
、STM32F2xx
、STM32F4xx
、STM32F767
微控制器(推荐采用 RAM 空间较大的型号)。上述的微控制器在 TFT_eSPI库当中,可以支持如下表格当中的接口类型:
微控制器 | 4 线制 SPI | 8 位并行总线 | 16 位并行总线 | DMA 支持 |
---|---|---|---|---|
ESP32 C3 | 是 | 否 | 否 | 否 |
ESP32 S3 | 是 | 是 | 否 | 是 (仅 SPI) |
ESP32 S2 | 是 | 否 | 否 | 否 |
ESP32 | 是 | 是 | 否 | 是 (仅 SPI) |
RP2040 | 是 | 是 | 是 | 是 (全部) |
ESP8266 | 是 | 否 | 否 | 否 |
STM32Fxxx | 是 | 是 | 否 | 是 (仅 SPI) |
其它 | 是 | 否 | 否 | 否 |
TFT_eSPI 库能够支持如下一系列 TFT液晶显示屏驱动芯片(官方推荐使用内置有 ILI9341
和ST7796
两款驱动芯片的 SPI 屏幕):
型号 | 型号 | 型号 | 型号 | 型号 |
---|---|---|---|---|
ILI9163 | ILI9225 | ILI9341 | ILI9342 | ILI9481 |
ILI9486 | ILI9488 | HX8357B | HX8357C | HX8357D |
GC9A01 | R61581 | RM68120 | RM68140 | S6D02A1 |
SSD1351 | SSD1963 | ST7735 | ST7789 | ST7796 |
通过 Arduino IDE 的【库管理器】安装完成TFT_eSPI 库之后,还需要对D:\Workspace\Workspace_Arduino\libraries\TFT_eSPI
路径下面的 User_Setup.h
头文件进行相应的编辑:
1 |
|
如果 UINIO-Monitor屏幕显示出现异常,可以尝试通过调整如下的选项进行修复:
1 | /* 只针对 ST7735、ST7789、ILI9341 有效,如果显示屏上红色与蓝色发生互换,那么可以重新调整其颜色顺序(只能启用一个选项)*/ |
Arduino IDE 的【库管理器】可以直接安装TFT_eSPI 库,安装完成之后就可以在 Arduino草图代码当中包含 #include <TFT_eSPI.h>
头文件,下面代码展示了 TFT_eSPI 库的基本使用方式:
1 |
|
TFT_eSPI 库所采用的颜色模式为RGB565,即每一个像素占据着 2 Byte
个字节的数据量(即 2 个字节的无符号整型数据),其中红色占据5 bit
位,绿色占据 6 bit
位,蓝色占据5 bit
位。TFT_eSPI 库提供了一个便捷的color565()
方法,可以将普通的 RGB 颜色转换为 RGB565模式的颜色:
归属类与返回值 | API 函数 | 功能描述 |
---|---|---|
uint16_t TFT_eSPI:: | color565(uint8_t r, uint8_t g, uint8_t b) | 用于将普通 RGB 颜色转换为 RGB565模式的颜色。 |
下面的示例代码,通过 color565()
函数将红、黄、蓝、绿4 种 RGB 颜色,分别转换为了 RGB565 模式的颜色值:
1 | uint16_t RGB_Red = tft.color565(255, 0, 0); |
在 TFT_eSPI 库安装目录下的 TFT_eSPI.h
源文件里,已经预定义了如下一系列的默认颜色,代码当中可以直接进行使用:
1 |
下面表格当中的函数用于控制TFT_eSP::print/printf/println()
系列文本输出函数(可以自动换行)的坐标系统:
API 方法 | 功能描述 |
---|---|
void setCursor(int16_t x, int16_t y) | 为 tft.print() 设置文本光标的(x, y) 坐标位置。 |
void setCursor(int16_t x, int16_t y, uint8_t font) | 为 tft.print() 设置文本光标的(x, y) 坐标位置和字体。 |
int16_t getCursorX(void) | 获取当前 tft.print() 文本光标在 x 轴的坐标位置。 |
int16_t getCursorY(void) | 获取当前 tft.print() 文本光标在 y 轴的坐标位置。 |
而接下来表格当中的这些方法,则用于控制TFT_eSP::drawXxx()
系列文本输出函数(无法自动换行)的参考基准点:
API 方法 | 功能描述 |
---|---|
uint8_t getTextDatum(void) | 获取文本输出基准点。 |
void setTextDatum(uint8_t d) | 设置文本输出基准点。 |
上面表格当中的 setTextDatum(uint8_t d)
函数的参数d
表示基准点的位置,可供选择的枚举参数有如下这些:
1 |
除此之外,TFT_eSPI库还提供了如下一系列文本输出相关的辅助函数:
API 方法 | 功能描述 |
---|---|
void setTextFont(uint8_t f) | 设置当前所要显示文本的字体。 |
void setTextSize(uint8_t s) | 设置文本放大倍数(自定义字体无效),参数s 的取值范围介于 1 ~ 7 之间。 |
void setTextColor(uint16_t c) | 设置字体颜色(背景为透明)。 |
void setTextColor(uint16_t c, uint16_t b) | 设置字体的颜色以及其背景色。 |
void setTextWrap(bool wrapX, bool wrapY) | 设置文本是否自动换行。 |
void setTextPadding(uint16_t x_width) | 设置填充宽度(以像素为单位),将会擦除之前的文本内容。 |
void getTextPadding(void) | 获取填充宽度(以像素为单位)。 |
下面的示例代码,会向 UINIO-Monitor屏幕从上至下依次打印 Hello UinIO.com
字符串内容:
1 |
|
TFT_eSPI 库在其安装目录TFT_eSPI\Tools\Create_Smooth_Font\Create_font
下面提供了处理自定义字体的 Create_font工具,其中包含有如下源文件和目录:
data
目录:用于存放 .ttf
以及.otf
字体文件。FontFiles
目录:保存的是转换处理之后所获得的.vlw
字体文件。Create_font.pde
工程文件:用于将自定义字体,从 Unicode编码转换为 .vlw
格式的字体文件(后续需要再进一步转换为.h
文件)。Processing是一款用于图像处理的开源编程语言与开发环境,通过其可以打开位于TFT_eSPI 库安装目录TFT_eSPI\Tools\Create_Smooth_Font\Create_font
下面,用于制作自定义字体的 Processing 工程文件Create_font.pde
:
将下面的代码复制到 Create_font.pde
的用户配置参数注释USER CONFIGURED PARAMETERS
所在的位置,并且替换掉原来的内容:
1 | // >>>>>>>>>> USER CONFIGURED PARAMETERS START HERE <<<<<<<<<< |
接下来,就可以根据下面列出的步骤,依次进行相关的处理和操作:
\u
替换为 0x
,最后将结果填写到Create_font.pde
工程源文件的specificUnicodes()
函数里。SourceHanSansSC-Bold.otf
复制到TFT_eSPI\Tools\Create_Smooth_Font\Create_font
路径下面的data
目录,同时把 Create_font.pde
里的fontName
变量修改为字体的文件名称SourceHanSansSC-Bold
,而 fontType
变量修改为.otf
。与此同时,就会在TFT_eSPI\Tools\Create_Smooth_Font\Create_font
路径下面的FontFiles
目录里,发现刚才已经转换完成了的SourceHanSansSC-Bold14.vlw
文件:
1 | D:\Workspace\Workspace_Arduino\libraries\TFT_eSPI\Tools\Create_Smooth_Font\Create_font\FontFiles |
接下来,继续通过在线文件十六进制转换器,或者该网站上提供的 bin2hex.exe
程序,把前面生成的SourceHanSansSC-Bold14.vlw
文件转换为十六进制的格式:
此时可以打开 Arduino IDE新建一个草图工程,接着在工程文件的根目录再新建一个font_chengdu.h
头文件(用于保存上述十六进制编码),把上面获得的十六进制编码拷贝到下面的font_chengdu
数组变量当中,就成功创建出了可供TFT_eSPI 库使用的 font_chengdu.h
字体头文件:
1 |
|
在刚才新建的 Arduino 草图工程源代码里边,通过预处理命令#include
包含上面建立的 font_chengdu.h
字体头文件,然后使用 loadFont()
函数加载字体,再分别通过print()
和 drawString()
函数向屏幕输出思源黑体的成都,最后在使用完成之后调用unloadFont()
函数卸载字体:
1 |
|
TFT_eSPI 库的作者还提供了一个简单小巧的 TFT_eWidget图形界面库,不过 Arduino 当中通常使用 LVGL 结合TFT_eSPI来绘制图形界面,所以该库的运用并不广泛,本文就不再赘述,有需要的朋友可以直接参考开源项目当中的说明文档。
]]>U8G2
、AsyncTimer
、RBD_BUTTON
、LiquidCrystal_I2C
、ESP32SPISlave
、Servo
、SdFat
等常用第三方库,通过分析注释典型的示例代码,分门别类的介绍了各种片上资源外设的实例化运用。ESP32-C3 和 ESP32-S3是当前市场上比较流行的两款物联网主控芯片方案,它们分别基于开源的RISC-V 内核,以及商业化的 Xtensa内核,并且同时支持 WiFi 与 Bluetooth无线连接。由于日常工作当中经常使用到这两款微控制器,所以特意设计了 UINIO-MCU-ESP32C3和 UINIO-MCU-ESP32S3两款核心板,关于它们硬件电路设计方面的相关内容,可以进一步参考本篇文章的姊妹篇《UINIO-MCU-ESP32核心板电路设计》。由于本文属于 Arduino进阶性质的教程,阅读时需要具备一定的嵌入式开发经验,萌新可以阅读笔者更早之前撰写的《玩转 Arduino Uno、Mega、ESP开源硬件》。
Arduino IDE 2 相较于之前的 1.8.19
版本,提供了更加友好的用户界面,新增了自动补全
、内置调试器
、Arduino Cloud 同步
等功能,拥有一个改进的侧边栏,使得常用的功能更加易于访问,详细用法可以查阅Arduino 官方提供的《Arduino IDE 2Tutorials》:
注意:Arduino IDE 创建的以
.ino
作为后缀名的源代码文件,被称为草图(Sketche)文件。
乐鑫科技在 GitHub 开源社区推出的 Arduino-ESP32板级支持包,目前已经更新到 2.0.11
版本,通过向Arduino IDE的【开发板管理器】添加如下的开发板管理器地址
,就可以完成Arduino-ESP32 板级支持包的安装:
https://espressif.github.io/arduino-esp32/package_esp32_index.json
https://espressif.github.io/arduino-esp32/package_esp32_dev_index.json
Arduino-ESP32 提供了对于ESP32、ESP32-S2、ESP32-C3、ESP32-S3系列芯片的支持,各个片上外设的具体兼容情况可以参见下表:
注意:所有 ESP32 系列芯片都支持 SPI 以太网,其中RMII 只有 ESP32 能够支持。
《ESP32Arduino 核心文档》 当中提供了如下这些 API的使用说明,具体内容可以点击下面表格当中的链接逐一查阅:
安装完成 CH343P的 USB 转串口驱动程序之后,就可以将 UINIO-MCU-ESP32核心板连接至电脑,再打开 Arduino IDE选择【ESP32C3 Dev Module】或者【ESP32S3 DevModule】开发板,以及相应的 USB端口,就可以完成全部的开发连接准备:
接下来,编写如下的代码,以 115200
波特率向Arduino IDE 的【串口监视器】打印字符串Welcome to UinIO.com
:
1 | /* 该函数只调用一次 */ |
如果 Arduino IDE的【串口监视器】当中正确打印出了如下结果,就表明当前的开发环境已经搭建成功了:
1 | Welcome to UinIO.com |
注意:笔者设计的 UINIO-MCU-ESP32C3和 UINIO-MCU-ESP32S3两款开源硬件在本文后续内容当中。都将会被统称为UINIO-MCU-ESP32,如果没有进行特殊说明,那么所有示例代码都同时兼容两款核心板。
发光二极管(LED,Light EmittingDiode)在正向导通之后就会发光,对于直插式发光二极管(长脚为正,短脚为负),其红色和黄色的正向压降为2.0V ~ 2.2V
,而绿色、白色、蓝色产生的正向压降为3.0V ~ 3.2V
,额定工作电流介于 5mA ~ 20mA
范围之间。接下来以红色发光二极管为例,介绍其限流电阻的计算方法。
首先,红色 LED 正常工作时产生的压降约为 2.0V
,而 ESP32引脚输出的高电平为 3.3V
,此时限流电阻上流过的电压等于3.3 - 2.0 = 1.3V
,而红色发光二极管的额定电流约为10mA
,所以这个限流电阻的取值应当为 \(\frac{1.3V}{0.01A} =130Ω\),这里近似的取电阻标称值为120Ω
,并且将其连接到 Arduino-MCU-ESP32 的GPIO0 引脚,具体的电路连接关系如下图所示:
注意:ESP32系列芯片高电平信号的最低电压值为
3.3V × 0.8 = 2.64V
,而低电平信号的最高电压值为3.3V × 0.1 = 0.33V
。
pinMode(pin, mode)
:配置引脚工作模式,其中mode
参数可选的值有INPU
、OUTPUT
、INPUT_PULLUP
、INPUT_PULLDOWN
;digitalWrite(pin, value)
:设置数字输出引脚的电平状态,其中value
参数可选的值是 HIGH
或者LOW
;delay(ms)
:延时函数,其参数 ms
的单位为毫秒;1 | int LED_Pin = 0; |
由于使用 delay()
延时函数会阻塞后续任务的执行,所以这里改用如下两个API,通过循环计算时间差值的方式来实现 LED 灯的闪烁:
millis()
:程序当前运行的毫秒数;micros()
:程序当前运行的微秒数;下面的示例代码通过 UINIO-MCU-ESP32 的GPIO0
引脚控制一个 LED 灯,每间隔 1秒循环不断的进行闪烁:
1 | int LED_Pin = 0; |
如果需要控制多个 LED的闪烁,则需要将电路连接关系修改为下面的样子,此时控制引脚需要变更为UINIO-MCU-ESP32 的 GPIO1
和GPIO2
:
注意需要同步修改代码当中控制引脚变量 LED_Pin_x
的值,其它的功能代码只需要进行相应的复制粘贴即可:
1 | int LED_Pin_1 = 1; // 将 LED 1 的控制引脚设置为 GPIO1 |
本示例需要将 UINIO-MCU-ESP32 的 GPIO3
和 GPIO4
分别连接至 LED和按键:
由于按键的控制引脚被配置为输入上拉INPUT_PULLUP
,所以当按键被按下时低电平有效,读取引脚的电平状态需要使用到如下的API:
digitalRead(pin)
:读取指定输入引脚 pin
的电平状态,返回值是 HIGH
或者 LOW
;1 | int LED_Pin = 3; // LED 控制引脚 |
观察上述代码的运行结果,可以发现按键对于 LED亮灭状态的控制并不准确,这是由于按键在按下时,触点的接触不够稳定所导致。在这里我们可以方便的借助RBD_BUTTON这款第三方库来消除这种抖动。接下来在 Arduino IDE当中安装 RBD_Button 以及关联的RBD_Timer 依赖库,由于该库所提供的Button
类位于 C++ 的RBD
命名空间当中,所以其构造函数的调用形式应当书写为:
1 | RBD::Button constructor(pin,[input, input_pullup, input_pulldown]) |
Button
类当中提供了如下一系列可以用于消除按键抖动的方法:
button.isPressed()
:当按键被按下或开启时返回true
,否则返回 false
;button.isReleased()
:当按键弹起或者释放时返回true
,否则返回 false
;button.onPressed()
:当按钮被按下(已经去除抖动)一次以后返回true
,接下来必须释放按钮,并且再次按下才能够返回true
;button.onReleased()
:当按钮被释放(已经去除抖动)一次以后返回true
,接下来必须按下按钮,并且再次释放才能够返回true
;button.setDebounceTimeout(value)
:设置消除抖动的时间,参数的单位为毫秒;修改前面的示例代码,加入按键消抖的处理逻辑,可以看到在消除抖动错误的同时,代码的书写也得到了极大简化:
1 |
|
LED 发光二极管的正常工作电压介于1.8V ~ 2.0V
之间,由于该电压变化区间的取值范围较小,难以通过电压大小来控制 LED的亮度。而脉冲宽度调制(PWM,PulseWidthModulation)则另辟蹊径,通过改变输出方波的占空比来控制LED 的亮灭频率,从而达到调整亮度的目的。
ESP32-C3 和 ESP32-S3 各拥有6
和 8
个 LEDC通道,分别用于产生独立的 PWM 波形信号,最大精度为 14位。Arduino-ESP32 提供了专门的 LED控制 API(LEDC,LED Control),可以方便的以 PWM 方式来控制LED 的亮度,具体的 API 方法可以参考下面的列表:
API | 功能描述 |
---|---|
uint32_t ledcSetup(uint8_t channel, uint32_t freq, uint8_t resolution_bits); | 用于设置 LEDC通道的频率和分辨率; |
void ledcWrite(uint8_t chan, uint32_t duty); | 设置指定 LEDC通道的占空比; |
uint32_t ledcRead(uint8_t chan); | 获取指定 LEDC通道的占空比; |
uint32_t ledcReadFreq(uint8_t chan); | 获取指定 LEDC通道的频率; |
uint32_t ledcWriteTone(uint8_t chan, uint32_t freq); | 用于在指定频率上将 LEDC 通道设置为50% 占空比的 PWM 音调; |
uint32_t ledcWriteNote(uint8_t chan, note_t note, uint8_t octave); | 用于将 LEDC通道设置为指定的音符; |
void ledcAttachPin(uint8_t pin, uint8_t chan); | 用于将指定的 GPIO引脚绑定至 LEDC 通道; |
void ledcDetachPin(uint8_t pin); | 用于取消指定的 GPIO引脚与 LEDC 通道的绑定; |
uint32_t ledcChangeFrequency(uint8_t chan, uint32_t freq, uint8_t bit_num); | 用于动态改变 LEDC通道的频率; |
void analogWrite(uint8_t pin, int value); | 用于在指定 GPIO引脚上写入模拟值(PWM 波形信号),该接口兼容 Arduino官方的 analogWrite() 函数; |
void analogWriteResolution(uint8_t bits); | 用于设置所有 analogWrite() 通道的分辨率; |
void analogWriteFrequency(uint32_t freq); | 用于设置所有 analogWrite() 通道的频率; |
下面的示例代码将 LEDC 配置为 0
通道,工作频率为 5000
赫兹,精度为 12
位(即将一个周期划分为 \(2^{12}\) 等分)。如果需要将其占空比调整为50%
,那么高电平就需要占据 \(2^{12} \div 2 = 2^{12 - 1} = 2^{11}\)等分:
1 | void setup() { |
接下来再利用 LEDC 和 PWM实现一个呼吸灯效果,具体策略为每秒钟调整占空比 50
次,假设T
为呼吸周期,那么 LED 从熄灭到最高亮度需要经过的时间为\(\frac{T}{2}\)(即半个呼吸周期)。这样每半个周期就需要进行\(50 \times \frac{T}{2}\)次占空比调整,而 count
表示占空比为 100%
时候的等分数量,step
就是每次占空比调整所需要增加的步进值\(step = \frac{count}{50 \times \frac{T}{2}} =2 \times \frac{count}{50 \times T}\),当占空比超过Count
时,就需要逐步将 Step
步进值递减至0
:
1 | int GPIO4 = 4; // 指定 GPIO 引脚 4 |
上面代码当中的 delay()
函数会阻塞UINIO-MCU-ESP32 的后续代码运行,下面通过prevTime
和 curTime
两个变量来循环计算时间差值,实现一个非阻塞式的呼吸灯:
1 | int GPIO4 = 4; // 指定 GPIO 引脚 4 |
ESP32-C3 和 ESP32-S3 分别拥有2
个和 4
个硬件定时器,虽然它们的精度较高,但是数量着实有限。在一些对于精度要求不高的场合,可以考虑使用诸如AsyncTimer这样的第三方库来作为软件定时器使用,它适用于一些对于精度要求不高的场合(精度为毫秒级别),具体的使用步骤如下面所示:
AsyncTimer
库;#include <AsyncTimer.h>
;AsyncTimer timer
;void loop()
函数当中调用t.handle()
;下面的示例代码,会通过 AsyncTimer 提供的setTimeout()
函数,分别延时 3
秒和5
秒向串口打印提示信息:
1 |
|
同样的,可以通过类似的方式调用 AsyncTimer 的setInterval()
函数,周期性的不断重复向串口打印提示信息:
1 |
|
注意:注意每次调用
setTimeout()
和setInterval()
之后返回的 ID 值都并不相同。
接下来,结合前面介绍的 RBD_Button 和AsyncTimer 两个第三方库,让一个 LED在刚开始启动的时候,每间隔 1秒钟进行闪烁,而在按下按键之后,再切换至间隔 3秒进行闪烁,再次按下按键则切换回间隔 1秒进行闪烁,这里依然沿用之前的按键与 LED 实验电路:
1 |
|
模数转换器(ADC,Analog to DigitalConverter)是一种常见外设,用于将模拟信号转换为便于 ESP32微控制器,读取与处理的数字信号。
Arduino-ESP32 当中针对 ADC外设,提供了如下一系列通用的 API 函数:
Arduino 通用的 ADC API | 功能描述 |
---|---|
uint16_t analogRead(uint8_t pin); | 获取指定引脚或者 ADC 通道的原始值。 |
uint32_t analogReadMilliVolts(uint8_t pin); | 获取指定引脚或者 ADC通道的原始值(以毫伏为单位)。 |
void analogReadResolution(uint8_t bits); | 设置 analogRead() 返回值的分辨率,ESP32S3 默认为 13位(从 0 到 8191 ),其它型号默认为12 位(从 0 到 4095 )。 |
void analogSetClockDiv(uint8_t clockDiv); | 设置 ADC 时钟的分频器,范围为0 ~ 255 ,默认值为 1 。 |
void analogSetAttenuation(adc_attenuation_t attenuation); | 设置全部通道的衰减系数,共拥有ADC_ATTEN_DB_0 、ADC_ATTEN_DB_2_5 、ADC_ATTEN_DB_6 、ADC_ATTEN_DB_11 四个选项。 |
void analogSetPinAttenuation(uint8_t pin, adc_attenuation_t attenuation); | 设置指定引脚或者 ADC 通道的衰减系数。 |
bool adcAttachPin(uint8_t pin); | 将 GPIO 引脚关联至 ADC,关联成功返回true ,否则返回 false 。 |
ADC 衰减系数 | ESP32-C3 可测量输入电压范围 | ESP32-S3 可测量输入电压范围 |
---|---|---|
ADC_ATTEN_DB_0 | 0 mV ~ 750 mV | 0 mV ~ 950 mV |
ADC_ATTEN_DB_2_5 | 0 mV ~ 1050 mV | 0 mV ~ 1250 mV |
ADC_ATTEN_DB_6 | 0 mV ~ 1300 mV | 0 mV ~ 1750 mV |
ADC_ATTEN_DB_11 | 0 mV ~ 2500 mV | 0 mV ~ 3100 mV |
注意:ESP32S3 的最高采样分辨率为13 位,由于计数范围从
0
开始进行计数,所以其最大计数值为 \(2^{13} - 1= 8191\),同理 ESP32C3 的最大计数值等于 \(2^{12} - 1 = 4095\)。
ESP32 专用的 ADC API | 功能描述 |
---|---|
void analogSetWidth(uint8_t bits); | 设置硬件采样分辨率,取值范围为9 ~ 12 ,默认值是 12 ; |
void analogSetVRefPin(uint8_t pin); | 设置需要进行 ADC 校准的引脚。 |
int hallRead(); | 读取连接至 36 (SVP)和39 (SVN)引脚的霍尔传感器 ADC 值。 |
接下来通过 ADC 完成一个实验,使用电位器调整UINIO-MCU-ESP32 的 ADC引脚所读取到的输入电压,然后根据这个输入电压的大小,调节 GPIO引脚输出信号的占空比,从而达到调整 LED亮度的目的,UINIO-MCU-ESP32的电路连接关系如下图所示:
可以看到,这里把 UINIO-MCU-ESP32 的GPIO2
引脚连接至电位器,而 GPIO1
作为 LED发光二极管的控制引脚,接着编写并且上传如下的控制逻辑代码:
1 |
|
内部集成电路总线(I²C,Inter-IntegratedCircuit)是一种低速串行通信协议(标准模式100 Kbit/s
,快速模式 400 Kbit/s
),采用SDA
(串行数据线)和SCL
(串行时钟线)两线制结构(需要使用上拉电阻),分别可以连接多个设备,每个设备都拥有唯一的7 位地址(最多 128个设备)。Arduino-ESP32 的 I²C 库实现了 ArduinoWire 官方库当中的如下一系列 API 函数:
I²C 通用 API | 功能描述 |
---|---|
bool begin(); | 基于默认参数配置 I²C外设,正确初始化之后返回 true 。 |
bool setPins(int sdaPin, int sclPin); | 用于定义 SDA 和SCL 引脚,两个参数的默认值分别为 GPIO21 和GPIO22 。 |
bool setClock(uint32_t frequency); | 设置 I²C总线的时钟频率,默认为 100KHz 。 |
uint32_t getClock(); | 获取 I²C总线的时钟频率。 |
void setTimeOut(uint16_t timeOutMillis); | 设置 I²C总线超时时间(毫秒)。 |
void setTimeOut(uint16_t timeOutMillis); | 获取 I²C总线超时时间(毫秒)。 |
size_t write(const uint8_t *, size_t); | 将数据写入到总线缓冲区,返回值为写入数据的大小。 |
bool end(); | 完成 I²C通信并且释放之前所有被分配的外设资源。 |
Arduino-ESP32 当中的 I²C总线可以分别运行于主设备(I²C MasterMode)和从设备(I²C SlaveMode)两种不同的工作模式:
I²C主设备模式:该模式用于向从设备发起通信,由主设备发出时钟信号,并且负责发起与从设备的通信。
I²C从设备模式:时钟信号依然由主设备产生,如果 I²C地址与从设备匹配,那么这个从设备就会响应主设备。
下面的表格展示了 I²C总线工作在主设备模式下时所使用到的 API:
I²C 主设备模式 API | 功能描述 |
---|---|
bool begin(int sdaPin, int sclPin, uint32_t frequency) | 指定 I²C 总线的 SDA 和SCL 引脚,以及通信频率。 |
void beginTransmission(uint16_t address) | 开始启动与指定 I²C地址从设备的通信。 |
uint8_t endTransmission(bool sendStop); | 将数据写入至缓冲区以后,使用该函数把数据发送给从设备,参数sendStop 用于使能 I²C 总线停止信号。 |
uint8_t requestFrom(uint16_t address, uint8_t size, bool sendStop) | 要求从设备向主设备发送响应数据。 |
上述 API 函数的基本使用步骤如下面的列表所示:
#include "Wire.h"
,包含 Wire.h
头文件;Wire.begin()
,开始配置 I²C 总线;Wire.beginTransmission(I2C_DEV_ADDR)
,指定 I²C从设备地址,开始进行数据传输;Wire.write(x)
,把数据写入到缓冲区;Wire.endTransmission(true)
,将缓冲区的全部数据写入至从设备;Wire.requestFrom(I2C_DEV_ADDR, SIZE)
,请求读取指定从设备的数据;Wire.readBytes(temp, error)
,开始读取从设备响应的数据;下面是一个如何在主设备模式下使用 I²C总线的示例代码:
1 |
|
下面的表格展示了 I²C总线工作在从设备模式下时所使用到的 API:
I²C 从设备模式 API | 功能描述 |
---|---|
bool Wire.begin(uint8_t addr, int sdaPin, int sclPin, uint32_t frequency) | 在从设备模式下,必须通过传递从设备的地址来调用begin() 函数。 |
void onReceive( void (*)(int) ) | 定义从设备接收主设备数据的回调函数。 |
void onRequest( void (*)(void) ) | 定义从设备请求主设备数据的回调函数。 |
size_t slaveWrite(const uint8_t *, size_t) | 接收到响应数据之前,该函数用于向从设备的缓冲区写入数据。 |
上述 API 函数的基本使用步骤如下面的列表所示:
#include "Wire.h"
,包含 Wire.h
头文件;Wire.onReceive(onReceive)
和Wire.onRequest(onRequest)
,创建两个回调函数来接收或者请求主设备的数据;Wire.begin((uint8_t)I2C_DEV_ADDR);
,使用指定的地址配置I²C 总线;Wire.slaveWrite((uint8_t *)message, strlen(message));
,预先向从设备的缓冲区写入数据;下面是一个如何在从设备工模式下使用 I²C总线的示例代码:
1 |
|
接下来,以 UINIO-MCU-ESP32S3 作为主设备,而UINIO-MCU-ESP32C3 作为从设备(I²C 地址为55
),两者的 SDA
和 SCK
都分别指定为为 GPIO5
和 GPIO6
,并且在从设备的GPIO8
上面连接一枚 LED:
UINIO-MCU-ESP32S3 作为主设备,每间隔 2秒就会向从设备 UINIO-MCU-ESP32C3发送一个递增的数值,从设备接收到主设备的数据之后LED 就会闪烁 0.5 秒,并且在收到的数值后面添加 已经被接收
字样,然后返回给主设备打印至串口,具体的示例代码如下面所示:
1 | /* UINIO-MCU-ESP32S3 主设备程序 */ |
如果主设备 requestFrom()
所指定的quantity
参数的数据量,大于从设备发送过来的数据量,那么多出的空间将会由0xff
进行填充。
1 | /* UINIO-MCU-ESP32C3 从设备程序 */ |
1602 字符型液晶显示屏,一共可以显示 2行内容,每一行可以显示 16个字符,屏幕驱动芯片采用了日立的HD44780,由于该屏幕在使用时需要占用大量 GPIO引脚。所以需要借助德州仪器的 PCF8574 八位 GPIO扩展器(工作电压介于 2.5V ~ 5.5V
范围),将其转换为两线制的I²C 总线协议。
注意:PCF8574 的 I²C 地址默认为
0x27
,可以通过0Ω
电阻调整PCF8574 模组A0
、A1
、A2
位置的通断来修改其 I²C地址。除此之外,还可以通过 PCF8574模组上面的电位器,调整 1602 液晶显示屏的对比度。
LiquidCrystal_I2C是一款兼容 HD44780 和 PCF8574 的 LCD屏幕驱动库,使用时需要将其工程 src
目录下的LiquidCrystal_I2C.cpp
和 LiquidCrystal_I2C.h
文件拷贝至 Arduino IDE 的草图根目录,然后通过#include "LiquidCrystal_I2C.h"
语句将其包含至 Arduino草图源文件:
1 |
|
注意:需要将 PCF8574 模块上丝印为
SDA
和SCL
的引脚,分别连接至UINIO-MCU-ESP32 的GPIO5
和GPIO6
引脚。
中断(Interrupt)是指计算机运行过程当中,如果出现某些意外情况需要干预时,程序能够自动停止当前正在运行的代码,转而处理这个新出现的情况,处理完毕之后再返回之前的程序继续执行。在Arduino-ESP32当中使用外部中断时,需要注意到以下情况:
delay()
函数依赖于中断,在中断服务程序当中无法调用;micros()
函数刚开始会正常工作,但是可能会在1 ~ 2
毫秒之后出现异常行为;millis()
函数依赖于中断计数器,其返回值在中断服务程序当中不会增加;delayMicroseconds()
并不会使用到中断计数器,因而能够在中断服务程序当中正常工作;ESP32-Arduino里的中断服务程序(ISR, Interrupt ServiceRoutines)是一种没有参数和返回值的特殊函数(如果代码中同时使用到多个中断服务程序,那么它们将会按照优先级的顺序进行执行),ESP32-Arduino库支持以如下方式,在指定的引脚上面启用或者关闭外部中断服务:
1 | attachInterrupt(digitalPinToInterrupt(pin), ISR, mode) // 开启中断,并且添加中断服务程序 |
pin
: 发生外部中断的 GPIO 引脚编号;ISR
:发生外部中断时候,自动调用的中断服务函数(无参数,无返回值);mode
: 中断触发方式,取值可以为LOW(低电平触发)、CHANGE(状态变化触发)、RISING(上升沿触发)、FALLING(下降沿触发)四个常量当中的一个;接下来使用中断服务程序,完成一个当按键按下的时候,LED发光二极管熄灭,而在按键弹起时 LED 点亮的程序:
1 | const byte LED = 5; // LED 连接的 GPIO 引脚 |
上述代码只是在中断服务程序里控制 LED的亮灭状态,如果需要使用一个全局变量,在中断服务程序与主程序之间传递数据,那么必须要将其声明为volatile
类型,从而确保该全局变量总是被正确的更新,例如下面代码当中的number
变量就使用了 volatile
关键字进行声明:
1 | volatile int number = 0; |
而在下面这份示例代码当中,如果程序执行到注释的位置发生了中断,那么变量number 1
的值将不会得到更新:
1 | volatile int number1 = 0; |
如果要确保 number 1
的值正常更新,就必须短暂的禁用中断。ESP32-Arduino支持手动使能 interrupts()
和失能 noInterrupts()
中断服务:
1 | void setup() {} |
可以修改前面的示例代码,通过使用 interrupts()
和noInterrupts()
函数,使得程序即使执行到注释位置发生中断,也仍然可以确保变量 number1被正确的更新:
1 | volatile int number1 = 0; |
由于 ESP32-C3 和 ESP32-S3两款微控制器都拥有两个计算核心,即使禁用了当前核心的中断服务,另外一个核心也同样可能访问到临界区(访问共用资源的程序片段)的资源,所以就需要在禁用中断的同时,对临界区的资源进行上锁。由ESP-IDF 提供的portMUX_INITIALIZER_UNLOCKED
自旋锁,同样可以应用在 ESP32-Arduino的草图代码当中:
1 | portMUX_TYPE mux = portMUX_INITIALIZER_UNLOCKED; // 定义自旋锁变量 |
注意:上述代码当中的
IRAM_ATTR
关键字,同样是由 ESP-IDF所提供,用于把这段代码保存至芯片内部的RAM(IRAM)里面(否则放置到Flash),从而提高中断服务程序的响应速度,建议ESP32-Arduino的中断服务程序都使用该关键字进行声明。
本示例将会基于 UINIO-MCU-ESP32实现一个频率与占空比的测量功能。首先,需要开启指定 GPIO引脚的外部中断,当每一次触发中断的时候,都记录下信号上升沿与下降沿发生的时间(单位为微秒
)。然后,在中断服务程序里使用digitalRead()
函数,判断当前属于高电平还是低电平。最后,记录前一次上升沿、下降沿产生的时间,并且在下一个上升沿中断发生时进行如下一系列计算:
这里同样将 1602 液晶屏 I²C 总线的 SDA
和SCL
,分别连接到 UINIO-MCU-ESP32 的GPIO5
和 GPIO6
引脚,同时把信号发生器的输出探头连接至UINIO-MCU-ESP32 的 GPIO8
引脚:
当信号发生器输出频率为 1000Hz
,占空比为 50%
的方波信号时,下面的代码就可以使得 UINIO-MCU-ESP32 在1602 屏幕上显示出频率 Freq: 1000.0
和占空比 Duty: 0.5
:
1 |
|
ESP32-C3 芯片内置有 2 个 54
位通用定时器(具有 16
位预分频器和 54
位可自动重载的向上/向下计数器)。 而ESP32-S3 则内置有 4 个 54
位通用定时器(具有 16
位预分频器和 54
位可自动重载的向上/向下计数器)。
ESP32 的通用定时器以 APB 时钟APB_CLK
作为基本时钟源(该时钟频率由 CPU_CLK
的时钟(即微控制器当前的运行频率)决定,其中 ESP32-C3为 160 MHz
,而 ESP32-S3 为240 MHz
),而 16 位预分频器(取值范围为1 ~ 65536
)的作用就是对 APB时钟进行分频,从而产生时基计数器时钟TB_CLK
(每经过 1 个周期向上或者向下进行计数)。
注意:所谓分频就是将信号频率降低到原来的\(\frac{1}{N}\),称为 N分频。
已知 \(CPU\_CLK_{C3} = 160MHz\),而\(CPU\_CLK_{S3} =240MHz\),假设每一次计数的时间间隔为 10
微秒,那么所需的频率等于其倒数 \(\frac{1}{10\mu S} = 0.1MHz\),此时 ESP32-C3 和ESP32-S3 的分频系数应当分别被设置为:
\[\begin{cases}\frac{CPU\_CLK\_{C3}}{0.1MHz} = \frac{160}{0.1} = 1600 \\\frac{CPU\_CLK\_{S3}}{0.1MHz} = \frac{240}{0.1} = 2400\end{cases}\]
换而言之,如果计数周期为 1
微秒,那么ESP32-C3 和 ESP32-S3的分频系数应当分别被设置为 160
和240
。Arduino-ESP32封装有一系列定时器相关的 API,它们的基本使用步骤如下面所示:
1 | /* 定义一个定时器指针变量 */ |
可以看到在定时器的整个使用过程当中,最为重要的就是定时器初始化函数timerBegin()
。如果定时器初始化成功,那么其返回值为一个timer
结构体,反之则会返回NULL
。除此之外,该函数的第 1 个参数 num
是定时器编号,第 2 个参数 divider
是定时器分频系数,第 3 个参数 countUp
则是定时器计数方向,更多关于Arduino-ESP32 当中定时器的 API 可以参考下面的表格:
API | 功能描述 |
---|---|
hw_timer_t * timerBegin(uint8_t num, uint16_t divider, bool countUp) | 配置定时器; |
void timerEnd(hw_timer_t *timer) | 结束定时器; |
uint32_t timerGetConfig(hw_timer_t *timer) | 获取定时器配置; |
void timerSetConfig(hw_timer_t *timer, uint32_t config) | 配置已经初始化的定时器; |
void timerAttachInterrupt(hw_timer_t *timer, void (*fn)(void), bool edge) | 添加定时器中断服务程序; |
void timerDetachInterrupt(hw_timer_t *timer) | 拆除定时器中断服务程序; |
void timerStart(hw_timer_t *timer) | 开始定时器计数; |
void timerStop(hw_timer_t *timer) | 停止定时器计数; |
void timerRestart(hw_timer_t *timer) | 重启定时器计数; |
void timerWrite(hw_timer_t *timer, uint64_t val) | 设置定时器的计数值; |
void timerSetDivider(hw_timer_t *timer, uint16_t divider) | 设置定时器的分频系数; |
void timerSetCountUp(hw_timer_t *timer, bool countUp) | 设置定时器的计数方向; |
void timerSetAutoReload(hw_timer_t *timer, bool autoreload) | 设置定时器计数值的自动重载; |
bool timerStarted(hw_timer_t *timer) | 判断定时器是否在运行; |
uint64_t timerRead(hw_timer_t *timer) | 获取定时器的计数值; |
uint64_t timerReadMicros(hw_timer_t *timer) | 获取定时器的计数(微秒); |
uint64_t timerReadMilis(hw_timer_t *timer) | 获取定时器的计数(毫秒); |
double timerReadSeconds(hw_timer_t *timer) | 获取定时器的计数(秒); |
uint16_t timerGetDivider(hw_timer_t *timer) | 获取定时器的分频系数; |
bool timerGetCountUp(hw_timer_t *timer) | 获取定时器的计数方向; |
bool timerGetAutoReload(hw_timer_t *timer) | 获取定时器计数值的自动重载状态; |
void timerAlarmEnable(hw_timer_t *timer) | 使能定时器告警事件的生成; |
void timerAlarmDisable(hw_timer_t *timer) | 失能定时器告警事件的生成; |
void timerAlarmWrite(hw_timer_t *timer, uint64_t alarm_value, bool autoreload) | 设置定时器的自动加载与告警值; |
bool timerAlarmEnabled(hw_timer_t *timer) | 获取定时器的告警状态; |
uint64_t timerAlarmRead(hw_timer_t *timer) | 获取定时器的告警值; |
uint64_t timerAlarmReadMicros(hw_timer_t *timer) | 获取定时器的告警值(微秒); |
double timerAlarmReadSeconds(hw_timer_t *timer) | 获取定时器的告警值(秒); |
信号量(Semaphore[ˈseməfɔːr])用于解决并发任务当中的互斥与同步问题。可以简单的将其理解为一个队列(只需要关注该队列当中元素的个数),也可以将其理解为一个整型的全局变量(用于记录信号个数)。而二值信号量则表示的是一种只存在两种状态的队列(有信号
或者无信号
),使用时通过检测信号是否存在,再来决定是否处理相关的任务。相比于全局变量,二值信号量可以等待信号,并且保证操作的原子化,通常应用于中断服务程序与主任务之间的状态同步,其基本使用方法如下面的示例所示:
1 | /* 中断服务程序 */ |
由于 Arduino-ESP32 在底层是基于嵌入式实时操作系统 FreeRTOS构建,该操作系统提供有一系列信号量API,因而在 Arduino-ESP32当中同样可以直接进行调用:
API | 功能描述 |
---|---|
SemaphoreHandle_t xSemaphoreCreateBinary() | 创建一个二进制信号量,并返回一个可以引用该信号量的句柄。 |
xSemaphoreTake( SemaphoreHandle_t xSemaphore, TickType_t xTicksToWait ) | 获取信号量。 |
xSemaphoreTakeFromISR(SemaphoreHandle_t xSemaphore, signed BaseType_t *pxHigherPriorityTaskWoken) | 在中断服务程序里获取信号量。 |
xSemaphoreGive( SemaphoreHandle_t xSemaphore ) | 释放信号量。 |
xSemaphoreGiveFromISR(SemaphoreHandle_t xSemaphore, signed BaseType_t *pxHigherPriorityTaskWoken) | 在中断服务程序里释放信号量。 |
在下面的示例代码当中,通过结合使用定时器中断和二值信号量,每间隔1
秒钟打印中断被触发的次数 Count
以及时间Time
:
1 | volatile int Count = 0; // 中断触发的次数 |
新款的 HC-SR04 超声波模组采用了RCWL-9206 作为测距解调芯片,其工作电压范围介于3V ~ 5.5V
之间,工作电流为2.2mA ~ 3mA
,同时支持GPIO、UART、I²C三种通信方式,更多的性能参数可以参考下面的表格:
HC-SR04超声波模组引脚接口的功能定义,如下面的表格所示:
通过配置模组上的电阻 \(R_4\) 和\(R_5\) 可以选择HC-SR04 的引脚通信模式:
由 UINIO-MCU-ESP32 发射一个持续时间至少10us
的脉冲信号到 HC-SR04 的Trig
引脚;此时 HC-SR04 会连续发送出 8 个40KHz
频率的超声波信号,并且 HC-SR04 的Echo
引脚会切换为高电平;如果超声波信号没有响应,那么Echo
引脚就会在维持 38ms
的高电平之后,重新切换为低电平状态:
如果超声波信号被物体反射,那么 Echo
引脚就会从高电平切换至低电平,从而产生出一个脉冲信号,这个脉冲的宽度就是超声波从发射到被物体反射回来的间隔时间,即经过超声波探头与物体之间2 倍距离所耗费的时间:
根据超声波在空气当中的传输速度,就可以计算出超声波探头与物体之间的距离(两次测量的间隔时间不能低于200
毫秒):
\[超声波探头与物体之间的距离 = 超声波传输速度 \times\frac{脉冲宽度时间}{2}\]
由于环境温度会对超声波信号的传输速度造成影响,如果需要更加精确的测量距离,那么就必须把温度的因素纳入考量范围,并且进行相应的温度补偿:
环境温度 | 超声波典型传输速度 |
---|---|
0℃ | 330.45 米每秒 |
20℃ | 342.62 米每秒 |
40℃ | 354.85 米每秒 |
Arduino 官方库当中提供的 pulseIn()
函数可以用于读取脉冲信号的持续时间(以微秒为单位),其中参数pin
是需要用于读取脉冲信号的UINIO-MCU-ESP32 引脚编号,而参数 value
则用于指定脉冲的类型(高电平脉冲 HIGH
或者低电平脉冲 LOW
),可选的参数timeout
则用于设置脉冲读取的超时时间(单位为微秒,默认为1000
,即 1
秒钟)。
1 | pulseIn(pin, value, timeout) |
这里把 UINIO-MCU-ESP32S3 的 GPIO8
和GPIO9
分别作为 HC-SR04 超声波模组的 Echo
和Trig
引脚,然后以 GPIO通信方式,通过上面的 pulseIn()
函数读取 HC-SR04传感器的数据,并且计算出以厘米作为单位的距离值,最后打印到波特率为115200
的串口上面:
1 | const int Echo_Pin = 8; // 指定 Echo 连接的 GPIO 引脚 |
由于上述代码当中的 pulseIn()
和 delay()
函数在运行时都是阻塞式的,会严重的迟滞其它任务的执行时间,接下来会以非阻塞式的中断方式来实现相同功能,有所不同的是,这次会把结果显示到1602 液晶屏幕上面:
change
添加至连接到超声波传感器Echo
的 GPIO 引脚,然后使用硬件定时器每间隔500
毫秒向超声波模组的 Trig
引脚发送15
微秒的脉冲,即每 1 秒钟进行两次测量。loop()
函数在接收到信号量之后,根据获取到的\(t_1\) 与 \(t_2\)的数值,就可以计算出物体与超声波探头之间的距离,并且显示在 1602屏幕上面。接下来,同样把 UINIO-MCU-ESP32S3 的GPIO5
和 GPIO6
引脚,作为 1602 液晶显示屏 I²C总线的 SDA
和 SCL
。而 GPIO8
和GPIO9
分别作为 HC-SR04 超声波模组的 Echo
和Trig
引脚:
下面代码同样是以 GPIO 通信方式读取 HC-SR04传感器的数据,并且以非阻塞式方式计算出以毫米作为单位的距离值,最后将该值显示到1602 液晶屏幕上面:
1 |
|
航模玩家经常使用到的舵机,本质上是一种低成本的伺服电机(Servomotor)系统。其工作原理是通过内部的控制电路接收PWM脉冲宽度调制信号,然后控制内置电机转动,内置电机带动一系列的减速齿轮组把扭矩传递至输出轴和舵盘。输出轴会与用于反馈角度位置的电位器相互连接,当舵盘转动的时候,同时会带动电位器输出一个电压信号,反馈至舵机内部的控制电路,然后控制电路根据其位置决定舵机转动的角度
或者速度
。
根据控制电路的不同,可以将舵机划分为数字舵机和模拟舵机两种类型。而根据旋转角度的不同,也可以将其进一步划分为180°
舵机和 360°
舵机两种类型:
180°
舵机:可以通过脉冲宽度调制 PWM信号控制旋转角度(从 0°
度到 180°
度)。360°
舵机:可以 360°
度转动,只能调节转动速度,不能调节转动角度。舵机的控制信号是一个周期为 20
毫秒的PWM 信号,其中脉冲宽度介于 0.5 ~ 2.5
毫秒范围之间,与其对应的线性旋转角度为0° ~ 180°
。换而言之,舵机会根据 PWM信号的脉冲宽度,将输出轴旋转到一个指定的角度上面:
在接下来的列表当中,分别介绍了舵机非常重要的 4 个性能参数:
F
与力臂 r
的乘积),其单位为牛顿·米(N·m
)。堵转力矩
通常高于额定力矩
)。该参数的单位为千克·厘米(Kg·cm
),即舵机发生堵转的时候,1
厘米的力臂所能够提起的最大质量。20
微秒,脉冲宽度为 1.5
微秒的基准信号。通过内置的比较器,将控制信号与这个基准信号进行比较,从而判断出旋转的角度。但是舵机在实际工作当中,难以完全精确的控制角度,而比较器的存在又势必会导致舵机在停止点附近往复振荡,因而就需要舵机的控制电路将这个误差值吸收掉,这就是动作死区。常见小型舵机的死区时间为5
微秒(对应角度为 0.45°
度),即如果想将舵机旋转 45°
度,其真正的停止位置会介于45° ± 0.45°
范围之间。60°
度所需要的时间。下面的两个表格,分别展示了采用塑料齿轮和传动轴的通用型SG90微型舵机(上图左)的性能参数,以及采用金属齿轮和传动轴的通用型MG996R 小型舵机(上图右)的性能参数:
SG90 舵机性能参数 | 参数值 |
---|---|
旋转角度 | 180° (± 15°) |
工作电压 | 4.8 V ~ 6 V (典型值为5 V ) |
空载电流 | 10 mA |
转动电流 | 100 mA ~ 250 mA |
堵转电流 | 360 mA |
失速力矩 | 1.7 Kg·cm |
转动速度 | 0.12 秒 / 60° |
MG996R 舵机性能参数 | 参数值 |
---|---|
旋转角度 | 180° (± 10°) |
工作电压 | 4.8 V ~ 6 V (典型值为5 V ) |
空载电流 | 10 mA |
转动电流 | 170 mA ~ 400 mA |
堵转电流 | 1.3 A ~ 1.5 A |
失速力矩 | 13 Kg·cm |
转动速度 | 0.2 秒 / 60° |
ESP32Servo库实现了 Arduino 官方舵机驱动库 Servo的全部功能,可以直接在 Arduino IDE的【库管理器】当中搜索安装,其主要 API 如下面的表格所示:
API | 功能描述 |
---|---|
Servo | 用于操作连接到UINIO-MCU-ESP32 引脚的舵机对象。 |
int attach(pin, min, max) | 将指定的 GPIO 引脚关联到 1 个 LEDC通道,并且返回通道编号(如果失败返回 0 )。其中参数min 的最小取值为 500 (默认值为544us ),而 max 的最大取值为2500 (默认值为 2400us )。 |
void write() | 指定舵机的旋转角度(0°~180° )。 |
void writeMicroseconds() | 以微秒 作为单位设置脉冲宽度(必须设置)。 |
int read() | 获取之前写入舵机的旋转角度(0°~180° )。 |
int readMicroseconds() | 获取之前写入舵机的脉冲宽度(以微秒 为单位)。 |
bool attached() | 如果舵机对象 Servo 成功绑定至UINIO-MCU-ESP32 的 GPIO 引脚,那么就会返回true 。 |
void detach() | 停止绑定 Servo 对象到 GPIO引脚,并且释放对于 LEDC 通道的占用。 |
setTimerWidth(value) | 设置 PWM 定时器输出的脉冲宽度。 |
int readTimerWidth() | 获取 PWM 定时器输出的脉冲宽度。 |
在使用上面表格当中的 void write()
函数指定舵机旋转角度的时候,传入的参数值会遵循如下的自动转换规则:
API | 功能描述 |
---|---|
< 0 | 0 |
0 - 180 | value (以度数为单位) |
181 - 499 | 180 |
500 - (min-1) | min |
min - max | value (以微秒为单位) |
(max + 1) - 2500 | max |
下面的伪代码简洁的演示了 ESP32Servo库的基本使用步骤,以及相关的重要 API 函数:
1 |
|
ESP32Servo 库的底层运用了定时器和LEDC 来控制 PWM 信号的生成,其中ESP32-C3 拥有 4 个定时器与 6 个独立的PWM 通道,而 ESP32-S3 同样拥有 4个定时器以及 8 个独立的 PWM通道,具体可以参见下面的示意图:
舵机通常拥有 PWM
、VCC
、GND
三路外接引脚,其中 VCC
需要连接到一个独立的 5V
电源(确保工作电流稳定),而舵机的 GND
引脚需要与UINIO-MCU-ESP32 的 GND
形成共地连接(作为 PWM 信号的电平基准),除此之外的PWM
则是属于用来输入 PWM 控制信号的引脚:
例如 SG90 和 MG996R型舵机的黄/橙色、红色、棕色杜邦线,就分别对应着舵机的PWM
、VCC
、GND
引脚。接下来,通过UINIO-MCU-ESP32 控制两个 SG90微型舵机,分别将两个舵机的 PWM
信号线连接至UINIO-MCU-ESP32 的 GPIO9
和GPIO10
引脚:
下面的这份示例代码,可以使得两个 SG90 微型舵机分别从0°
旋转到 180°
度,以及从 180°
旋转到 0°
度:
1 |
|
注意:由于 UINIO-MCU-ESP32C3采用了两线制 SPI 的 DIO模式,因而在运行上述示例程序的时候,需要将 Arduino IDE的 【Flash Mode】设置为
DIO
模式,否则会导致舵机程序无法正常工作。除此之外,因为UINIO-MCU-ESP32C3 的第GPIO11
、GPIO12
、GPIO13
引脚已经被用作 Flash 的 SPI 电源和信号引脚,所以无法用于控制舵机。
本节内容将会综合运用之前介绍过的 SG90 舵机和HC-SR04 超声波模组,基于UINIO-MCU-ESP32S3 实现一个能够自动打开盒盖的UINIO-Auto-Box
智能收纳盒子项目,这里假设盒盖关闭时候舵机的角度为 0°
度,而盒盖打开时候舵机的角度为 90°
度。当用手遮挡住超声波探头的时候,舵机旋转 90°
度打开盒盖。而当手离开之后,舵机就会回到 0°
度位置,表示已经自动关闭盒盖。
VCC
引脚连接到UINIO-MCU-ESP32S3 的 5V
引脚,而PWM
引脚连接到 GPIO7
引脚,除此之外两者的GND
相互连接形成共地关系。VCC
引脚连接到UINIO-MCU-ESP32S3 的 3V3
引脚,而Trig
引脚连接至 GPIO6
,Echo
引脚连接至 GPIO5
,同样 GND
相互连接形成共地关系。打开 Arduino IDE 新建一个名为UINIO-Auto-Box
的草图工程,其主程序会被自动命名为UINIO-Auto-Box.ino
,然后手动添加超声波传感器相关的Sonar.h
与 Sonar.cpp
源文件,盒盖控制相关的 Cover.h
与Cover.cpp
源文件,以及舵机控制相关的Servo.h
与 Servo.cpp
源文件,最后生成的工程结构如下面所示:
1 | D:\Workspace\UINIO-Auto-Box |
.cpp
源文件当中,然后在对应的 .h
头文件当中将其声明为extern
外部变量。.ino
草图文件添加依赖的头文件,而在 .h
和 .cpp
源文件当中使用信号量相关的方法时,就需要手动包含源文件#include <freertos/FreeRTOS.h>
和#include <freertos/semphr.h>
,并且#include <freertos/FreeRTOS.h>
必须放置在<freertos/semphr.h>
之前。而在使用定时器相关的方法时,则需要手动包含源文件#include <esp32-hal-timer.h>
。Events Run On: "Core 0"
和Arduino Runs On: "Core 1"
,才能够正确的运行本节的示例程序。注意:由于 UINIO-MCU-ESP32C3 属于RISC-V架构的单核微控制器,所以无法正常运行本节的示例程序。如果强行上传示例程序,串口会打印出错误信息:
Guru Meditation Error: Core 0 panic'ed (Load access fault). Exception was unhandled.
。
1 | /*========== 主程序 ==========*/ |
1 | /*========== Cover.h ==========*/ |
1 | /*========== Cover.cpp ==========*/ |
1 | /*========== Servo.h ==========*/ |
1 | /*========== Servo.cpp ==========*/ |
1 | /*========== Sonar.h ==========*/ |
1 | /*========== Sonar.cpp ==========*/ |
串行外设接口(SPI,SerialPeripheralInterface)是一种高速、全双工、同步通信总线,其优点在于支持全双工通信(可以同时进行数据的接收与发送),数据传输速率相对I²C总线更加迅速,不过其缺点在于没有应答机制(无法判断数据是否准确收发)。
SPI总线通信协议只允许一个主设备,但是可以存在多个从设备,其一共拥有着四条物理信号线:
SCK
;主设备
输出,从设备
输入,也称为SDO (Slave Device Output);主设备
输入,从设备
输出,也称为SDI (Slave Device Input);除了 CS/SS 片选信号线需要每一台 从设备
都与 主设备
进行单独连接之外,其它的SCLK/SCK、MOSI/SDO、MISO/SDI三条信号线都分别各自连接到一起:
SPI总线上的主设备与从设备都分别内置有串行移位寄存器,主设备向该寄存器写入1
个字节数据,就会进行一次数据传输:
CS
片选信号线拉低,开始与其进行通信。SCLK
时钟信号,开始准备对从设备进行读写操作(时钟信号是高电平
还是低电平
有效,称为时钟极性)。串行移位寄存器
,将数据从MOSI
信号线逐位发送给从设备;同时主设备也可以把MISO
信号线上待接收的从设备数据,同样通过串行移位寄存器
逐位移动到接收缓冲区。串行移位寄存器
里的内容,通过MISO
信号线返回给主设备;并且同样也可以通过MOSI
信号线接收主设备发送过来的数据(数据是在时钟信号的上升沿还是下降沿处理,称为时钟相位)。SCLK
时钟脉冲,SPI 总线上就可以接收或者发送1bit
数据。在上述 SPI通信过程当中,时钟极性和时钟相位是非常重要的两个概念:
SCLK
处于高电平还是低电平;如果CPOL = 0
,那么时钟信号在总线空闲时处于低电平;如果CPOL = 1
,那么时钟信号在总线空闲时则处于高电平;CPHA = 0
,那么在时钟信号 SCLK
的第 1个跳变沿采样,第 2个跳变沿被改变;如果CPHA = 0
,那么在时钟信号 SCLK 的第 1个跳变沿被改变,第 2个跳变沿采样;注意:上图当中的红色竖线代表数据采样(Sampled)的位置,而蓝色代表数据被改变(Launched)的位置。
根据 SPI总线的时钟极性与时钟相位,可以划分出四种不同的SPI总线通信工作模式,它们分别定义了在时钟信号的哪个边沿采样信号,哪个边沿改变信号:
模式 | 时钟极性与相位 |
---|---|
Mode 0 | CPOL = 0 ,CPHA = 0 |
Mode 1 | CPOL = 0 ,CPHA = 1 |
Mode 2 | CPOL = 1 ,CPHA = 0 |
Mode 3 | CPOL = 1 ,CPHA = 1 |
除此之外,在 SPI串行通信过程当中,当前是最高有效位(MSB,MostSignificantBit)优先传输,还是最低有效位(LSB,LeastSignificantBit)优先传输是非常重要的两个关键因素,收发双方必须保持传输时序的一致:
注意:SPI 通信涉及的所有 API函数都不能放置到中断服务程序当中,否则将会导致程序报错。
由于乐鑫早期的 ESP32 芯片(例如ESP32-D0WD-V3
、ESP32-D2WD
、ESP32-S0WD
、ESP32-U4WDH
),分别使用了HSPI 和 VSPI 来指代 SPI2
和 SPI3
外设:
官方的 Arduino-ESP32库出于兼容性考虑延续了这种叫法,它们默认的 GPIO引脚编号,如下面的表格所示:
分类 | 主机输入从机输出引脚 | 主机输出从机输入引脚 | 时钟引脚 | 片选引脚 |
---|---|---|---|---|
VSPI | MISO = 19 | MOSI = 23 | SCLK = 18 | CS = 5 |
HSPI | MISO = 12 | MOSI = 13 | SCLK = 14 | CS = 15 |
ESP32-C3 芯片集成有SPI0
、SPI1
、SPI2
三个 SPI总线控制器,因为 SPI0
和 SPI1
主要用于访问外部Flash 以及 PSRAM,所以仅有 SPI2
可以供用户配置使用(即GP-SPI2)。
而 ESP32-S3 芯片集成有SPI0
、SPI1
、SPI2
、SPI3
四个 SPI 总线控制器,同样因为 SPI0
和 SPI1
被用于访问外部 Flash 以及 PSRAM,所以仅有SPI2
、SPI3
可以供用户配置使用(即GP-SPI2 和 GP-SPI3)。
观察上述 ESP32-C3 和 ESP32-S3 的SPI 系统框图可以发现,两者都将 GP-SPI2
称为FSPI(Fast SPI),因而在随后的主设备 SPI官方库示例代码当中,宏定义里才会出现 #define VSPI FSPI
这样的语句。
注意:ESP32-C3 与ESP32-S3工作在主设备模式下的时钟频率都可以达到
80 MHz
,而工作在从设备模式下的时钟频率也可以达到60 MHz
。
Arduino-ESP32 封装的 SPI库已经提供了主设备 SPI 总线通信的支持,使用时只需要包含<SPI.h>
头文件即可,相关的方法都已经被封装至SPIClass
类:
1 | SPIClass *vspi = new SPIClass(VSPI); |
Arduino-ESP32 内部已经定义有一个SPIClass SPI = new SPIClass(VSPI)
,可以在代码当中直接使用SPI
对象控制总线通信,下面的伪代码展示了 SPI主设备通信的基本过程:
1 |
|
下面的代码详细展示了 UINIO-MCU-ESP32S3 使用Arduino-ESP32 库进行 SPI 主设备通信的整个步骤,由于UINIO-MCU-ESP32C3 只存在一个 HSPI
可以供用户配置使用,运行下面代码会导致'VSPI' was not declared in this scope
错误的出现:
1 |
|
接下来介绍一下 Arduino-ESP32 当中 SPI内置的相关方法,首先 SPISettings
类用于配置 SPI总线通信端口的相关参数(默认的时钟频率clock
为 1MHz
、传输顺序bitOrder
为高位优先
、时钟的极性与相位模式dataMode
为 MODE0
):
SPISettings 构造函数 | 功能描述 |
---|---|
SPISettings(uint32_t clock, uint8_t bitOrder, uint8_t dataMode) | SPI总线配置参数的载体,三个参数的默认值分别为1000000 、SPI_MSBFIRST 、SPI_MODE0 。 |
除此之外,Arduino-ESP32 库还通过SPIClass
类,提供了丰富的 SPI通信相关的工具函数,具体如下面的表格所示:
SPIClass 中的主要 API | 功能描述 |
---|---|
void begin(int8_t sck=-1, int8_t miso=-1, int8_t mosi=-1, int8_t ss=-1) | 初始化 SPI 总线。 |
void end() | 结束 SPI 总线的资源占用。 |
void beginTransaction(SPISettings settings) | 使用 SPISettings 作为参数,开始进行 SPI 总线通信。 |
void endTransaction(void) | 结束 SPI 总线通信。 |
int8_t pinSS() | 返回 SPI 片选引脚。 |
SPIClass 中的 Transfer API | 功能描述 |
---|---|
void transfer(void * data, uint32_t size) | 发送 size 个字节的data 数据,但是并不会接收数据。 |
uint8_t transfer(uint8_t data) | 发送 1 个字节的 data 数据,同时接收 1 个字节的数据。 |
uint16_t transfer16(uint16_t data) | 发送 2 个字节的 data 数据,同时接收 2 个字节的数据。 |
uint32_t transfer32(uint32_t data) | 发送 4 个字节的 data 数据,同时接收 4 个字节的数据。 |
void transferBytes(const uint8_t * data, uint8_t * out, uint32_t size) | 接收 size 个字节到读取缓冲区 data ,或者发送size 个字节到输出缓冲区out 。 |
void transferBits(uint32_t data, uint32_t * out, uint8_t bits) | 接收 size 位数据到读取缓冲区 data ,或者发送size 位数据到输出缓冲区out 。 |
SPIClass 中的 Write API | 功能描述 |
---|---|
void write(uint8_t data) | 发送 1 个字节的 data 数据,但是不会接收数据。 |
void write16(uint16_t data) | 发送 2 个字节的 data 数据,但是不会接收数据。 |
void write32(uint32_t data) | 发送 4 个字节的 data 数据,但是不会接收数据。 |
void writeBytes(const uint8_t * data, uint32_t size) | 发送 size 个字节的data 数据,但是不会接收数据。 |
void writePattern(const uint8_t * data, uint8_t size, uint32_t repeat) | 循环发送 size 个字节的data 数据 repeat 次,但是不会接收数据。 |
void writePixels(const void * data, uint32_t size) | 请参考用户目录USER\AppData\Local\Arduino15\packages\esp32\hardware\esp32\2.0.9\libraries\SPI\src 下面的源码。 |
由于 Arduino-ESP32 官方库只支持把ESP32 芯片作为 SPI主设备来使用,并未提供 SPI 从设备通信相关的API,需要在 Arduino IDE 当中安装第三方库 ESP32SPISlave。由于该库目前仅支持诸如ESP32-D0WD-V3
、ESP32-D2WD
、ESP32-S0WD
、ESP32-U4WDH
等较老型号的 ESP32 系列,暂不支持相对较新的ESP32-C3 与 ESP32-S3 芯片。如果在Arduino IDE当中选择以这两款芯片作为主控的开发板,那么就会导致编译错误的出现。所以在接下来的示例当中,都会以乐鑫官方采用ESP32-D0WD 主控的 ESP32-DevKitC开发板作为 SPI 总线从设备:
ESP32SPISlave 库可以支持以阻塞式等待的方式访问 SPI传输事务队列:
1 |
|
相对应的,也能够支持以轮询的方式访问 SPI传输事务队列:
1 |
|
或者是以任务的方式访问 SPI 传输事务队列:
1 |
|
接下来的一系列表格当中,展示了 ESP32SPISlave库当中提供的一系列 API 函数:
SPI 总线配置 API | 功能描述 |
---|---|
bool begin(const uint8_t spi_bus = HSPI) | 使用默认的 HSPI 或者VSPI 作为 SPI 通信引脚。 |
bool begin(const uint8_t spi_bus, const int8_t sck, const int8_t miso, const int8_t mosi, const int8_t ss) | 自定义 SPI 通信引脚。 |
void setDataMode(const uint8_t m) | 设置 SPI 数据模式(SPI时钟的极性与相位)。 |
void setSpiMode(const uint8_t m) | 设置 SPI 工作模式。 |
void setSlaveFlags(const uint32_t flags) | 设置从设备标记。 |
void setQueueSize(const int n) | 设置队列大小。 |
bool end() | 结束 SPI 传输。 |
SPI 传输事务 API | 功能描述 |
---|---|
bool wait(uint8_t* rx_buf, const size_t size) | 阻塞式等待传输事务,只接收不发送,成功返回true ,失败返回 false 。 |
bool wait(uint8_t* rx_buf, const uint8_t* tx_buf, const size_t size) | 阻塞式等待传输事务,即接收也发送,成功返回true ,失败返回 false 。 |
bool queue(uint8_t* rx_buf, const size_t size) | 添加传输事务,只接收不发送,成功返回true ,失败返回 false 。 |
bool queue(uint8_t* rx_buf, const uint8_t* tx_buf, const size_t size) | 添加传输事务,即接收也发送,成功返回true ,失败返回 false 。 |
void yield() | 等待主设备处理完毕所有传输事务,如果yield 完成,则更新全部缓冲区。 |
SPI 传输结果信息 API | 功能描述 |
---|---|
size_t available() const | 如果主设备的传输事务已经结束,那么从设备的available() 就会返回传输的结果数量,并且自动更新spi_slave_rx_buf 接收缓冲区。 |
size_t remained() const | 判断传输队列当中剩余的事务数量。 |
uint32_t size() const | 从传输队列当中接收到的字节数量。 |
void pop() | 获取从设备接收缓冲区当中的数据。 |
注意:SPI 传输涉及的 API中都以传输事务作为基础,当主设备拉低片选线,并且时钟线上发出脉冲信号时,就开始了1 次全双工的 SPI 传输事务。每一个时钟脉冲都意味着主设备通过
MOSI
线发送1
个数据位到从设备,并且同时从设备通过MISO
线返回1
个数据位。当传输事务结束之后,主设备就会拉高片选线。每一次 SPI总线传输事务,主设备与从设备所能传输的最大数据量为64
字节,如果需要传输更大的数据,则必须借助 DMA方式进行。
本小节将会基于 SPI 总线实现UINIO-MCU-ESP32S3(主设备)与ESP32-DevKitC(从设备)之间的相互通信,把两块核心板的HSPI/SPI2 按照下图关系相互连接,即UINIO-MCU-ESP32S3 的SCLK = 21
、MISO = 20
、MOSI = 19
、SS = 18
与 ESP32-DevKitC 的SCLK = 14
,MISO = 12
,MOSI = 13
,SS = 15
一一对应连接。同时两者的 GND
也要连接到一起,从而形成共地连接关系:
让主设备每间隔 1
秒钟,向从设备发送小写英文字符串,从设备接收之后将其转换为大写形式再返还给主设备,主设备将接收到的大写字符串打印至Arduino IDE 的【串口监视器】。接下来,分别在Arduino IDE 当中新建 3 份草图源文件,它们分别是用于 SPI主设备的 SPIMaster.ino
、从设备(采用阻塞等待处理方式)的SPISlaveWait.ino
、从设备(采用队列处理方式)的SPISlaveQueue.ino
:
采用 UINIO-MCU-ESP32S3 作为 SPI 主设备,基于Arduino-ESP32 官方库提供的 SPI 通信 API与从设备进行数据交互。
1 | /*========== SPIMaster.ino(主设备) ==========*/ |
采用 ESP32-DevKitC 作为 SPI 从设备,基于ESP32SPISlave 库提供的 wait()
方法,以阻塞等待的方式与主设备进行通信:
1 | /*========== SPISlaveWait.ino() ==========*/ |
采用 ESP32-DevKitC 作为 SPI 从设备,基于ESP32SPISlave 库提供的 queue()
方法与主设备进行通信,由于队列方式只能同时处理 3 个 SPI传输任务。所以从设备需要初始化出 3个传输任务,然后逐一用于处理数据的收发。
1 | /*========== SPISlaveQueue.ino ==========*/ |
本节内容介绍的这款 SD 存储卡模组,可以使得UINIO-MCU-ESP32 通过 SPI 接口以及文件系统读写 SD存储卡(同时支持普通 Micro SD 和高速 MicroSDHC 存储卡)。该款模组还板载有电平转换芯片,可以同时兼容5V
和 3.3V
规格的电平信号。而自带的3.3V 线性稳压器,也可以使其分别工作于 5V
和 3.3V
电源下。
这款 SD 存储卡模组 一共拥有六个外接引脚,它们分别是GND
,VCC
,MISO
,MOSI
,SCK
,CS
,具体的引脚排列顺序可以参考下图:
笔者目前使用 Arduino-ESP32 库的 2.0.11
版本,已经基于 SPI 总线通信,提供了对于 SD卡操作的支持(可以支持中文文件名,以及 UTF-8编码的文件内容),使用时只需要在 Arduino 草图源文件当中包含SPI.h
和 SD.h
头文件即可。由于截止到 2023 年 8月为止,该库依然还处于开发状态,官方并未提供详尽的 API文档说明,只是提供了一份比较典型的 SD卡读写示例代码。接下来就基于这份代码,以自定义 SPI通信引脚的方式,读写一颗文件系统为 FAT32,存储容量为32GB
的 TF 存储卡:
首先把 UINIO-MCU-ESP32 的引脚SS = GPIO0
、SCLK = GPIO1
、MOSI = GPIO2
、MISO = GPIO3
分别与读卡器模块的CS
、SCK
、MOSI
、MISO
引脚相互连接,然后再将读卡器模组的 VCC
和 GND
分别接入至 UINIO-MCU-ESP32 的 5V
和GND
电源,最后就可以下载并且运行这份参考代码:
1 |
|
上述代码下载执行之后,测试用的 SD 卡上面会生成一个内容为您好,电子技术博客 UinIO.com!
的文件UinIO.txt
,以及通过文件输入输出写入了内容为空的成都.txt
文件,同时会以 115200
波特率向串口打印如下一系列执行结果:
1 | SD 卡类型: SDHC 存储卡 |
注意:如果串口打印出的调试内容提示
存储卡挂载失败!
,那么可以将这片 SD卡拔出之后重新插入,然后按下 UINIO-MCU-ESP32核心板上面的 RESET 按钮,重新执行上述程序。
因为 ESP32-Arduino 官方库的 SD 卡相关 API暂时还不够完善,所以本节内容将会介绍功能更加丰富的 SdFat 库,可以同时支持SD、SDHC、SDXC类型的存储卡,以及FAT16、FAT32、exFAT文件系统。该库的 API 文档可以访问 SdFat 源文件 的\doc
目录下,压缩文件 html.zip
当中的index.html
。总体上来看,SdFat 库是通过SdFat32
、SdExFat
、SdFs
三个类来分别代表不同的存储卡文件系统:
SdFs
类:用于支持 FAT16 和FAT32 以及 exFAT文件系统,对应的文件类为 FsFile
;SdFat32
类:用于支持 FAT16 和FAT32 文件系统,对应的文件类为File32
;SdExFat
类:用于支持 exFAT文件系统,对应的文件类为 ExFile
;该库可以方便的通过 Arduino IDE的【库管理器】进行安装,安装之后需要修改 Arduino 项目文件夹libraries\SdFat\src
下的 SdFatConfig.h
头文件,将宏定义 #define USE_UTF8_LONG_NAMES
的值修改为1
,即采用 UTF-8格式编码所有字符串,从而能够自由的使用中文字符。除此之外,通过修改SdFatConfig.h
头文件中 SPI_DRIVER_SELECT
宏定义的值,还可以选择当前是使用 SPI 硬件总线(使用 SPI控制器默认的引脚)还是 SPI 软件总线(自定义 SPI通信引脚):
0
:如果存在优化的自定义 SPI驱动程序,则使用它,否则使用标准库驱动程序。1
:总是使用标准库驱动程序。2
:总是使用 SoftSpiDriver 模板类的外部 SPI驱动程序。3
:总是使用从 SdSpiBaseClass 类派生的外部 SPI驱动程序。接下来,我们把 SdFatConfig.h
头文件里的SPI_DRIVER_SELECT
配置为 2
,而#define USE_UTF8_LONG_NAMES
的值配置为1
,同时依然将 UINIO-MCU-ESP32 的SS = GPIO0
、SCLK = GPIO1
、MOSI = GPIO2
、MISO = GPIO3
与读卡器模块的CS
、SCK
、MOSI
、MISO
引脚连接,而读卡器模块的 VCC
和 GND
则分别接入UINIO-MCU-ESP32 的 5V
和 GND
进行供电,最后就可以编写并且执行如下的参考代码:
1 |
|
UINIO-MCU-ESP32开始运行上述代码之后,可以打开一个第三方的串口上位机程序(例如VOFA+ 或者COMTransmit),首先将其波特率设置为115200
,然后手动向串口上位机的【发送窗口】输入test
并且按下发送,此时 UINIO-MCU-ESP32就会自动向 SD存储卡写入内容:欢迎访问 UinIO.com,获取技术分享文章,以及更多有趣的开源项目。
,同时串口上位机的【接收窗口】会打印出如下信息:
1 | ESP-ROM:esp32s3-20210327 |
注意:DSPI(DualSPI)常用于 SPI 总线通信的 Flash 存储器,由于 Flash存储器无需使用全双工通信,所以 DSPI 将
MOSI
和MISO
都作为并行数据传输线,从而工作在半双工模式下,可以达到在单个时钟周期内,双倍提升数据传输速率的目的。
FreeRTOS是一款适用于微控制器和小型微处理器的嵌入式实时操作系统(RTOS,Real-timeOperatingSystem),其提供了任务
与通知
、队列
、流缓冲区
、消息缓冲区
、信号量
/互斥锁
、软件定时器
、事件组
等丰富特性,可以协助开发人员在资源受限的嵌入式场景下,实现稳定可靠的实时任务调度与协作。当Arduino IDE 成功安装 Arduino-ESP32之后,就会在如下目录里发现 ESP32-C3 和ESP32-S3 源码实现都内嵌有FreeRTOS。
C:\Users\Hank\AppData\Local\Arduino15\packages\esp32\hardware\esp32\2.0.11\tools\sdk\esp32c3\include\freertos
;C:\Users\Hank\AppData\Local\Arduino15\packages\esp32\hardware\esp32\2.0.11\tools\sdk\esp32s3\include\freertos
;相应的,Arduino-ESP32 当中所使用的FreeRTOS 都会通过头文件 FreeRTOSConfig.h
来进行配置,其位置位于 Arduino-ESP32用户安装目录的如下路径:
FreeRTOSConfig.h
:Arduino15\packages\esp32\hardware\esp32\2.0.11\tools\sdk\esp32c3\include\freertos\include\esp_additions\freertos\FreeRTOSConfig.h
;FreeRTOSConfig.h
:Arduino15\packages\esp32\hardware\esp32\2.0.11\tools\sdk\esp32s3\include\freertos\include\esp_additions\freertos\FreeRTOSConfig.h
;例如 Arduino-ESP32 当中的 loop()
函数,就是通过在 FreeRTOS 当中创建一个优先级为1
的任务来进行执行的。也正是因为如此,我们同样可以在Arduino 草图代码当中引入 FreeRTOS 相关的头文件来使用其相关的特性。
注意:当前本文使用的 Arduino-ESP32版本为
2.0.11
,其内嵌的 FreeRTOS 版本为V10.4.x
。
当 Arduino IDE 安装了 Arduino-ESP32之后,菜单栏的上【工具】下就会出现一系列配置选项。对于UINIO-MCU-ESP32S3这样的多核微控制器,就可以发现如下两条配置项:
上述两个配置项的值可以分别被指定为Core 0
和 Core 1
,除此之外,由于Arduino-ESP32 库在底层实现上,使用了嵌入式实时操作系统FreeRTOS,所以在 Arduino草图代码也可以通过包含如下两个头文件,以使用其提供的多任务处理函数:
1 |
Arduino-ESP32 当中可以通过xTaskCreatePinnedToCore()
函数创建一个任务,如果任务创建成功,则会返回pdPASS
,否则表示创建失败:
1 | BaseType_t xTaskCreatePinnedToCore( |
任务创建之后,就可以通过 vTaskDelete()
函数结束并且删除掉一个任务:
1 | void vTaskDelete( |
除此之外,还可以利用 uxTaskPriorityGet()
返回参数任务XTask
的优先级:
1 | UBaseType_t uxTaskPriorityGet( |
以及使用 XPortGetCoreID()
返回当前任务运行于哪一个微控制器内核:
1 | BaseType t IRAM ATTR XPortGetCoreID( void ); |
在接下来的示例代码当中,通过直接包含 FreeRTOS 配置文件FreeRTOSConfig.h
的方式(也可以采用分别包含FreeRTOS.h
和 task.h
两个头文件的方式),展示了如何基于采用 ESP32-S3多核微控制器的 UINIO-MCU-ESP32S3 进行多任务的处理:
1 |
|
将上述代码下载到 UINIO-MCU-ESP32S3上面,核心板就会每间隔 2 秒,以 115200
波特率向Arduino IDE 的串口监视器打印如下内容:
1 | Task-1 任务运行在:Core 0 |
FreeRTOS 提供的互斥锁机制是一种包含有优先级继承机制的二进制信号量,之前介绍过的二进制信号量可以用于实现任务与任务,以及任务与中断之间的同步。而互斥锁则有助于更好的实现资源的互斥访问,它就像是保护互斥资源的一个令牌,当任务需要访问资源时,必须首先获取这个令牌;而在使用完资源之后,则必须返回这个令牌,从而使得其它任务能够继续访问该资源。
Arduino-ESP32 可以通过xSemaphoreCreateMutex()
函数创建一个互斥锁,执行之后就会返回这个互斥锁的句柄:
1 | SemaphoreHandle_t xSemaphoreCreateMutex( void ); |
在创建信号量之后,接下来就可以通过 xSemaphoreTake()
函数获取互斥锁信号量,如果获取成功就返回pdTRUE
,如果获取失败则返回 pdFALSE
:
1 | xSemaphoreTake( |
除此之外,互斥锁信号量可以通过 xSemaphoreGive()
函数进行释放,信号量释放成功就返回pdTRUE
,如果发生错误则返回 pdFALSE
:
1 | xSemaphoreGive( |
下面的伪代码,简单明了的展示了互斥锁信号量的典型使用方法:
1 | /* 获取互斥锁信号量 */ |
接下来的示例代码当中,通过使用互斥信号量确保了 Task-1
和Task-2
两个任务,对于互斥资源变量 number
的同步访问:
1 |
|
注意:不能在中断服务程序当中使用FreeRTOS 的互斥锁信号量。
Arduino-ESP32 提供了一系列 WIFI相关的 API,支持 802.11b/g/n 无线局域网标准,可以用于扫描WIFI 接入点,也支持WPA2、WPA3 等 WIFI安全模式,除此之外还提供了 WIFI 的 STA 和AP 两种工作模式:
Wi-Fi 客户端模式,也被称为 STA模式(Station mode),这种模式支持把 ESP32 连接到一个 WIFI 接入点。
Wi-Fi 接入点模式,也被称为 AP模式(Access Point mode),这种模式下 ESP32被配置为一个接入点,可以通过提供 Wi-Fi 局域网接收其它设备的连接。
通用 API | 功能描述 |
---|---|
wifi_event_id_t onEvent(WiFiEventCb, arduino_event_id_t = ARDUINO_EVENT_MAX) | 注册一个 WIFI 事件回调函数。 |
void removeEvent(WiFiEventCb, arduino_event_id_t = ARDUINO_EVENT_MAX) | 移除一个 WIFI 事件回调函数。 |
setHostname(const char *hostname) | 设置 DHCP 客户端标识。 |
const char *getHostname() | 获取 DHCP 客户端标识。 |
static void useStaticBuffers(bool bufferMode) | 设置 Wi-Fi缓冲区的内存分配方式,true 为静态,而 false 为动态。 |
bool setDualAntennaConfig(uint8_t gpio_ant1, uint8_t gpio_ant2, wifi_rx_ant_t rx_mode, wifi_tx_ant_t tx_mode) | 配置双天线功能,仅支持带有 RF 开关的 ESP32使用。 |
AP 模式 WIFI 相关 API | 功能描述 |
---|---|
WiFi.softAP(ssid, password) | 启动 Wi-Fi 作为接入点。 |
bool softAP(const char* ssid, const char* passphrase = NULL, int channel = 1, int ssid_hidden = 0, int max_connection = 4, bool ftm_responder = false) | 配置 Wi-Fi 的 AP 特性 |
bool softAPConfig(IPAddress local_ip, IPAddress gateway, IPAddress subnet) | 用于配置静态 IP、网关、子网。 |
bool softAPdisconnect(bool wifioff = false) | 强制断开 AP 连接。 |
uint8_t softAPgetStationNum() | 返回当前连接到 AP 的客户端数量。 |
IPAddress softAPIP() | 获取 AP 的 IPv4 地址。 |
IPAddress softAPBroadcastIP() | 获取 AP 的 IPv4 广播地址。 |
IPAddress softAPNetworkID() | 获取 AP 网络的 ID。 |
uint8_t softAPSubnetCIDR() | 获取 AP 网络的子网 CIDR。 |
IPAddress softAPSubnetMask() | 获取 AP 网络的子网掩码。 |
bool softAPenableIpV6() | 启用 IPv6 支持。 |
IPv6Address softAPIPv6() | 获取 IPv6 地址。 |
bool softAPsetHostname(const char * hostname) | 设置 AP 的主机名称。 |
const char * softAPgetHostname() | 获取 AP 的主机名称。 |
uint8_t* softAPmacAddress(uint8_t* mac) | 设置或者获取 AP 的 MAC 地址。 |
String softAPSSID(void) const | 获取 AP 网络的 SSID。 |
STA 模式 WIFI 相关 API | 功能描述 |
---|---|
wl_status_t begin(const char* ssid, const char *passphrase = NULL, int32_t channel = 0, const uint8_t* bssid = NULL, bool connect = true); | 启动 Wi-Fi 连接。 |
bool config(IPAddress local_ip, IPAddress gateway, IPAddress subnet, IPAddress dns1 = (uint32_t)0x00000000, IPAddress dns2 = (uint32_t)0x00000000) | 配置 IP 地址、网关、子网、DNS 信息。 |
IPAddress(uint8_t first_octet, uint8_t second_octet, uint8_t third_octet, uint8_t fourth_octet) | IPAddress 格式由 4个字节进行定义。 |
bool reconnect() | 重新连接 Wi-Fi。 |
bool disconnect(bool wifioff = false, bool eraseap = false) | 强制断开 Wi-Fi 连接。 |
bool isConnected(); | 获取 Wi-Fi 连接状态。 |
bool setAutoReconnect(bool autoReconnect) | 设置连接丢失时,是否开启自动重新连接。 |
bool getAutoReconnect() | 获取连接丢失时,自动重连的设置状态。 |
bool setMinSecurity(wifi_auth_mode_t minSecurity) | 设置 AP 连接的最低安全性,默认为WIFI_AUTH_WPA2_PSK 。 |
WiFiMulti 相关 API | 功能描述 |
---|---|
bool addAP(const char* ssid, const char *passphrase = NULL) | 添加多个 AP 接入点。 |
uint8_t run(uint32_t connectTimeout=5000) | 开始运行 WiFiMulti。 |
WiFiScan 相关 API | 功能描述 |
---|---|
int16_t scanNetworks(bool async = false, bool show_hidden = false, bool passive = false, uint32_t max_ms_per_chan = 300, uint8_t channel = 0) | 开始扫描可用的 WiFi 网络。 |
int16_t scanComplete() | 采用异步模式获取扫描状态。 |
void scanDelete() | 删除 RAM 当中的最后一次扫描结果。 |
bool getNetworkInfo(uint8_t networkItem, String &ssid, uint8_t &encryptionType, int32_t &RSSI, uint8_t* &BSSID, int32_t &channel) | 获取扫描到的 WIFI 网络信息。 |
提供了 WIFI 接入点,并且运行了一个 Web服务器,http://192.168.4.1/H
去打开 LED on orhttp://192.168.4.1/L
ESP32-Arduino 内嵌有一个开源的 HttpClient库,可以方便的与 Web 服务器进行交互。下面的示例代码会通过 WIFI局域网,不断的向 http://www.uinio.com
地址发起一个HTTP GET 请求:
1 |
|
除此之外,配合第三方 JSON 解析库 ArduinoJson 使用,还可以方便的以POST 方式传输 JSON格式的数据。下面的示例代码,将会携带一个包含有 data
属性的JSON 对象参数,向远程服务器的 http://192.168.1.1:8080/test
接口发起一个 HTTP POST请求,并且将响应的结果打印出来:
1 |
|
近几年低压差稳压器(LDO,LowDropoutRegulator)被广泛应用在微控制器电路当中,其主要特点在于输入电压与输出电压之间的压差\(V_{DROPOUT}\)非常小(通常在几十毫伏到几百毫伏范围)。在上述的 LDO原理示意图当中,绿色的误差放大器通过改变内部的可变电阻,就能够达到了稳定输出电压\(V_{OUT}\) 的目的(其中 \(RDS_{ON}\) 包含了 LDO内部的调整元件电阻
、片内互连电阻
、引脚电阻
、线焊电阻
)。
AMS 公司(Advanced Monolithic Systems)的 AMS1117是一款比较经典的线性稳压器。除此之外,德州仪器TLV1117、安森美NCP1117、微盟电子ME1117、长晶科技CJT1117 也推出了类似命名的 Pin-to-Pin产品。SOT-223 是 1117系列芯片的典型封装形式,下面的示意图对其引脚的功能进行了说明:
而下面的原理图是固定电压输出版本1117 的典型应用电路,这里推荐使用 10uF
的钽电容作为旁路电容 \(C_1\),以及 10uF
的钽电容作为输出电容 \(C_2\):
而下面的原理图则是可调电压输出版本1117 的典型应用电路,其输出电压公式为 \(V_{OUT} = V_{REF} \times (1 + \frac{R_2}{R_1}) +I_{ADJ} \times R_2\)。公式当中的 \(I_{ADJ}\)(约50uA
)通常可以被忽略,因为其值远远小于 \(R_1\) 上面的电流(约2mA ~ 10mA
)。
1117系列线性稳压器的输出电压精度,通常为标称电压值的 \(\pm 1.5 \%\) 左右,即如果标称输出电压为3.3V
,那么实际的输出电压应当介于 3.25V ~ 3.35V
之间:
元件型号 | 空载输出电压 | 满载输出电压 |
---|---|---|
AMS1117 | 3.33V | 3.3V |
TLV1117 | 3.27V | 3.26V |
NCP1117 | 3.31V | 3.3V |
ME1117 | 3.28V | 3.26V |
CJT1117 | 3.32V | 3.32V |
注意:空载输出是指稳压器在输出电流为
0mA
时的输出电压值,而满载输出则是指 1117芯片在输出电流为800mA
时的输出电压值。
输出纹波用于衡量线性稳压器输出电压的平稳程度,是一个叠加在直流稳定值之上的交流分量。通常只需要把这种纹波控制在20mV
以内,就能够满足正常的使用。
元件型号 | 空载输出电压纹波 | 满载输出电压纹波 |
---|---|---|
AMS1117 | 17.6mV | 19.2mV |
TLV1117 | 16.2mV | 18.4mV |
NCP1117 | 15.8mV | 16.8mV |
ME1117 | 16.7mV | 17.6mV |
CJT1117 | 16.2mV | 16.8mV |
因为线性稳压器的后级负载通常是动态变化的,所以就会导致其输出电压发生波动,这种波动是衡量线性稳压器性能一个非常重要的参数。
元件型号 | 波动电压大小 |
---|---|
AMS1117 | 344mV |
TLV1117 | 94mV |
NCP1117 | 134mV |
ME1117 | 216mV |
CJT1117 | 172mV |
注意:通常 1117系列的输出电容都会要求使用钽电容,而非相同容值的陶瓷电容,这是因为钽电容的寄生电阻较大,而陶瓷电容的寄生电阻较小。换而言之1117系列的电源环路稳定性,非常依赖于拥有更大寄生电阻的钽电容,从而提升其动态响应性能。
1A
,但是当在 5V
转 3.3V
且输出电流为 800mA
的时候,芯片的发热温度将会达到130°C
左右,所以尽量不要让 1117 去负载高于1W
的功率;低压差稳压器(LDO,Low DropoutRegulator)相对于传统的线性稳压器而言,输入与输出之间的电压差更小。传统的78xx 系列线性稳压器,其输入电压至少要比输出电压高出2V ~ 3V
。即便是要求更低一些的 1117系列,其压差也至少应在 1V
以上。这种情况对于5V
转 3.3V
的场景,其输入与输出之间的压差仅有1.7V
,显然无法满足正常工作的要求,因此 LDO低压差稳压器应运而生,下面表格展示市场上常见的三款 LDO芯片的性能参数:
LDO 型号 | 封装形式 | 静态电流 | 输出纹波 | 动态响应 | 输出精度 |
---|---|---|---|---|---|
XC6206 | SOT-23-3 | 1.4uA | < 5mV | 680mV | 0.6% |
ME6206 | SOT-23-3 | 8.3uA | < 5mV | 11.6mV | 0.9% |
ME6211 | SOT-23-5 | 36.9mA | < 5mV | 18.2mV | 0.6% |
注意:当上述芯片的输出电流为
100mA
的时候,发热温度约等于55°C
,而当输出电流达到200mA
的时候,则发热温度也将会达到76°C
,高于这个温度就需要考虑加装散热装置,并且选用更加有利于散热的PCB 布局。
5V
转 3.3V
的情况下,最大输入电流应当控制在200mA
以内。如果需要使用更大的输出电流,则可以考虑使用1117 系列;ENABLE
控制引脚(关断之后电流较小),如果需要控制输出就选择SOT-23-5 封装,如果希望更小的封装,则可以选择SOT-23-3 封装;特瑞仕XC6206 系列是一款高精度低功耗的 LDO线性稳压芯片,即使在输出电流较大的情况下,其输入与输出之间的压差依然较小。其常见的SOT-23-3 封装通常拥有输入
、输出
、接地
三个引脚,内部包含有限流电路、驱动三极管、高精度参考电压源、误差校正电路等单元电路:
XC6206系列稳压芯片的主要性能参数如下面的表格所示:
参数名称 | 参数值 |
---|---|
最大输出电流 | 200mA (3.0V type) |
输入输出压差 | 250mV @ 100mA (3.0V type) |
最大工作电压 | 6.0V |
输出电压范围 | 1.2V ~ 5.0V (0.1V 递进) |
输出精度 | \(\pm2\%@V_{OUT}\ge1.5V\)、\(\pm30mV@V_{OUT}<1.5V\)、\(\pm1\% @V_{OUT}\ge2.0V\) |
低功耗 | 典型值为 1.0 μA |
输出电容类型 | 可以兼容低 ESR 的陶瓷电容 |
保护措施 | 内置限流电路 |
工作环境温度 | -40℃ ~ 85℃ |
XC6206系列可以选用较低等效串联电阻(ESR,Equivalent SeriesResistance)的陶瓷电容,并且可以通过内部的限流电路提供输出引脚的短路保护,其典型应用电路如下面的原理图所示:
微盟电子推出的ME6206系列是一款低功耗低压差、高纹波抑制率,并且具有过流与短路保护的 CMOS降压型稳压芯片,该系列元件具有较低的静态偏置电流(典型值为8.0μA
),可以在输入输出电压差极小情况下,提供约300mA
的输出电流,并且仍然能够保持良好的调整率。
参数名称 | 参数值 |
---|---|
高精度输出电压 | ±2% |
输出电压 | 1.5V ~ 5.0V ,步长为0.1V |
最大工作电压 | 6V |
静态偏置电流典型值 | 8.0μA |
带载能力 | 当 \(V_{in}=4.3V\) 且 \(V_{out}=3.3V\) 的时候,输出电流 \(I_{out}=300mA\) |
输入输出电压差 | 输出电流为 90mA 时的压差为0.2V ,而输出电流为 200mA 时的压差为0.4V |
ME6206 系列稳压芯片的常用封装形式为SOT-23-3,其典型应用电路如下图所示:
注意:上述原理图当中的 VIN表示电压输入引脚,VOUT 表示电压输出引脚,而VSS 则表示的是接地引脚。
微盟电子推出的ME6211系列,同样是一款高精度、高纹波抑制比、低噪声,快速响应的 CMOS低压差线性稳压器,该芯片内置有参考电压源
、误差修正电路
、限流电路
、相位补偿电路
、低内阻 MOSFET
,可以达到高纹波抑制、低输出噪声、超快速响应的性能指标:
参数名称 | 参数值 |
---|---|
最大输出电流 | 当 \(V_{in}=5V\) 且 \(V_{out}=3.3V\) 的时候,输出电流 \(I_{out}=500mA\) |
输入输出电压差 | 输出电流为 100mA 时压差为100mV |
工作电压范围 | 2V ~ 6.0V |
输出电压范围 | 1.2V ~ 5.0V ,步长为0.1V |
输出精度 | ±2% |
静态电流 | 典型值为 50uA |
关断电流 | 典型值为 0.1uA |
纹波抑制比 | 例如 ME6211C33 为70dB@1KHz |
输出噪声 | 50uVrms |
输入稳定性 | 典型值为 0.05% |
ME6211系列兼容体积相对于钽电容更加小巧的陶瓷电容,并且无需再额外使用0.1μF
的旁路电容,可以进一步节省物料成本。除此之外,ME6211系列常用的封装形式为SOT-23-5,其典型应用电路如下图所示:
]]>注意:上图当中的 VIN是电压输入引脚,VOUT 是电压输出引脚,VSS 属于接地引脚,CE则是使能引脚(高电平),而 NC 引脚无需进行连接。
CY7C68013A
和芯佰微电子 CBM9002A
两款 USB控制器的开源逻辑分析仪,可以同时采集 8个通道的数字信号,单个通道的最大采样频率为24Mhz
,可以支持高达 5.5V
的逻辑电平(大于2V
视为高电平,低于 0.8V
视为低电平)。即可以采用 Sigrok PulseView(可以实时下载固件),也可以采用 SaleaeLogic(需提前烧录固件)作为逻辑分析仪的上位机程序。逻辑分析仪(LogicAnalyzer)作为一种非常重要的数字信号分析仪器,虽然市场上已经存在有 DSLogic或者 Saleae等功能强大的商业化产品,但是在日常的微控制器与数字信号总线开发过程当中,如果不是用于调试PCIE
、USB3.0
等高速信号,一台小巧可靠的24MHz采样率逻辑分析仪,就已经足以应付大多数的开发场景。因而笔者在自己的 GitHub当中,开源了这款逻辑分析仪的全部 KiCad 原理图以及PCB版图,希望能够对于广大电子工程师的工作有所帮助。
UINIO-Logic-24MHz是一款硬件电路、固件程序、上位机软件均开源的逻辑分析仪,可以完成一百余种总线协议的解析工作,最高可以支持到24Mhz 采样频率 8个采样通道,其中每个通道支持的输入电压介于-0.5V ~ 5.25V
之间,其中低电平范围为-0.5V ~ 0.8V
,而高电平范围为2V ~ 5.25V
,本项目所涉及到的全部开源工具如下面列表所示:
根据奈奎斯特采样定理,逻辑分析仪的采样频率至少应当是采样信号频率的5 到 10 倍,才可采样出较为完整的原始信号,所以在只开启1
个通道的情况下,使用最高 24Mhz
的采样频率,UINIO-Logic-24MHz 最高可以采集到5MHz
左右的数字信号。
注意:由于 UINIO-Logic-24MHz 的 USB接口工作在 USB2.0 高速模式下,对于 USB接口带宽的需求比较高,而外接 USB扩展坞可能无法支撑如此高的带宽需求,所以请尽量直接连接到计算机的 USB接口上使用。
UINIO-Logic-24MHz 采用赛普拉斯(Cypress)的 CY7C68013A作为主控芯片,内部集成有 USB 2.0 收发器、串行接口引擎(SIE)、增强型8051 微控制器,以及可编程的外设接口,其功能逻辑框图如下面所示:
通过片上的 GPIF(General ProgrammableInterface)与主从设备接口 FIFO(拥有 8 位或 16位数据总线),建立起计算机上位软件(例如 PulseView、Saleae Logic等)与逻辑分析仪 UINIO-Logic-24MHz采样通道(CH1 ~ CH8
)之间的高速信号连接:
UINIO-Logic-24MHz 板载了型号为AT24CS64-XHM 的 TSSOP
封装EEPROM,用于下载和存储各类逻辑分析仪的固件:
UINIO-Logic-24MHz 的 8 条采样线,通过100
欧姆的限流电阻,连接至一片同样采用 TSSOP
封装的 74HC245双向总线缓冲芯片,一方面用于隔离输入与输出,另一方面能够确保采样信号的稳定与完整性:
注意:国产芯佰微电子的 CBM9002A是一款对标
CY7C68013A
的 Pin to Pin 产品。
使用 UINIO-Logic-24MHz 之前,需要手动安装PulseView 上位机软件,完成之后需要执行其安装目录下的 Zadig来安装逻辑分析仪的 USB 驱动程序,在开始进一步的操作之前,需要先将UINIO-Logic-24MHz 的 USB Type-C 接口连接至计算机:
双击执行 zadig.exe
之后弹出上图的界面,首先鼠标勾选右侧的【Edit】,然后将设备名称修改为fx2lafw
,最后按下【Install Driver】按钮开始安装驱动:
稍等片刻,当弹出下面信息提示框的时候,就表明当前的 USB驱动程序已经安装成功:
此时在操作系统的设备管理器当中,可以看到UINIO-Logic-24MHz 的设备名称已经被显示为fx2lafw
:
安装完成 USB 驱动程序之后,保证 UINIO-Logic-24MHz稳定的插入计算机,然后打开 PulseView
开始进行 USB的枚举配置,并且将固件在线写入 EEPROM,成功后丝印为PA1
的绿色 LED 将会自动亮起:
注意:推荐下载使用 PulseView 的
pulseview-0.4.2-64bit-static-release-installer.exe
稳定版本,官方推荐的每晚编译版本pulseview-NIGHTLY-64bit-static-release-installer.exe
工作十分不稳定,甚至可能会导致 UINIO-Logic-24MHz无法正确的采样信号。
PulseView的界面非常简单,可以在顶部【菜单栏】选择采样数量和采样频率,然后点击左上角的【Run】按钮,就可以开始让指定的通道采样数字信号:
注意:运行
pulseview-0.4.2-64bit-static-release-installer.exe
版本之前,需要先下载安装微软官方的 MicrosoftVisual C++ 2010 SP1 Redistributable Package,否则可能出现运行PulseView 时找不到msvcr100.dll
动态链接库的错误。
PulseView 支持一百余种总线通信协议的解析,当UINIO-Logic-24MHz采集到有效的数字信号之后,鼠标点击顶部菜单栏上的协议解码器
图标,在右侧的弹出窗口当中选择具体的通信协议:
例如在这里选择解析 UART协议,此时就需要在主窗口区域配置 UART的波特率
、数据奇偶校验
、停止位
等信息,使得UINIO-Logic-24MHz能够正确解析出可视化的数据以供开发人员分析:
]]>注意:目前 PulseView上位机支持的总线通信协议解码器可以查阅这个链接。
160MHz
,板载 384KB
容量的 ROM,以及400KB
容量的 SRAM 和 8KB
容量的 RTCSRAM,支持的数字外设接口有3 × SPI
、2 × UART
、1 × I²C
、1 × I²S
,而模拟外设接口则采用了6 通道的 2 × 12
位 SAR 模/数转换器。稍晚一些推出的 ESP32-S3 微控制器则是基于Cadence 公司的 Xtensa Dual-Core 32-bitLX7 架构,拥有 45 个 GPIO 接口,主频高达240MHz
,板载有 384KB
容量的 ROM,以及512KB
容量的 SRAM 和 16KB
容量的 RTCSRAM,支持的数字外设接口有4 × SPI
、3 × UART
、2 × I²C
、2 × I²S
。而模拟外设接口采用了20 通道的 2 × 12
位 SAR模/数转换器。核心板的 KiCad 原理图以及 PCB源文件,可以在我的 GitHub仓库当中进行获取。
上海乐鑫科技推出的 ESP32-C3 微控制器基于 RISC-V架构,拥有 22 个 GPIO 接口,主频高达160MHz
,板载有 384KB
容量的 ROM,以及400KB
容量的 SRAM 和 8KB
容量的 RTCSRAM,支持的数字外设接口有3 × SPI
、2 × UART
、1 × I²C
、1 × I²S
,而模拟外设接口方面则支持多达6 通道的 2 × 12
位 SAR 模/数转换器。
ESP32-C3 的外围电路设计较为简单,仅仅只需要20 个左右的贴片电阻、电容、电感,以及1 个无源晶振、1 个 SPI 接口的 Flash存储芯片。其核心电路主要包括电源
、上电时序与复位
、Flash 存储器
、时钟源
、射频天线
、UART 串行通信
、ADC 模/数转换
、Strapping 引脚
、GPIO 引脚
、UART0 自动下载电路
等部分,下面展示了 ESP32-C3 官方给出的参考原理图:
ESP32-C3 一共拥有 VDDA1
和VDDA2
(模拟电源)、VDD3P3_RTC
(RTC电源)、VDD3P3_CPU
(MCU 电源)四组电源输入引脚,以及一组 VDD_SPI
引脚(电源输入/输出管脚,由 VDD3P3_CPU
通过电阻 \(R_{SPI}\)进行供电,因而会相对于 VDD3P3_CPU
存在着一定的电压降)。
注意:当
VDD_SPI
无需为外部进行供电时,也可以将其复用为GPIO11
来进行使用。
ESP32-C3 的典型工作电压为3.3V
,而工作电流则需要达到500mA
及以上。在 UINIO-MCU-ESP32C3原理图当中,ESP32-C3 的第 11
和17
引脚分别为 RTC 电源引脚和 MCU电源引脚,工作电压介于 3.0V ~ 3.6V
范围之间,并且分别添加了 0.1µF
以及 1µF
的对地滤波电容。
注意:当使用
VDD_SPI
作为外部 Flash存储器的电源时,需要满足该款 Flash存储芯片的最低工作电压要求,通常应当保证其电压值处于3.0V
及以上的值。
ESP32-C3 芯片的第2
、3
、31
、32
为模拟电源引脚,工作电压同样介于 3.0V ~ 3.6V
范围。
注意:当 ESP32-C3 工作在
TX
状态下时,由于瞬时电流较大,可能会导致电源轨道塌陷(当电源与地之间的电流发生变化时,电源路径与接地路径之间的阻抗会产生一个压降,从而导致提供给芯片的工作电压被降低),所以官方建议在电源走线上增加了一个10µF
电容,并且将其与0.1µF
、1µF
电容并联起来搭配使用。
ESP32-C3 的上电时序需要遵循:编号为 7
的使能引脚CHIP_EN
,上电时间必须晚于系统电源3.3V
的上电时间。
参数 | 说明 | 最小值(微秒) |
---|---|---|
\(t_0\) | CHIP_EN 管脚上电时间晚于VDDA 、VDD3P3 、VDD3P3_RTC 、VDD3P3_CPU ; | 50微秒 |
\(t_1\) | CHIP_EN 引脚的电平低于 \(V_{IL\_{nRST}}\) 的时间; | 50微秒 |
注意:为了确保 ESP32-C3在上电时电源的正常供电,
CHIP_EN
引脚需要添加 RC延时电路(典型取值为R = 10 kΩ
,C = 1 µF
,具体数值需要根据电源的上电时序和芯片的上电复位时序进行调整)。
ESP32-C3 可以通过 CHIP_EN
引脚进行复位,当 CHIP_EN
为低电平的时候,建议复位电平 \(V_{IL\_{nRST}}\) 的取值范围为 \((–0.3 \sim 0.25) \times VDD\)伏。除此之外,为了防止外界干扰导致系统重启,建议尽量缩短CHIP_EN
的 PCB 走线,并且添加上拉电阻\(R_2\)以及对地去耦电容 \(C_9\)。
注意:ESP32-C3 的
CHIP_EN
引脚不可以处于浮空状态。
ESP32-C3 最大支持 16MB
容量的 Flash存储器,可以选择使用 VDD_SPI
引脚输出的电源进行供电。在UINIO-MCU-ESP32C3 当中,直接选择将 LDO线性稳压器输出的 VDD_3.3V
作为 Flash存储芯片的工作电源。
注意:如果采用了
VDD_SPI
作为电源,那么建议在 SPI 总线引脚上预留一个0Ω
串联电阻的封装位置,用于降低驱动电流、减小串扰、调节时序等后续调试工作。
ESP32-C3可以使用外部晶振和外部RTC两个时钟源。
ESP32-C3 只支持 40MHz
晶振(精度为\(\pm 10 ppm\)),匹配电容C15
和 C17
的取值需要经过测试之后再行确定。
ESP32-C3 支持将 XTAL_32K_P
和XTAL_32K_N
引脚,连接至外部的 32.768 kHz
晶振作为 RTC 实时时钟。而UINIO-MCU-ESP32C3 为了获得更多的 GPIO 资源,索性直接将XTAL_32K_P
和 XTAL_32K_N
引脚复用为GPIO0
和 GPIO1
进行使用。
UINIO-MCU-ESP32C3 在引出射频天线时,预留了CLC 结构的 \(\pi\)型阻抗匹配网络(具体参数需要根据实际天线的 PCB布局来测定),以期获得最佳的发射功率:
ESP32-C3在复位过程当中(上电复位
、RTC 看门狗复位
、欠压复位
、模拟超级看门狗复位
、晶振时钟毛刺检测复位
),Strapping引脚会将引脚上的电平状态采样并且存储到锁存器当中(锁存值为0
或 1
),并且会一直保持到芯片掉电或者关闭。ESP32-C3一共拥有 GPIO2
、GPIO8
、GPIO9
三个Strapping 引脚(可以通过读取GPIO_STRAP_REG
寄存器上的 GPIO_STRAPPING
字段,获得这三个引脚上面的状态值)。
使用外接上下拉电阻或者直接经由GPIO,可以直接控制复位时 Strapping引脚的电平状态。在复位完成之后,Strapping 引脚会转变为普通引脚。其中GPIO9
默认连接内部的上拉电阻,如果该引脚悬空或者连接到外部的高阻抗电路,则锁存值默认为1
。ESP32-C3 的 Strapping引脚启动模式配置,可以参考下面的表格:
引脚 | 默认 | SPI 启动模式 | 下载启动模式 |
---|---|---|---|
GPIO2 | 无 | 1 | 1 |
GPIO8 | 无 | 无关 | 1 |
GPIO9 | 内部上拉 | 1 | 0 |
下图展示了 CHIP_EN
在上电前后,Strapping引脚的建立时间 \(t_0\)(最少保持 0
毫秒)和保持时间 \(t_1\)(最少保持 3
毫秒)之间的关系:
ESP32-C3 一共拥有 22 个 GPIO引脚,通过配置对应的寄存器,可以为这些引脚指定不同的功能。除了作为数字信号引脚之外,一部分GPIO 引脚也可以配置为 ADC 模拟引脚。所有 GPIO都可以在内部被设置为上拉、下拉、高阻,当GPIO被配置为输入状态,则可以通过读取寄存器获取该状态值。已经被设置为输入状态的GPIO引脚,可以产生出信号边缘触发
或者电平状态触发
中断。
注意:ESP32-C3 的数字 GPIO引脚都是双向、非反相、三态的,因而这些引脚也可以被复用为
UART
、SPI
等其它用途。
ESP32-C3 的 IO MUX 和 GPIO交换矩阵用于将信号从外设传输至 GPIO 引脚,两者共同控制着ESP32-C3 的输入输出:
下面的表格展示了所有通过 IO MUX 和 GPIO交换矩阵 所映射出的引脚功能:
注意:
GPIO12
和GPIO13
在Arduino 的 QIO 模式下被复用为SPI 总线的SPIHD
和SPIWP
信号线,为了增加可用的 GPIO 数量,UINIO-MCU-ESP32C3采用了两线制 SPI 的 DIO 模式,使用时需要注意将 Flash配置为 DIO 模式。除此之外,GPIO11
默认为SPI Flash 的VDD_SPI
引脚,需要配置之后才能够复用为 GPIO 使用。
下面展示了上述表格当中,复位一栏各个符号所代表的含义:
复位状态序列号 | 默认配置说明 |
---|---|
0 | 输入关闭,高阻 (IE = 0 ) |
1 | 输入使能,高阻 (IE = 1 ) |
2 | 输入使能,下拉电阻使能(IE = 1 ,WPD = 1 ) |
3 | 输入使能,上拉电阻使能(IE = 1 ,WPU = 1 ) |
4 | 输出使能,上拉电阻使能(OE = 1 , WPU = 1 ) |
0* | 输入关闭,上拉电阻使能(IE = 0 ,WPU = 0 ,USB_WPU = 1 ) |
1* | 当 eFuse 的EFUSE_DIS_PAD_JTAG 位为 0 时(默认值),引脚复位之后输入使能,上拉电阻使能(IE = 1 ,WPU = 1 );而当 EFUSE_DIS_PAD_JTAG 被置为 1 时,引脚复位之后输入使能,且处于高阻状态(IE = 1 )。 |
在上面表格当中,说明一栏里符号所代表的含义如下所示:
GPIO18
和 GPIO19
属于 USB 引脚,其上拉电阻由引脚上拉和 USB 上拉共同控制,当其中任意一个为1
时,对应引脚的上拉电阻使能;USB 上拉由USB_SERIAL_JTAG_DP_PULLUP
位进行控制;注意:建议将处于高阻状态的引脚配置为
上拉
或者下拉
,从而避免不必要的电能消耗。
当 ESP32-C3 复位完成之后,就可以通过GPIO2
、GPIO8
、GPIO9
三个Strapping 引脚共同控制 Boot 模式:
UART0
或者 USB 接口将代码下载至Flash,或者将程序加载至 SRAM 并在 SRAM 当中运行(确保 .bin
文件当中地址为 0x42000000
的前两个字为0xaedb041d
);UINIO-MCU-ESP32C3 的 GPIO2
在默认情况下,已经在内部被弱上拉为 3.3V
高电平(此处存疑,因为根据官方文档,该引脚实际上为输入高阻状态,并非处于高电平,可能文档撰写过程当中存在着谬误,了解该问题的同学可以联系我);而GPIO8
通过外接上拉电阻 R4
也被钳制为高电平。此时 ESP32-C3进入【下载启动模式】的条件就转变为:当CHIP_EN
引脚上面的信号处于上升沿的时候,Strapping 引脚GPIO9
必须保持为低电平 0
。
通过上面的原理图可以看到,GPIO9/BOOT
和CHIP_EN
分别连接至 ESP32-C3 的集电极,此时USB 转串口芯片 DTR
与 DTR
引脚,以及三极管Q1 与 Q2 和 ESP32-C3的 CHIP_EN
、GPIO9
引脚之间的逻辑关系如下表所示:
串口 DTR 和 DTR 状态 | 三极管 Q1 和 Q2 状态 | ESP32-C3 引脚状态 |
---|---|---|
DTR = 0 并且RTS = 0 | Q1截止,Q2 截止 | CHIP_EN = 1 、GPIO9 = 1 |
DTR = 0 并且RTS = 1 | Q1截止,Q2 导通 | CHIP_EN = 1 、GPIO9 = 0 |
DTR = 1 并且RTS = 0 | Q1导通,Q2 截止 | CHIP_EN = 0 、GPIO9 = 1 |
DTR = 1 并且RTS = 1 | Q1截止,Q2 截止 | CHIP_EN = 1 、GPIO9 = 1 |
概而言之,当 USB 转串口芯片的 DTR
和 RTS
同时为 0
或者 1
的时候,三极管Q1 和 Q2 均处于截止状态,此时CHIP_EN
和 GPIO9
的状态由内外部的上下拉电阻决定。而当串口芯片的 DTR
和RTS
不同时为 0
或者 1
时,CHIP_EN
与 RTS
的电平状态,以及GPIO9
与 DTR
的电平状态完全相同。这就意味着CHIP_EN
与 IO0
不可能同时为0
,然而进入下载模式需要 CHIP_EN
在从0
向 1
跳变时,GPIO9
的电平状态持续等于0
。为了满足这个条件,ESP32-C3 的CHIP_EN
引脚被连接到了一个 RC充放电电路上面,具体可以参见 UINIO-MCU-ESP32C3的原理图:
由于电容具有充放电效应,电平状态并不会马上切变为高电平,而是会从0
缓慢上升至 1
,在这个过程当中GPIO9
维持低电平 0
状态,即当串口芯片的DTR = 0
并且 RTS = 1
的时候,就可以实现ESP32-C3 的自动串口下载。
除此之外,UINIO-MCU-ESP32C3 板载的 SW1
和 SW2
两颗按键,分别是实现复位功能的【复位按键】,以及实现下载功能的【下载按键】,具体用途可以参考下面的表格:
按键位号 | 功能说明 | 有效值 |
---|---|---|
SW1 | 按键按下时 ESP32-C3开始复位 | 低电平 0 有效 |
SW2 | 按键按下时 ESP32-C3进入下载模式 | 低电平 0 有效 |
上海乐鑫科技推出的 ESP32-S3 微控制器基于 Cadence公司的 Xtensa® Dual-Core 32-bit LX7 架构,拥有45 个 GPIO 接口,主频高达 240MHz
,板载有384KB
容量的 ROM,以及 512KB
容量的 SRAM 和16KB
容量的 RTC SRAM,支持的数字外设接口有4 × SPI
、3 × UART
、2 × I²C
、2 × I²S
。而模拟外设接口方面则支持多达20 通道的 2 × 12
位 SAR 模/数转换器。
ESP32-S3 的核心电路与 ESP32-C3非常相似,同样仅需要 20个左右的贴片电阻、电容、电感,以及 1个无源晶振、1 个 SPI 接口的 Flash 存储芯片和1 个可选的 PSRAM 存储芯片。下面展示的是ESP32-S3 的官方参考原理图(基于四线制3.3V
工作电压的外部 Flash 和PSRAM 存储器进行设计):
ESP32-S3 的正常工作电压为3.3V
,正常工作所需的最大电流在 500mA
以上,并且电源入口位置建议添加静电释放(ESD,Electro-StaticDischarge)保护元件。整体上看,ESP32-S3 与上面介绍的ESP32-C3在电路设计方面的整体区别不大,因而本节内容主要介绍两者在供电电源、系统复位、Flash与 PSRAM 存储器、Strapping 引脚、USB自动下载等方面的主要差别。
ESP32-S3 的第 46 引脚VDD3P3_CPU
属于微控制器的 VDD数字电源引脚,其工作电压范围为3.0V ~ 3.6V
,设计时需要在靠近该引脚的位置添加0.1µF
去耦电容。而第 29 引脚VDD_SPI
可以被配置为 1.8V
输出(启动时配置GPIO45 的电平状态为 1
)或者3.3V
输出(启动时配置 GPIO45 的电平状态为0
,即默认状态)给外部电路使用,并且添加 0.1µF
和 1µF
的去耦电容。
VDD_SPI
处于 1.8V
模式,由ESP32-S3 内部的 Flash VoltageRegulator 进行供电(最大电流 40mA
);VDD_SPI
处于 3.3V
模式,由VDD3P3_RTC 经过 \(R_{SPI}\) 电阻进行供电,因此VDD_SPI
相对于 VDD3P3_RTC
会存在一定的电压降;注意:UINIO-MCU-ESP32S3 的
VDD_SPI
串联有一枚10KΩ
的电阻 \(R_6\),如果采用3.3V
工作电压的 Flash 存储芯片,则需要移除 \(R_6\) 电阻,使得 GPIO45的电平状态默认为0
。
ESP32-S3 的第2、3、55、56引脚为 VDDA 模拟电源引脚,其工作电压范围为3.0V ~ 3.6V
。类似于 ESP32-C3,为了防止TX
状态下瞬时电流增大导致的电源轨道塌陷,所以UINIO-MCU-ESP32S3 在 VDD3P3_CPU
的电源走线上增加了一枚 10µF
电容,并且将其与1µF
、0.1µF
电容并联起来使用。
ESP32-S3 的第 20 引脚VDD3P3_RTC
属于 RTC电源引脚,UINIO-MCU-ESP32S3 在该引脚位置添加了一枚0.1µF
的去耦电容。
不同于 ESP32-C3 通过 CHIP_EN
引脚进行复位,ESP32-S3 的复位引脚被称为CHIP_PU
。两者除了命名上的不同,其它参数乃至于使用方法基本一致。
ESP32-S3 支持的片外 Flash 和PSRAM 最大分别可以达到 1GB
存储容量,在元件选型时需要特别注意根据 VDD_SPI
的输出电压,选择相应工作电压的 Flash 和PSRAM 存储器芯片。
ESP32-S3 拥有GPIO0、GPIO45、GPIO46、GPIO3一共四个 Strapping 引脚,也可以像 ESP32-C3那样通过寄存器 GPIO_STRAPPING
读取这几个引脚的状态值。
在 ESP32-S3 的复位过程当中(上电复位、RTC看门狗复位、欠压复位、模拟超级看门狗复位、晶振时钟毛刺检测复位),Strapping引脚会采样当前的电平状态并且存储至锁存器(锁存值为0
或 1
),并一直保持到芯片掉电或者关闭。
下面表格列出了用于选择 JTAG 信号来源的EFUSE_DIS_USB_JTAG
、EFUSE_DIS_PAD_JTAG
、EFUSE_STRAP_JTAG_SEL
全部寄存器配置组合:
JTAG 信号源 | EFUSE_STRAP_JTAG_SEL | EFUSE_DIS_USB_JTAG | EFUSE_DIS_PAD_JTAG |
---|---|---|---|
见后表 | 1 | 0 | 0 |
USB Serial/JTAG控制器 | 0 | 0 | 0 |
USB Serial/JTAG控制器 | 无关 | 0 | 1 |
片上 JTAG 引脚 | 无关 | 1 | 0 |
无 | 无关 | 1 | 1 |
可以通过外部上下拉电阻,或者 GPIO 控制 ESP32-S3上电复位时的 Strapping 引脚电平。而在复位放开之后,Strapping引脚就会恢复为普通功能引脚。接下来的表格展示了 ESP32-S3全部 Strapping 引脚的配置含义。
通过配置 GPIO45 这个 Strapping引脚的状态,就可以控制 VDD_SPI
的输出电压:
引脚 | 默认状态 | 3.3V | 1.8V |
---|---|---|---|
GPIO45 | 下拉 | 0 | 1 |
而通过控制 GPIO0 和 GPIO46 这两个Strapping 引脚的状态,则可以选择 ESP32-S3的系统启动模式:
引脚 | 默认状态 | SPI 启动模式 | 下载启动模式 |
---|---|---|---|
GPIO0 | 上拉 | 1 | 0 |
GPIO46 | 下拉 | 无关 | 0 |
当EFUSE_DIS_USB_JTAG = 0
、EFUSE_DIS_PAD_JTAG = 0
、EFUSE_STRAP_JTAG_SEL=1
的时候,则可以通过 GPIO46 选择 JTAG 信号的来源:
引脚 | 默认状态 | 引脚状态值为 0 | 引脚状态值为 1 |
---|---|---|---|
GPIO46 | 下拉 | JTAG 信号来源于芯片上的 JTAG 引脚 | JTAG 信号来源于 USB Serial/JTAG控制器 |
ESP32-S3 一共拥有 45 个 GPIO数字引脚,它们可以被分配为 \(F_{0 \sim4}\) 这几种不同类型的功能:
上面表格当中,每一项数字功能 \(F_{0 \sim 4}\) 的含义如下所示:
1
);1
);0
);而上述表格当中,引脚复位状态的具体含义如下所示:
EFUSE_DIS_PAD_JTAG
的 eFuse
位为1
时,芯片复位之后 MTCK
浮空(IE1
),而 eFuse
位为 0
时,芯片复位之后 MTCK
连接至内部的弱上拉电阻(IE1
&WPU1
)。上面表格当中,备注一栏里各个符号的功能说明如下所示:
R
:该引脚具有 RTC 或模拟功能;G
:该引脚在芯片上电过程中存在着毛刺;注意:
GPIO19 ~ GPIO20
的默认驱动电流接近40mA
,除此之外其它引脚的默认驱动电流接近20mA
。
当 ESP32-S3 复位完成之后,就可以通过GPIO0
、GPIO46
两个 Strapping 引脚共同控制 Boot模式:
.bin
文件里地址为 0x42000000
的前两个字为0xaedb041d
);UINIO-MCU-ESP32S3 的 GPIO46
会在复位之后处于输入和内部弱下拉电阻使能状态(IE1
、WPD1
),即电平状态被下拉为0
,此时 ESP32-S3进入【下载启动模式】的条件就变为:当 CHIP_PU
引脚上面的信号处于上升沿的时候,Strapping 引脚 GPIO0
必须保持为低电平 0
。
类似于之前介绍的 UINIO-MCU-ESP32C3自动下载电路,ESP32-S3 的 CHIP_PU
引脚也连接有一个 RC 充放电电路,同样利用了电容的充放电效应,在CHIP_PU
从 0
向 1
跳变的过程中,将 GPIO0
的电平状态维持为低电平0
。这样当串口芯片的 DTR = 0
并且RTS = 1
时,就可以实现 ESP32-S3的自动下载。
UINIO-MCU-ESP32S3 自动下载电路的不同之处,在于将UINIO-MCU-ESP32C3 当中由 Q1 和Q2 两个 NPN 三极管组成的下载逻辑电路,简化为了一颗乐山无线电生产的 LMBT3904DW1T1G双 NPN 晶体管阵列芯片,该芯片的内部电路与UINIO-MCU-ESP32C3 的下载逻辑电路接法基本保持一致:
除此之外,UINIO-MCU-ESP32S3 同样板载了SW1
和 SW2
两颗分别用于实现下载功能和复位功能的按键:
它们的具体用途,与 UINIO-MCU-ESP32C3 上面的两颗按键SW1
和 SW2
完全保持一致:
按键位号 | 功能说明 | 有效值 |
---|---|---|
SW1 | 按键按下时 ESP32-C3开始复位 | 低电平 0 有效 |
SW2 | 按键按下时 ESP32-C3进入下载模式 | 低电平 0 有效 |
ESP32-S3 集成了一颗携带有收发器,并且符合USB2.0 规范的全速 USB On-The-Go外设(OTG),其中 GPIO19
和GPIO20
引脚可以分别用于接入 USB的差分信号线 D-
和 D+
:
利用 ESP32-S3 集成的 USB OTG 外设功能,就可以通过USB 接口直接进行固件的下载,而无需再借助 CH343P 这类USB 转串口芯片。UINIO-MCU-ESP32S3 为了同时兼容UART0 和 USB OTG两种下载方式,专门加入了一颗由 江苏润石科技提供的高速低功耗双刀双掷(DPDT,Double Pole DoubleThrow)模拟开关 RS2227XUTQK10,其工作电压在1.8V ~ 5.5V
范围,采用 WQFN-10
封装,内部原理与引脚连接如下图所示:
上图当中的 D+
和 D-
是 USB差分信号输入引脚,而 HSD1+
和HSD1-
、HSD2+
和 HSD2-
则分别是USB 差分信号输出引脚,通过编号为 10
的S
引脚可以选择当前是使用 HSD1 还是HSD2 进行 USB差分信号输出,下面的表格是该芯片各个引脚功能的真值表:
注意:通过原理图当中位号为
J1
的跳线座,就可以指定 UINIO-MCU-ESP32S3当前所使用的下载方式。
当采用两层 PCB进行设计时,可以遵循如下的层功能划分:
而采用四层 PCB进行设计时,则可以遵循下面的层功能划分:
50Ω
的单端阻抗控制,参考平面为第二层,射频走线上的 \(\pi\) 型阻抗匹配网络需要呈Z字型摆放;射频走线必须保证相邻层拥有完整的地平面,并且走线下方尽可能不要出现任何的走线;射频走线必须远离晶振、DDR、USB转串口等高频元器件;U0TXD
和 U0RXD
走线要尽量缩短,并且最好是进行包地处理;DAPLink 主要由 Mbed硬件开发工具包 以及 DAPLink固件 两个开源项目构成,而 UINIO-DAP-Link则是由我自己设计的一款完全开源的 DAPLink实现,相比于官方原版的硬件电路设计,在引出有 SWD调试接口(由 ARM 公司制订)的同时,还引出了 JTAG接口(属于 IEEE1149 国际标准)以及5V
和 3.3V
电源,并且附带有 SWD 至 JTAG 转接板的PCB 设计,而固件部分则是基于 ARM官方的最新的原版固件移植而来,全部的原理图与固件程序都已经开源在 GitHub。
DAPLink调试器可以为开发人员提供如下一系列方便实用的功能:
注意:目前 DAPLink 已经取代了过去 ARMMbed 推出的 CMSIS-DAP 开源调试器项目。
如下品牌的 ARM 硬件接口电路(HIC,Hardware InterfaceCircuits,即调试器硬件)与 DAPLink 的固件完全兼容:
DAPLink主要提供了拖放编程、串口通信、调试三种主要功能:
.bin
或者.hex
格式的文件复制或者保存到 DAPLink驱动器,从而实现对目标微控制器的编程。完成以后,驱动器将会重新进行挂载。如果下载出现问题,则驱动器上将会自动生成一个包含有故障信息的FAIL.TXT
文件;9600
、14400
、19200
、28800
、38400
、56000
、57600
、115200
等常用波特率;更新设备固件时,只需要连接上 USB 并且按住重置键,让设备进入Bootloader引导模式,从而开始下载固件。如果下载成功,那么设备将会离开引导模式,并且开始运行新的固件。如果下载失败,则设备将会自动生成显示有错误信息的FAIL.TXT
文件。
DAPLink 的固件源代码,使用开源项目构建工具 project-generator提供的 progen
命令进行构建。除此之外,在编译过程当中还需要使用到如下一系列工具软件:
gcc_arm
的 GNUARM Embedded Toolchain 、标识为 armclang
的 ARMCompiler 6,以及标识为 armcc
的 KeilMDK 或者 ARMCompiler 5 编译器,它们当中的大部分都只支持 Linux 和 Windows操作系统环境;pip Install virtualenv
命令全局安装 Python虚拟环境 virtualenv
;首先,需要去克隆 DAPLink托管在 Github 上面的开源工程,并且创建出一个 Python 虚拟环境:
1 | $ git clone https://github.com/mbedmicro/DAPLink |
如果当前使用的是 DAPLink 的指定 Release版本,当把这些版本下载至本地以后,为了避免后续编译过程当中报错,需要将其初始化为一个Git 工程项目:
1 | $ git init |
接下来,就可以激活 Python 虚拟环境,并且更新 DAPLink开源工程相关的第三方依赖库:
1 | $ venv/Scripts/activate (For Linux) |
除此之外,还需要再额外全局安装 intelhex
和pyelftools
两个 Python 第三方库,避免后续使用 KeilµVision 进行编译的时候出现依赖缺失的错误:
1 | $ pip install intelhex pyelftools |
接下来开始构建 DAPLink 的项目工程结构,可以使用 project-generator提供的 progen
命令或者直接执行tools/progen_compile.py
脚本:
1 | (venv) $ python tools/progen_compile.py [-t <tool>] [--clean] [-v] [--parallel] [<project> [<project> ...]] |
-t <tool>
:选择当前构建所使用的工具链,默认为make_gcc_arm
,其它的可选项分别为make_gcc_arm
、make_armclang
、make_armcc
、cmake_gcc_arm
、cmake_armclang
、cmake_armcc
;--clean
:清除现有的编译结果,并且强制重新编译所有文件;-v
: 列出详细信息,该选项会延长编译运行时间;--parallel
: 启用并行编译,加快编译速度;<project>
:等待编译的目标工程,如果缺省将会编译全部工程;通过执行下面的命令,可以在 projectfiles/uvision
目录下面生成一系列的 Keil µVision 工程:
1 | (venv) $ progen generate -t uvision |
当然也可以使用下面这条命令,只生成 stm32f103xb_bl
和stm32f103xb_stm32f103rb_if
两个指定的 KeilµVision 工程:
1 | (venv) $ progen generate -f projects.yaml -p stm32f103xb_bl stm32f103xb_stm32f103rb_if -t uvision |
上述命令当中的参数 -f
用于指定工程配置文件,而参数-p
则用于指定工程的名称,最后的 -t
则用于指定工程所属的开发环境。
编译 DAPLink 工程所需要使用到的 ARM 编译器版本为5,而当前最新版本的 KeilµVision 5.39 包含的编译器版本为 6,此时需要下载 KeilµVision 5.36,同时提取其 ARM
目录下的ARMCC
编译器,并将其解压至当前 KeilµVision 程序安装目录下的 ARM
文件夹下面:
启动 Keil µVision 开发环境,依次点击菜单栏上面的【Project】->【Mange】->【Project Items】
选项:
选中弹出对话框当中的 【Folders/Extensions】
选项卡,点击Use ARM Compiler
最右侧的按钮(即下图橙色圈出部分):
鼠标再点击新弹出界面上的【Add another ARM Compiler Version to List】
按钮,将路径定位至刚才放置到 Keil µVision 安装目录下的ARMCC
文件夹:
关闭上述对话框,再使用鼠标点击一次界面上的【Setup Default ARM Compiler Version】
按钮:
选中 【Use default Compiler Version 5】
,将上面的ARMCC
目录设置为当前 Keil µVision的默认编译器:
完成上述操作之后,就可以打开当前 Keil µVision 工程的【Target】
选项卡,打开 ARM Compiler
下拉菜单,就可以看到相关的编译器选项:
由于当前 DAPLink 采用了 Keil µVision4 进行构建,所以打开工程的时候会弹出如下的【Using an MDK Version 4 Project】
对话框:
依次点击弹出界面上的【Migrate to Device Pack】
、【Stop Waiting】
按钮,最后点击 【是(Y)】
:
选择当前 UINIO-DAP-Link 所使用的意法半导体STM32F103C8T6
作为目标编译芯片:
确认把当前以 .uvproj
作为后缀名的 Keil µVision4 工程,转换为以 .uvprojx
作为后缀名的Keil µVision 5 工程:
当使用 progen
执行完成项目构建之后,就会自动在DAPLink 工程的 projectfiles\uvision
目录下面生成如下两个 Keil µVision 工程:
stm32f103xb_bl
目录:DAPLink 的Bootloader 工程,编译后得到 stm32f103xb_bl.hex
。stm32f103xb_stm32f103rb_if
目录:DAPLink 的 Interface 工程,编译后得到stm32f103xb_stm32f103rb_if.hex
。首先,计算机需要连接上一台已经下载好固件的 CMSIS-DAPDebugger 调试器,并且在 Keil µVision当中进行如下一系列设置:
然后,就可以编译 DAPLink 的 Bootloader 工程stm32f103xb_bl
,并且将其直接烧录至UINIO-DAP-Link 当中:
完成 Bootloader 的烧录之后,将 UINIO-DAP-Link连接至计算机的 USB端口,就会自动在操作系统的资源管理器当中挂载出一个MAINTENANCE
盘符:
接下来,开始编译 DAPLink 的 Interface 工程stm32f103xb_stm32f103rb_if
,完成之后将编译得到的stm32f103xb_stm32f103rb_if.hex
文件拖入MAINTENANCE
盘符。如果此时资源管理器当中的MAINTENANCE
盘符自动被更名为DAPLINK
,就表示已经成功完成了UINIO-DAP-Link 的全部固件下载工作:
注意:下载 DAPLink 固件所需的
stm32f103xb_bl.hex
stm32f103xb_stm32f103rb_if.hex
固件,已经被放置到 UINIO-DAP-Link开源项目的Firmware
目录下面,故而大家可以省略前述的Keil µVision编译步骤,直接按照上述流程下载固件即可。
首先,打开 DAPLink\source\daplink\cmsis-dap
目录下的dap_strings.h
源文件,将其中的#define CMSIS_DAP_PRODUCT_NAME "DAPLink CMSIS-DAP"
语句修改为自定义的#define CMSIS_DAP_PRODUCT_NAME "UINIO-CMSIS-DAP"
:
1 |
然后,再打开 DAPLink\source\hic_hal\stm32\stm32f103xb
目录下的 IO_Config.h
头文件,根据当前UINIO-DAP-Link 的引脚连接关系进行如下一系列配置:
1 |
|
UINIO-DAP-Link 调试器采用意法半导体STM32F103C8T6
作为主控芯片,片上 Flash的容量为 64KB
。在之前所述的步骤当中,已经为其烧录了stm32f103xb_bl.hex
作为Bootloader,因而支持通过拖拽方式升级快速升级Interface 固件stm32f103xb_stm32f103rb_if.hex
,具体操作步骤如下所示:
nRST
和 GND
针脚进行短接。MAINTENANCE
盘符。nRST
和 GND
引脚的杜邦线连接断开。MAINTENANCE
盘符,等待UINIO-DAP-Link 自动更新固件。DAPLINK
盘符,就表示已经升级成功。在接下来的内容里,将会基于我所制作的 UINIO-MCU-STM32L051K8核心板,在意法半导体提供的最新版本 STM32CubeIDE当中,实现固件的烧录与调试。
在 STM32CubeIDE 当中运用 DAPLink调试与下载程序,需要使用到 ARM嵌入式应用程序二进制接口,也就是 ARMEABI。包括了 Windows Toolchain forARM 和 OpenOCD两个工具库:
openocd.exe
开启一个连接到 DAP-Link与目标微控制器的 GDB 调试服务;arm-none-eabi-gdb.exe
访问这个 GDB 服务;下载并且解压上述两个工具库之后,分别将它们的 bin
目录添加到操作系统的环境变量,再分别执行如下两个命令,测试其是否已经正确的被安装:
1 | λ openocd |
1 | λ arm-none-eabi-gdb |
OpenOCD 命令的调用格式如下面的代码所示,其中的 -f
参数表示当前使用的是配置文件:
1 | openocd.exe -f interface\调试器接口配置文件 -f target\目标微控制器配置文件 |
下面列出了 OpenOCD\share\openocd\scripts\interface
目录下的所有配置文件,由于这里使用的是 DAP-Link作为调试器,所以通常都是以 cmsis-dap.cfg
作为参数:
1 | λ ls OpenOCD\share\openocd\scripts\interface |
接下来例出的是 OpenOCD\share\openocd\scripts\target
目录下的全部配置文件,这里需要根据目标 MCU微控制器的型号,酌情选择相应的配置文件作为参数:
1 | λ ls OpenOCD\share\openocd\scripts\target |
这里以STM32L0
、STM32F1
、STM32F4
系列微控制器为例,需要分别使用到如下几条 OpenOCD 命令:
1 | openocd.exe -f interface\cmsis-dap.cfg -f target\stm32l0.cfg |
接下来以 STM32L051K8U6
微控制器为例,正确执行 OpenOCD命令之后的效果如下所示,命令行会提示当前提供的 GDB 服务端口为3333
:
1 | λ openocd.exe -f interface\cmsis-dap.cfg -f target\stm32l0.cfg |
简便起见,也可以将上述命令保存为 Windows 系统下面一个名为OpenOCD stm32l0.bat
的批处理文件,方便调试的时候快速进行调用:
1 | echo Openocd Runing ... ... ... |
启动 OpenOCD 服务之后,接着在STM32CubeIDE 当中新建一个名称叫做Test-STM32L051K8U6
的工程:
首先,选中 STM32CubeIDE左侧的工程名称,点击鼠标右键菜单上的 【BuildProject】, 编译生成出一个 Test-STM32L051K8U6.elf
二进制文件。点击工具栏上【Debug】图标右侧的箭头,点击弹出菜单上的Debug Configrations...
打开调试配置窗口,鼠标双击窗口上的GDB Hardware Debugging
新建一条名为Test-STM32L051K8U6 Debug
的 GDB硬件调试配置,并在自动打开的【Main】选项卡界面进行如下一系列配置:
切换至【Debugger】选项卡,将 GDB 命令修改为D:\Software\Tech\ARMEabi\bin\arm-none-eabi-gdb.exe
,并且将连接地址设置为localhost:3333
:
经过上述步骤的配置,鼠标点击【Debug】按钮,就已经可以让STM32CubeIDE 通过 UINIO-DAP-Link实现固件的烧录下载,如果需要进入单步调试模式,则可以在【Startup】选项卡当中,手动在main
函数位置设置一个断点:
首先,需要在 STM32CubeIDE 的 ExternalTool 当中添加 OpenOCD,依次点击顶部菜单栏当中的 【RUN-> External Tools -> External ToolsConfigrations...】,新建一个名称为Test-STM32L051K8U6 Run
的配置,并且将 OpenOCD命令所在的位置指定为D:\Software\Tech\ARMEabi\OpenOCD\bin\openocd.exe
,相应的参数设置为-f interface\cmsis-dap.cfg -f target\stm32l0.cfg
:
打开 STM32CubeIDE 的 DebuggerConfigration 窗口,鼠标双击左侧的【LaunchGroup】新建一个名为 UINIO-DAP-Link
的运行组,然后点击右侧的【Add...】按钮:
此时添加的执行配置策略为:首先执行 OpenOCD
命令开启 GDB服务,然后再通过 arm-none-eabi-gdb
执行调试任务。
最后,配置完成之后的 Launch Group顺序如下图所示:
接下来,就可以在 STM32CubeIDE顶部工具栏上【Run】和【Debug】按钮的下面,发现上面的配置的UINIO-DAP-Link
运行组,点击之后就可以愉快的使用UINIO-DAP-Link 执行 STM32微控制器的程序调试工作了。
本节内容将会基于 UINIO-MCU-GD32F350RBT6核心板,新建一个名称为 test
的 KeilµVision 工程,并且点击菜单栏上的【Options for target】->【Device】
,选择当前编译的目标设备为GD32F350RB
:
接下来,再点击弹出的 【Manage Run-Time Environment】
界面上的 OK 按钮,完成测试工程的建立:
再次打开 【Options for target】
,鼠标选择【Output】
选项卡,勾选 Create HEX File
选项之后,在 Name of Executable
当中把待下载的二进制文件添加上 .hex
后缀名称(否则Keil µVision 会默认下载 .axf
后缀的二进制文件):
紧接着打开 【Debug】
选项卡,选择CMSIS-DAP Debugger
,并且点击 【Settings】
按钮:
在弹出的对话框中,选择 UINIO-CMSIS-DAP(需要提前将UINIO-DAP-Link 连接到电脑的 USB 端口):
再打开对话框上的 【Flash Download】
选项卡,勾选Reset and Run
之后,点击 【Add】
按钮添加片上的 Flash 编程算法:
至此就完成了 UINIO-DAP-Link 在 KeilµVision 当中的全部配置,接下来就可以添加官方的 ARM标准库,愉快的编写并且下载工程代码了。
如果需要直接烧录已经编译过的 .hex
固件(例如下载 UINIO-DAP-Link 当中Firmware
目录下的stm32f103xb_bl.hex
),可以按照前一小节内容所述的步骤,建立一个名为test
的 Keil µVision 工程,并将需要下载的.hex
文件拷贝至其 Objects
目录当中,接着在【Options for target】->【Output】
选项卡下面的Name of Executable
输入框当中,填入当前需要下载的.hex
文件完整名称(下图以 stm32f103xb_bl.hex
为例):
注意:通过上述界面当中的
【Select Folder Objects...】
按钮,还可以指定除了Objects
之外其它包含有.hex
固件的目录。
然后,就可以点击 Keil µVision 顶部工具栏上的【Download】
按钮,或者直接按下快捷键【F8】
,就可以将上面指定的 .hex
文件下载至目标ARM 芯片当中:
]]>注意:新建的 Keil µVision工程必须参考前面的步骤,配置好目标芯片的型号以及片上 Flash的编程算法。
1m
,而 NFC 的传输范围通常在10cm
以内。NFC 的无线信号频率为13.56MHz
,可以兼容ISO14443、ISO15693、Felica等非接触式智能卡规范,数据传输速率可以达到106kbit/s
、212 kbit/s
、424kbit/s
。意法半导体的 NFC 动态标签芯片 ST25DV-I2C 和ST25DV-PWM 可以通过低功率的 I²C总线以及 13.56MHz
无线射频访问芯片内置的EEPROM(电可擦除只读存储器),同时支持近程的ISO/IEC 14443 Type A 和远程的 ISO/IEC15693 标准。本文旨在介绍无源 RFID的基本原理,以及 13.56MHz
感应天线设计的基础知识,文中部分内容参考自意法半导体编号为《AN2972》的官方应用笔记(ApplicationNote)。
实际电路当中集成动态 NFC 标签芯片是一项非常简单的工作,只需要将其通过I²C 总线连接至 MCU 微控制器即可,而动态 NFC 标签芯片在RF(射频,RadioFrequency)一端,则还需要连接外部天线才能够正常工作。
动态 NFC 标签的天线通常是放置于 PCB电路板上的一圈环形走线,其阻抗与内部的调谐电容值相匹配,进而创建出一个13.56MHz
频率的共振电路,这个调谐频率的基本方程为:
\[f_{调谐} = \frac{1}{2 \pi \times \sqrt{L_{天线} \times C_{调谐}}}\]
本文接下来的内容当中,NFC 标签用于指代安装在 PCB上并与其天线相连接的动态 NFC 标签芯片,而 NFC读卡器则是指能够以射频模式与 NFC 标签进行通信的设备。
动态 NFC标签芯片通过其环形天线,从读卡器产生的磁场中获取运行所需的能量。该过程类似于变压器的互感,其中NFC 读卡器相当于初级绕组,而 NFC标签则相当于次级绕组。从 NFC 读卡器到 NFC标签芯片的能量传输主要取决于如下四个方面:
13.56 MHz
;下面的示意图展示了在射频模式下,NFC读卡器与标签之间的功率传输机制:
NFC 读卡器通过电磁场向 NFC 标签传递的能量,取决于 NFC读卡器产生的磁感线如何流经 NFC 标签天线。
将 NFC 标签放置于 NFC 读卡器的电磁场当中,NFC标签芯片的内置电路就会开始解调来自于读卡器的信息:
通信结束之后,NFC 读卡器会继续为 NFC 标签供电,以使得 NFC标签产生一个应答响应,发送回 NFC 读卡器(动态 NFC标签芯片会通过调节内部的输入阻抗,将应答信号反向散射到 NFC读卡器)。
▶ 整个数据通信过程所涉及的全部标准与协议,都已经嵌入到了 NFC 读卡器与NFC 标签芯片的内部电路当中。
下面的示意图给出了 NFC 动态标签及其天线的等效电路:
其中,虽然 \(C_{ant}\)、\(R_{ant}\)、\(L_{ant}\)是一个常量,但是其总阻抗具有频率依赖性。即在自谐振频率下,天线阻抗的虚部\(Z_{ant}\)为零呈现纯阻性;而在低于自谐振频率时,天线阻抗的虚部为正值呈现感性。当频率低于自谐振频率(\(Z_{ant} = R_A+j_{XA}\))的时候,天线的等效电感 \(L_A\) 被定义为 \(L_A = \frac{X_A}{\omega}\)。
▶ 低频情况下,杂散电容的影响可以忽略不计 \(L_A = L_{ant}\)(自感)。而达到
13.56MHz
频率的时候,杂散电容的影响就不能再被忽视 \(L_A > L_{ant}\)。
下图展示了存在正弦磁场的情况下,安装有环形天线的NFC 动态标签芯片的等效电路。其中的 \(V_{OC}\)表示天线传递的开路电压,该电压值取决于磁场强度
以及天线的尺寸
和匝数
。
NFC 标签的天线阻抗为 \(Z_{ant} = R_A + jL_A\omega\),其中的 \(L_A\)表示天线的电感。而 NFC 标签芯片的阻抗为 \(Z_S = R_S + j \times \frac{1}{CS\omega}\),其中的 \(R_S\)表示的是 NFC 标签芯片的电流损耗,而 \(C_S\)表示的是串联等效调谐电容。
▶ 等效 RLC 电路的谐振频率由条件 \(L_A C_S\omega^2 = 1\) 给出,其中 \(\omega = 2\pi f\)(此处的 \(f\) 表示频率
Hz
)。
RLC 电路的总阻抗 \(Z_{tot}= Z_{ant} + Z_S\),当谐振频率为 \(L_A C_S \omega^2 = 1\) 时,总阻抗降低至\(Z_{tot} = R_A +R_S\),此时天线的总阻抗最小,天线内部的电流以及传递给NFC标签芯片的电压最大,进而向设备提供的能量也就最大。
▶ 上图展示了三个动态 NFC 标签天线调优的例子,其中的标签
#2
为最优的天线调谐。
13.56MHz
频率下的 NFC天线可以根据需要,被设计成为不同的形状。如前所述,需要重点关注的参数是天线在13.56MHz
频率下的等效电感 \(L_A\)。
▶ 杂散电容非常难进行近似的取值,通常处于以
pF
作为单位的范围以内。
接下来的内容会给出计算各种形状天线自感 \(L_{ant}\)的有效公式(不考虑天线杂散电容),以及如何通过意法半导体官方提供的 eDesignsuite工具来计算等效电感 \(L_A\)。
\[L_{ant} = \mu_0 \times N^{1.9} \times r \times \ln(\frac{r}{r_0})\implies4 \pi \cdot 10^{-7} \times 天线圈数^{1.9} \times 天线半径 \times\ln\bigg(\frac{天线半径}{导线直径}\bigg)\]
r
是天线半径,单位为毫米;r_0
是导线直径,单位为毫米;N
是天线的圈数;\[L_{ant} = 31.33 \times \mu_0 \times N^2 \times \frac{a^2}{8a + 11c}\implies31.33 \times 4 \pi \cdot 10^{-7} \times 天线匝数^2 \times\frac{平均半径^2}{8\times平均半径 + 11\times绕组厚度}\]
\[L_{ant} = K_1 \times \mu_0 \times N^2 \times \frac{d}{1 + K_2 \times p}\]
布局 | \(K_1\) | \(K_2\) |
---|---|---|
正方形 | 2.34 | 2.75 |
六角形 | 2.33 | 3.82 |
八角形 | 2.25 | 3.55 |
意法半导体官方提供的 eDesignsuite在线工具套件,为 NFC 天线设计提供了 NFC 电感 (NFCInductance) 和 NFC调谐电路 (NFC Tuning Circuit) 两款小工具。只需要输入与 PCB材料和天线尺寸相关的参数,该工具就可以通过计算自电感和杂散电容来得到天线的等效电感。
上图给出了一个天线等效电感的计算示例,包括了天线的几何参数、导体参数、PCB基板参数。通过计算出的天线等效电感,就可以生成一个天线的原型。接下来,就可以使用网络分析仪测量天线阻抗,或者使用非接触式的方式测量NFC 标签的调谐频率来验证天线设计。
动态 NFC标签芯片必须尽可能的靠近天线(位于几毫米范围以内),任何额外的布线都会改变天线的特性。
布局 PCB 上的 NFC天线时,需要注意天线的顶层与底层两个面都不能进行铺铜,并且在天线周围也最好不要存在铜平面;下面的示意图展示了NFC 天线的最优布局:NFC标签芯片靠近天线,而接地平面远离天线。
接下来,展示的是两种错误设计的示例,这两种情况下电磁波不会流经天线,NFC读卡器与动态 NFC 标签的天线之间不会进行能量传递。
下面同样是一种不推荐的布局示例,因为动态 NFC标签天线周围的环形铺铜会极大的衰减电磁波信号。
而下面则是一种可以被接受的布局示例,主要是由于此处的天线并没有与地平面发生重叠。
▶ 建议在进行 PCB 布局时,专门为 NFC天线划分出一块周围没有接地层的独立区域。
当 NFC 天线靠近导电层时,其自感将会减小,从而造成NFC 标签的调谐频率增加。
如果设计的 NFC天线必须靠近金属表面进行工作,那么就必须对频率调谐的漂移进行补偿,以获得13.56MHz
的正确调谐频率。这里可以通过重新设计一个具有更大等效电感的全新 NFC天线,或者在现有天线基础之上增加一个外部调谐电容来实现补偿。下面的表格,就展示了一个使用74pF
调谐电容进行频率补偿的示例:
特性 | ANT1-M24LR16E | ANT1-M24LR16E加入74pF 调谐电容 |
---|---|---|
天线尺寸 | 45 mm x 75 mm | 45 mm x 75 mm |
空气中的频率调谐 | 13.7 MHz | 7.5 MHz |
接近金属表面的频率调谐 | 25 MHz | 14 MHz |
空气中的读取范围 | 7.5 cm | 0.5 cm |
接近金属表面的读取范围 | 未检测到 | 2.5 cm |
状态 | 天线经过调谐可以暴露在空气中工作 | 天线可以靠近金属表面进行工作 |
▶ 天线的重新设计会导致走线匝数的增加,需要注意 PCB上是否预留有足够的空间。如果布局空间无法有效的进行延伸布线,那么就必须采用外部调谐电容作为频率补偿方案。
如下的这些因素都会影响到 NFC/RFID标签的调谐频率:
▶ 在实际的生产环境当中,往往需要通过专门的仪器来测量 NFC/RFID标签的谐振频率。
动态 NFC标签天线的调谐频率可以使用带有环形探头的网络分析仪来进行测量。其中的射频电磁场可以由连接环形探头的网络分析仪(设置为反射模式,测量S11回波损耗)产生。环形探头可以购买成品,或者使用单匝线圈自行绕制,并且将其连接至同轴连接器。这样构建出的环形探头可以根据标签天线的尺寸相应的调整大小,进而达到更优的耦合效果。
▶通过上述的设备配置与连接,可以直接获得当前系统的谐振频率。
如下是一个用于实际测量的网络分析仪参数设置列表:
5 MHz
;20 MHz
;- 10 dBm
;Reflection 或者 S11
;log magnitude
;将 NFC 天线放置到连接有网络分析仪的环形探头磁场内,由于环形探头与 NFC标签天线相互耦合,从而导致环形探头的阻抗发生变化。当 NFC标签处于谐振频率的时候,环形探头的阻抗电阻达到最大值,而电抗恢复到自谐振值。环形探头的阻抗接近于50Ω
,可以通过 S11曲线上面的最小值进行证明。下图展示了某一个天线原型的谐振频率响应曲线:
NFC天线的谐振频率也可以采用信号发生器和示波器,以及两个环形天线来进行测量。测试步骤是将一个ISO 10373-7标准的环形天线(如下图所示)与信号发生器连接,从而产生出射频电磁场:
再通过示波器探头(1MΩ
或者 10MΩ
输入阻抗)或者 50Ω
阻抗的 BNC 电缆(示波器输入阻抗也设置为50Ω
),将另外一个 ISO 10373-7标准的环形天线连接到示波器。
此时,由于 NFC标签与第一个环形天线连接,通过信号发生器输出变化的信号使得NFC标签连接的天线产生电磁感应,这些电磁场会被连接在示波器的第二个环天线捕获。如果当前处于NFC标签的谐振频率时,那么流入 NFC 标签天线的电流
、NFC 标签天线产生的电磁波
、示波器显示的电压幅值
均将会达到最大值。
首先,让信号发生器输出峰峰值为 200mV
的正弦波信号。然后,以 5MHz
作为起点,逐步提高信号发生器的输出频率,直至达到示波器所测量到信号的最大幅值。最后,信号发生器所输出的频率就是NFC 标签的谐振频率。下图给了一款 NFC天线原型的频率响应曲线,也就是在不同的信号发生器频率下,示波器所测量到的信号幅值:
开发设计人员必须了解电路板上 NFC天线的理论与实际性能差异,这里列出一些注意事项。对于不同的NFC 读卡器,同一个 NFC标签天线所获得的通信效果并不相同,正如下面的示意图所展示的那样:
另外 PCB制造的工艺参数(例如铜层或者环氧层的厚度)也会对天线性能产生影响,这在更换板材供应商的时候需要格外注意。除此之外,同时使用多个动态NFC标签会导致天线相互耦合,从而出现谐振频率不同于单个天线的情况,例如下面的示意图所展示的情况:
更加值得注意的是,产品的外壳也会影响 NFC标签天线的通信效果,例如使用金属外壳所产生的法拉第笼效应,就会阻止NFC 读卡器的能量与信号传递到 NFC 标签天线。同时外壳也会影响 PCB天线的调谐频率,因而总是建议在最终成品上进行 NFC 射频性能的测试。
]]>▶总而言之,在实际量产过程当中,需要充分的考量到设计、原型、生产制造三个环节对于NFC 标签天线射频性能所带来的一系列影响。
长度
、宽度
、高度
三个参数共同决定,这些参数可以随时进行修改。除此之外,FreeCAD还可以使用其它模型作为参数;例如将一个立方体作为输入参数,FreeCAD就能够基于它创建出一个柱状的 3D 模型。FreeCAD并非只是为了完成某一项特定的工作,或者仅用于生成某一类特定的模型。使用者可以利用它创作小到电子元件与3D打印部件,大到建筑物的不同尺寸模型。由于每一种任务的工作流程并不完全相同,所以FreeCAD 分别提供了相应的工作台。目前网络上关于FreeCAD的应用资料较少,所以尝试利用本文记录一些日常使用的技巧,全文基于 2022 年9 月份发布的 FreeCAD 0.20.1版本撰写,文中所涉及的实例已经共享至我的 FreeCAD-Tutorial-Example。
依次选择 FreeCAD 顶部菜单栏上面的【Edit ->Preference...】,打开首选项窗口:
首先,依次在【General】界面进行语言
、界面风格
、默认工作台
的设置:
然后,再切换至的【Display】界面,在【Navigation】选项卡下面将3D 导航模式设置为 Blender
:
最后,继续切换到【Display】界面内的【Colors】选项卡,选择背景色为简单颜色
,并在弹出的颜色选择对话框中将其设置为#3C3C3C
:
保存上述设置之后,FreeCAD界面的语言格式会自动切换为中文,并且界面颜色调整为暗黑风格,此时将工作台切换至【Part Design】:
鼠标再次选中顶部菜单栏上面的【编辑 ->首选项...】,选择弹出窗口中的【草绘】界面,勾选显示1mm
的网格:
接下来,再打开弹出窗口上的【Part / PartDesign】界面,点选下图当中的所有 3 个选项:
FreeCAD的工作台提供了一系列针对不同模型用途的工具集,通过选择不同的工具集,可以制作不同种类的模型:
立方体
和球体
等;直线
、圆
、弧
;FreeCAD 的 3D 空间拥有 X
、Y
、Z
三个轴以及一个原点,其中 X
轴指向右侧,Y
轴指向后面,Z
轴指向上方,这三条轴线相交的位置就是原点,也就是X
、Y
、Z
坐标值均为零的点。
首先,依次点击工具栏上的【新建 -> 创建实体 ->创建草图】,鼠标选择 XY_Plane (基准平面)
:
然后,FreeCAD 就会自动进入到 Sketcher工作台,此时就可以开始着手在屏幕中间的区域进行草图的绘制工作:
接下来,使用右侧工具栏上的【创建圆】工具绘制出一个圆形,并且使用约束工具,将其直径约束为50mm
,同时将其圆心与坐标原点进行【重合约束】对齐:
最后,点击左侧的【Close】退出Sketcher 工作台,重新返回到【PartDesign】工作台的【模型】视图,并且鼠标点击右侧工具栏上的【凸台】工具:
此时,FreeCAD 自动切换至【PartDesign】工作台的【任务】视图,在这里同样将凸台的高度设置为50mm
,然后点击左侧的【OK】按钮:
此时,FreeCAD 再次切换回【PartDesign】工作台的【模型】视图:
在【PartDesign】工作台的【模型】视图当中,根据当前采用的鼠标3D 导航设置(前面已经设置为 Blender
模式),就可以对 3D模型进行全方位的观察:
完成上述操作之后,将文件保存到 FreeCAD-Tutorial-Example的 Example-1-Cylinder
目录下名为 Cylinder
的文档。除此之外,还可以通过如下的键盘快捷键组合,更加便捷的对 3D模型进行查看:
首先,在 FreeCAD-Tutorial-Example的 Example-2-Table
目录下新建一个 Table
空白文档。根据前面介绍的方法,使用 FreeCAD右侧工具栏上的【创建矩形】,绘制出一个长度约束为100mm
宽度约束为 50mm
的矩形:
➤ FreeCAD当中设置宽度的快捷键为【L】,设置高度的快捷键为【I】。
然后,分别选中下图【1】、【2】、【3】位置的点(选中后呈现绿色),并且点击右侧工具栏上的【对称约束】工具。最后,就可以得到一个与原点居中对齐的矩形,此时由于整个矩形处于完全约束状态,所以线条呈现出绿色。
➤ Sketcher工作台当中绘制的任何图形,都必须使其处于完全约束的状态。
接下来,使用 FreeCAD右侧工具栏上的【凸台】工具,将桌面拉伸成为一个厚度为3mm
的立方体,选中底部(此时导航立方体上面显示为BUTTON
),点击左侧工具栏上的【创建草图】按钮:
首先,绘制出 5mm * 5mm
的矩形作为桌脚的基础轮廓,然后再点击 FreeCAD右侧工具栏上的【外部参考几何体】,并且选择矩形的右侧边框作为外部参考线,最后分别选中5mm * 5mm
矩形与 100mm * 50mm
矩形的右上角顶点,同时分别点击右侧工具栏上的水平与垂直距离约束,将约束距离设置为3mm
。
最后,再借助【凸台】工具,将这个5mm * 5mm
的矩形拉伸成为高度为 50mm
的桌腿。
在 FreeCAD 右侧工具栏上,选择刚才创建的桌腿凸台Pad001
,然后点击右侧工具栏上的【镜像】按钮。
在镜像参数当中选择【垂直草绘轴】,就可以垂直于草绘时所选择的轴,自动生成出一条桌腿。
重复刚才的步骤,不过这次选择【水平草绘轴】,从而就可以自动生成出另外一条桌腿。
仍然选中之前创建的桌腿凸台Pad001
,这次点击右侧工具栏上的【环形阵列】按钮。
这样就可以创建出最后一条桌腿,到这里一张完整的桌子就绘制完成了。
➤ 使用环形阵列功能时,需要注意左侧
角度
和出现次数
两个参数的设置。
首先,在 FreeCAD-Tutorial-Example的 Example-3-ISO-PRAC2
目录下新建一个ISO-PRAC2
空白文档。然后,再分别创建一个实体和草图,选择右侧工具栏上的【前视图】按钮,切换至XZ_Plane
平面。最后,鼠标点击【OK】按钮进入Sketcher 工作台。
点击 FreeCAD右侧工具栏上的【创建折线】工具,绘制出如下的草图,绘制过程当中可以通过按下【M】键循环切换工具的行为,从而得到下图当中的圆弧效果。
绘制完上图的圆弧效果之后,需要选中并且删除位于圆弧左侧的【相切约束】:
使用右侧工具栏上的【重合约束】,让下图当中选中的两个点(绿色)自动进行闭合。
使用鼠标进行拖动调整,然后删除弧形右下角的垂直约束,最终就可以得到下面的图形。
接下来,再分别为上述图形当中的线条添加水平约束、垂直约束、宽度约束、长度约束、相等约束、半径约束。
完成全部约束之后,分别选中弧形的圆心和草图的原点,然后点击右侧工具栏当中的【重合约束】按钮,使得草图与原点完成对齐。
实现完全约束之后的草图如下面所示,可以看到,所有的线条都呈现出了绿色的效果:
在 Sketcher工作台完成草图的绘制工作之后,就可以切换至 Part Design工作台,利用工具栏上的【凸台】功能将前面绘制的图形拉伸为40mm
高度的三维形状,从而就完成了 ISO-PRAC2零件的全部绘制工作。
在 FreeCAD-Tutorial-Example的 Example-4-ISO-Chair
目录下新建一个 Chair
空白文档,选择XY_Plane (基准平面)
,使用【创建圆】工具,并将其半径约束为 100mm
。
按照上面的操作步骤,分别用鼠标选中圆心和原点,再点击右侧工具栏上的【重合约束】,就可以完成圆心与原点的居中对齐。
接下来,鼠标选中上面绘制好的圆形,然后点击工具栏右侧的【切换辅助线】按钮,就可以将其切换为辅助线。
参考线用于在 Sketcher工作台里辅助绘制工作,通常呈现为蓝色,而在 PartDesign 工作台当中并不会被显示。
选择右侧工具栏的【三角形】绘制工具,画出一个三角形,然后分别添加【水平约束】和【重合约束】,最终得到如下的图形。
首先,清除最外侧较大的那个蓝色圆形。然后,鼠标选择三角形任意两条边的连接点,按下键盘上面的【Delete】键,此时FreeCAD 会自动断开两条边之间的连接关系。
首先,使用 FreeCAD右侧的【创建线】工具绘制出两条线段。然后,使用【重合约束】将它们连接到草图原点,再使用【夹角约束】将两条线段与垂直坐标轴的夹角设置为60°
度,同时将两条线段设置为【相等约束】。
首先,选中一条之前绘制好的线段。然后,鼠标点击工具栏右侧的【距离约束】按钮。最后,将其长度设置为250mm
。
利用右侧工具栏上的【圆弧】创建工具,分别绘制出 3个圆弧。然后分别添加【相等约束】,并且使用【半径约束】将其半径设置为120mm
。
➤ 为了更加方便的进行展示,在接下来的示例当中,将 FreeCAD的网格尺寸调整为
10mm
。
首先,分别选中蓝色的圆形参考线,以及每一个弧形的圆心。然后,点击【将点约束至对象】按钮,从而将圆心约束到圆形的参考线上面。
接下来,选择已经被固定至蓝色圆形参考线上面的弧形圆心,以及蓝色参考线段与Y轴,继续使用【将点约束至对象】功能,最后就可以得到如下的图形:
使用工具栏右侧的【相切约束】,闭合草图最外侧的零散线段。
如下就是草图最外侧零散线段实现完全约束之后的效果。
➤ 注意不要忘记将之前绘制的两条线段切换为参考线模式。
3mm
的三维形状;通过所有
;Pocket
,然后在右侧工具栏,选中【环形阵列】,把产生次数
参数设置为 3次,从而自动产生出另外 2 个凹坑;首先,按住【CTRL】键多选相应的边。然后,分别将内侧的弧形设置为10mm
的斜角,外侧的弧形设置为10mm
的圆角,最终得到的效果如下所示。
Bottom
新建草图;30mm
的圆形,并使用【固定点至对象约束】将其圆心与Y 轴重合;160mm
,从而完成草图绘制;180mm
的椅脚;出现次数
参数设置为3
,从而自动创建出另外的 2 条椅脚;使用【空格键】,可以切换 FreeCAD组合浏览器当中的每一个操作步骤的显示与隐藏。
]]>Spring
全家桶、前端Vue
全家桶),而开发方式也日趋套路化与工程化,上手难度与技术门槛以肉眼可见的速度不断下探,进而伴随着大量从业人员的持续涌入,整个行业全面开启了996 内卷模式。除此之外,叠加近几日中概股跌穿了板凳,以及反垄断监管的不断强化,互联网行业合规经营的大幕徐徐拉开。未来全行业的整体薪酬水平,必然回归至类似财务会计这类市场化职位应有的水平。高薪光环终究是到了褪去的时刻,重新回到利润与收支挂钩的市场化薪酬体系,将会是整个行业未来的大势所趋。
笔者在 IT 行业的从业时间比较长,经历过 2014~2018
年国内互联网的黄金发展时期,目睹过众多互联网企业,在各路资本的助推之下大干快上,薪资水平与岗位数量两旺。然而时过境迁,又不得不感慨市场规律的强大力量:任何市场化行业,其薪酬与职位数量,都只会与该行业产生的实际利润相关。过去资本追捧互联网题材,一方面由于国内缺乏健全的反垄断机制,另一方面在于涌入资本对于美股上市有着极为强烈的偏好。在两者共同的化学反应之下,造成了国内互联行业短期的急剧膨胀,大量互联网企业出于垄断流量,或者资本市场套利的目的,在各类不赚钱甚至也不具备赚钱潜力的题材背书之下,如同雨后春笋一般冒出头来。
然而最近一年多以来,各家互联网大厂陆续发起批量的裁员动作,同时不断缩减校园招聘的head count
,已然意味着互联网行业的泡沫开始走向消退。从国家宏观产业与经济发展的角度而言,互联网行业泡沫的出清,有益于中国科技行业整体的长远健康发展。其主要原因在于国内互联网企业在做大做强之后,对于各路流量完成了事实上的垄断,然而后续并没有将资金投入至更深层次的技术创新,反而在各式花样繁多的金融创新道路上渐行渐远。例如国内头部的互联网企业,几乎每一家都有推出自己的金融消费贷款业务,大量的资金和人力资源都投放在了垄断流量(例如社区团购)、金融信贷(例如×呗
、×宝
、×金
、×条
等高息信贷产品)方面。
反观海外的 谷歌 Google、脸书 Meta等互联网巨头,就并未在本企业的移动 App与网站产品当中,夹带与金融消费贷相关的业务与服务,而是在盈利并且获取行业优势地位之后,广泛的为开源技术社区进行贡献,新的语言(Go
、Dart
、Hack
、React
)、新的操作系统(Fuchsia
、Chrome OS
、Android
)、新的算法框架(RankBrain
、Deepmind
、Prophet
)、新的硬件(Tensor
、Portal
、Oculus
、BCI
)层出不穷。而对比同期的国内互联网企业,在技术创新与开源社区贡献方面,其建树近乎乏善可陈。
以搜索引擎巨头谷歌 Google 为例,其现有的金融业务当中,Google Pay基于其自有的 Android手机操作系统,仅提供移动支付的基础设施。而与其核心搜索及广告相关的业务当中,贷款业务在其业务闭环之内,借款人限于客户,用途也仅限于对谷歌的广告支出;整体上,谷歌并未推出其它金融服务,从而利用其巨大的流量与强大的数据收集分析能力获利。然而这个中的原因,并非是由于海外的互联网巨头们,自带白莲花属性,能够做到出淤泥而不染。而是在于其所归属的市场主体,拥有着健全的反垄断监管法律体系。企业难以通过流量与数据,随意扩张经营版图。想要获得更多的利润,必须依靠技术层面的创新带动,而非依赖其自身的垄断支配地位。
近年以来,面对美帝在基础科技方面,三番五次的卡脖子行为。国内 IT技术行业头重脚轻、有软无硬、缺芯少魂的短板暴露无遗。而彼时的各大互联网巨头们,却正在为孰能垄断社区团购流量,而激战正酣。所以人民日报专门于2020 年的双十二期间刊文:《别只惦记着几捆白菜的流量,科技创新的星辰大海更令人心潮澎湃》。时间转瞬即逝,来到了两年之后的今天,针对互联网行业的反垄断监管祭出重拳,其意图就是倒逼国内科技企业与互联网巨头们,将精力放回至技术创新的主赛道上面,合法合规经营,停止无序竞争与流量垄断。
切换一个视角,美帝今日之所以能够制霸于全球,有媒体认为原因在于其发达的资本市场与金融行业,也有媒体认为在于其得天独厚的地理位置与高效的集约化农业,而更多媒体则认为是在于其强大的军事实力。而在笔者看来,无论是军事
、农业
、金融
,这些行业与产业背后的科技属性才是美帝百年以来真正的立国之本。除了脸书、谷歌这样的互联网巨擎,以及微软、苹果这类耳熟能详的科技大触之外。美帝还拥有着工业软件领域的Autodesk、Ansys、Altair,嵌入式操作系统领域的Vxworks、FreeRTOS、QNX,电子自动化设计领域的Cadence、Synopsys两巨头,数学分析与仿真领域的Matlab、Mathmatical,这些厂商在全球基础软件细分市场的份额约在70% ~ 90%
之间。
而在底层硬件电子技术方面,从电子测量仪器行业的Keysight、Tek、Lecroy、Fluke,到拥有琳琅满目模拟/数字芯片产品线的National Semiconductor、TexasInstruments、Maxim Integrated、AnalogDevices,以及专注于 FPGA 可编程逻辑器件的Xilinx、Altera、Lattice、Microsemi,这些体量与产品线都属于灭霸级存在的IC 厂商,几乎垄断了全球七成以上的市场份额。整体而言,美帝的 IT行业,呈现出 芯片电子技术 + 基础软件 + 互联网应用至上而下、齐头并进的全能型产业格局。
我国在芯片电子技术方向的落后程度,相信大家已然从近两年的科技制裁与缺芯潮里有所领悟,无需笔者再耗费过多的笔墨。而软件程序技术方向,虽然坐拥宠大的人口基数与工程师红利,但是在工业与民用领域的基础性软件产品当中,要么面临着功能与算法方面的重大缺陷,要么直接就处于一片空白的蛮荒状态。整体而言,由于市场化应用程度不高,导致相关企业的盈利能力普遍较弱,从业人员的薪酬待遇水平,远远不及处于资本推波助澜之下的互联网。而在国内互联网行业高歌猛进的这几年当中,由于无数资本的蜂拥进场,快速抬高了互联网从业人员的整体薪酬水平,致使大量原本就读于电子信息工程、自动化、应用数学、机械、物理、化学等理工科专业的优秀毕业生,悉数放弃本专业,而转投互联网Web技术方向。各个基础行业面临着严重的人才流失,而知乎上关于其它专业或者行业,转投互联网的讨论也一直延续至今。学生娃娃们都想着趁年轻,冲入互联网行业挣上一笔快钱。而在国家真正急需的光刻设备
、离子注入设备
、高纯度蚀刻用硫酸
、EDA 自动布线算法
、工业设计与仿真软件
、高精度多轴数控机床
等方向,却由于产业化能力不足,从业人员薪酬水平明显低于互联网,因而一直乏人问津。
一个国家与民族的强大,必然离不开科技的鼎力支持,互联网企业的合规经营与去金融化,虽然会带来短期的裁员阵痛,但是同样可以倒逼互联网公司们,将企业资源集中到科技创新的方向开疆扩土,让人才重新回流至本专业所属的技术领域,特别是在国家当前所紧缺的底层硬核科技方面。藉以此文,笔者愿与众IT 行业研发同仁共勉之,合光同尘,知行合一。
]]>电阻
与 电容
等基本元件,相关的定律(欧姆定律
、焦耳定律
、基尔霍夫定律
)定理(叠加定理
、戴维南定理
、诺顿定理
)和等效变换(电源等效
、串并联等效
、星形三角形等效
),以及基本的分析方法(支路电流法
、结点电压法
、非线性电阻分析
);第2 部分则以电磁感应现象作为核心,同时引入安培力
、洛仑兹力
、磁通量
等电磁学基本概念。第 3 部分围绕交流信号展开,包含了动态元件电阻
、电容
、电感
相关的交流电路,并且介绍了 功率因数
的提高,RC 与 LC电路,以及三相交流电路;第 4部分介绍了互感与变压器,主要讨论互感现象与变压器的原理;第5 部分则主要讨论电路的过渡过程,比如RC 与 RL 电路的过渡过程,以及其中电压
与 电流
随着时间变化的规律和影响过渡过程快慢的时间常数
,同时还引入了换路定则与微分电路
以及 积分电路
。
电子带有最小单位的负电荷,质子则带有最小单位的正电荷,这些带电粒子所携带的电量\(e = - 1.60 \times 10^{-19} C\)就被称为元电荷。
同种电荷之间相互排斥,异种电荷之间相互吸引。真空当中两个静止点电荷\(Q_1\) 与 \(Q_2\) 之间的相互作用力 \(F\)(库仑力),与它们的电荷量的乘积成正比,与它们的距离\(r\)的二次方成反比,作用力的方向在它们的连线上面,这就是库仑定律:
\[库仑力 F = 静电力常量 k \frac{点电荷量 Q_1 \cdot 点电荷量 Q_2}{距离r^2}\]
注意:上述公式当中的 \(k =9.0 \times 10^9\ N \cdot m^2 / C^2\)称为静电力常量。
电荷即不能创造,也不能被消灭,它只能从一个物体转移到另外一个物体,或者从物体的一部分转移至另外一个部分,这就是电荷守恒定律。
静电感应是指将电荷靠近近不带电的物体,从而使其带电的现象。这种利用静电感应使得物体带电的方式,称为感应起电。感应起电并没有创造电荷,只是暂时性分离了物体上的正负电荷。
电场是一种带电物体周围存在的特殊物质,其基本性质是对放入其中的电荷存在力的作用,这种力就称为电场力。放置在电场当中的电荷,所受到的电场力\(F\) 与其电荷量 \(q\)的比值,称为电场强度,简称为场强,通常用字母E 表示,单位为牛/库N/C
:
\[电场强度 E = \frac{电场力 F}{电荷量 q}\]
电场线用于表征电场当中各点的场强大小与方向,由一系列从正电荷出发,到负电荷截止的曲线所组成,曲线密度越大,表征的电场强度也就越大。
电路就是电的流通路径,通常由电源
、负载
、导线
、开关
组成。而电路图是为了便于对电路进行分析,采用电路符号来表示电路上的实际元件,也称为电路原理图。其中,串联电路(元件首尾依次相连)和并联电路(元件首尾并列连接)是最为基本的两种电路组成形式:
总体上看,电路一共拥有通路
、开路
、短路
三种物理连接状态:
电荷有规则的运动形成电流,其大小等于导体横截面电荷量\(q\)(库仑C
)与单位时间 \(t\)(秒s
)的比值,该比值就称为电流强度,简称为电流,用字母\(I\) 进行表示:
\[电流 I = \frac{电荷量 q}{时间 t}\]
如果在 1
秒钟内通过导体横截面的电荷量为 1
库仑,那么导体当中的电流就是 \(1 安培 =\frac{1\ 库仑}{1\ 秒钟}\)。电流常用的单位除了安培(\(A\))之外,还有毫安(\(mA\))和微安(\(\mu A\))以及纳安(\(nA\)),它们之间的换算关系如下所示:
\[1 A = 10^3 mA = 10^6 \mu A = 10^9 nA\]
注意:直流电流的
大小
与方向
都不会随时间变化,采用大写字母\(I\)表示;而交流电流的大小
与方向
均会随着时间进行变化,采用小写字母\(i\) 表示。
电压是衡量电场力做功能力的物理量,电路当中a 与 b 两点之间的电压 \(U_{ab}\) 等于将单位正电荷从a 点迁移至 b点时,电场力所做的功,其值等于耗费的总功率 \(W\)(焦耳J
)与迁移的总电荷量 \(q\)(库仑 C
)之比:
\[电压 U_{ab} = \frac{功率 W}{电荷量 q}\]
如果通过 1
库仑电荷量消耗的总功率为 1焦耳,那么导体上的电压就为 \(1 伏特 = \frac{1\焦耳}{1\ 库仑}\)。电压的单位为伏特V
,除此之外,还有毫伏(\(mV\))和微伏(\(\mu V\))以及纳伏(\(nV\)),它们之间的换算关系如下所示:
\[1 V = 10^3 mV = 10^6 \mu V = 10^9 nV\]
高电位
指向低电位
方向;注意:直流电压的
大小
与方向
都不会随时间变化,采用大写字母\(U\)表示;而交流电压的大小
与方向
均会随着时间进行变化,采用小写字母\(u\) 表示。
在电路当中任意选择一个参考点(通常选择电路的接地点),电路上其它各点相对于参考点的电压降或者电压升,就是各个点的相对电位,其单位与电压一样为伏特V
。此时,电路上 a 与 b两点之间的电压 \(U_{ab}\) 等于a 点电位 \(U_a\) 与b 点电位 \(U_b\)之差:
\[U_{ab} = U_a - U_b\]
当某点相对参考点的电位为正值时,表示该点的电位高于参考点;而当某点相对参考点的电位为负值时,则表示该点的电位低于参考点。
注意:实际工程当中,通常将大地作为零电位参考点。而在电路分析时,通常会将多个元件汇集的公共点视为参考点。
电动势用于表示电源将其它形式的能量(非静电力)转换为电能的能力,通常使用大写字母\(E\)表示,单位同样为伏特V
。其值等于电源能量将电荷从负极
传送至正极
所做的功W
(焦耳 J)与被传送的电荷量q
(库伦 C)之比:
\[电动势 E = \frac{电源做功 W}{电荷量 q}\]
注意:电动势的方向被规定为从电源内部的负极指向正极,即与电源两端电压的方向相反。
电功率是指电流在单位时间内所做的功,其值等于电压\(U\)(伏特)与电流 \(I\)(安培)的乘积,通常采用字母P表示,单位为瓦特,简称为瓦W
:
\[电功率 P = 电压 U \times 电流 I\]
注意:额定功率是指用电器在长时间稳定工作的情况下,所需要耗费的功率。
电流所做的功称为电功,电流做功的过程就是电能转换为其它形式能量的过程。电流在某段电路上所做的功,等于该电路两端的电压U
(伏特)与通过电流I
(安培)以及通电时间t
(秒)的乘积,通常采用字母 W进行表示,单位为焦耳 J
:
\[电功 W = 电压 U \cdot 电流 I \cdot 时间 t\]
由于焦耳的单位较小,家庭用电通常使用度作为电功的计量单位。1
度电就是功率为 1
千瓦的用电设备运行 1
小时所消耗的电能:
\[1 度 = 1 千瓦 \cdot 时 = 1 kW \cdot h\]
电功的度与焦耳两个单位的换算关系如下面公式所示:
\[1 度 = 1000 瓦 \times 3600 秒 = 3.6 \times 10^6 焦\]
电阻元件的基本特征是消耗电能,通常采用字母R 进行表示,对应的电路符号如下图所示:
电阻值的单位是欧姆Ω
,除此之外,常用的单位还有:
\[1 MΩ = 10^3 kΩ = 10^6 Ω\]
导体的电阻与材料的电阻率 \(\rho\)(欧米 \(Ω\cdot m\)),以及长度 \(L\)(米 \(m\)),横截面积 \(S\)(平方米 \(m^2\))有关:
\[电阻 R = 电阻率 \rho \cdot \frac{长度 L}{横截面积 S}\]
金属材料的电阻率与温度相关,温度越高电阻率越大,下面表格是几种常见金属材料在20°C
左右的电阻率:
金属材料 | 电阻率 \(\rho\)(\(Ω \cdotm\)) | 金属材料 | 电阻率 \(\rho\)(\(Ω \cdotm\)) |
---|---|---|---|
金 | \(2.44 \times10^{-8}\) | 铝 | \(2.82 \times10^{-8}\) |
银 | \(1.59 \times10^{-8}\) | 钨 | \(5.6 \times10^{-8}\) |
铜 | \(1.72 \times10^{-8}\) | 铁 | \(10.0 \times10^{-8}\) |
阻值可以改变的电阻称为可变电阻,或者电位器,其内部主要有限流和分压2 种连接形式:
注意:限流连接方式移动滑片P 可以控制负载 R上的电流;而 分压连接方式:移动滑片P 可以控制负载 R上的电压。
电阻串联之后的总电阻等于各个电阻的阻值之和\(R = R_1 + R_2 + R_3\):
电阻并联之后的总电阻等于各个电阻阻值的倒数之和\(\frac{1}{R} = \frac{1}{R_1} + \frac{1}{R_2}+ \frac{1}{R_3}\):
两片平行金属板中间夹上电介质就可以组成最为简单的电容器,其电路符号如下图所示:
平行板电容器的电容 \(C\)可以通过下面的公式计算得到:
\[C = \frac{介电常量 \epsilon \times 正对面积 S}{4 \pi \times 静电力常量 k\times 极板之间距离 d}\]
电容器所携带的电荷量 Q
与其两极之间的电势差 U
的比值称为该电容器的电容值,即一个用于表征电容器容纳电荷能力的物理量:
\[电容 C = \frac{电荷量 Q}{电势差 U}\]
国际单位制当中,电容的单位是法拉,简称法F
,常用的单位还有微法(\(\mu F\))、纳法(\(nF\))、皮法(\(pF\)):
\[1 F = 10^6 \mu F = 10^9 nF = 10^{12} pF\]
普通电容器通常没有极性,而电解电容在使用时需要区分正负极,其电路符号如下图所示:
注意:电解电容的优点在于价格便宜,容值较大;但是同时也有体积较大,温度稳定性比较差的缺点。
由于电路的分布特点而具有的电容称为分布电容,例如线圈的相邻两匝之间、两个分立的元件之间、两根相邻的导线之间,都会存在着一定的分布电容。其对于电路的影响,等效于为电路并联上一个电容器。低频交流电路当中,分布电容的容抗较大,对于电路影响较小。而对于高频交流电路,分布电容带来的影响则不能忽略。
电容器的特点主要体现在其所具备的通交隔直方面:
电容器的通交和隔直特性通常同时体现,例如下图所示电路,输入信号\(U_i\)是一个含有直流分量的交流信号,而输出信号 \(U_o\)当中只存在交流成份,直流成分已经被电容器所滤除:
除此之外,电容还具有储能特性和两端电压不会突变的特性:
容抗表征的是电容器对于交流信号的阻碍作用,其单位为欧姆1Ω
,容抗值 \(X_C\)与交流信号的频率 \(f\)以及电容器容量 \(C\)相关:
\[容抗 X_C = \frac{1}{2 \pi \cdot 频率 f \cdot 电容 C}\]
注意:通过上述公式可以发现:当电容值恒定时,频率越高容抗越小;而当频率一定时,电容越大容抗越小。而对于频率\(f = 0\) 的直流信号,电容的容抗 \(X_C \rightarrow\infty\),即相当于断路。
电容器在使用时,经常会遇到容值不够,或者耐压能力不足的问题,此时就需要将电容器串联或者并联起来使用。当电容器串联使用时,虽然容值会减少,但是可以提升耐压值。而电容器并联使用时,虽然增大了容值,但是耐压值并没有发生变化。
将多个无极性电容器首尾相连,就可以组成如下的电容串联电路:
无极性电容串联之后,相当于只有最外层的两个极板才可以感应到电荷,并且两个极板之间距离也被增大,此时总电容的倒数等于各个电容器的倒数之和,即总电容值小于每一个串联电容的值,但是耐压值却得到了提高:
\[\frac{1}{C} = \frac{1}{C_1} + \frac{1}{C_2} + \frac{1}{C_3}\]
对于下面这个由电容器 \(C_1\) 和\(C_2\) 构成的串联分压电路:
电容器 \(C_1\) 的容抗 \(X_{C1} = \frac{1}{2 \pi f C_1}\),而 \(C_2\) 的容抗 \(X_{C2} = \frac{1}{2 \pi fC_2}\),进而通过分析以后可以得出如下结论:
有极性电容器(电解电容)的串联,分为顺序串联和逆序串联两种情况。
顺序串联是指 \(C_1\) 的负极与 \(C_2\)的正极相连,这种串联方式可以提高电容器的耐压值。即当 \(C_1\) 与 \(C_2\)的容值与耐压值都相等时,串联以后的电容 \(C\) 只有 \(C_1\) 和 \(C_2\) 的一半,但是耐压值却要比 \(C_1\) 和 \(C_2\) 大上一倍。
逆序串联是指将电容器 \(C_1\) 与 \(C_2\)的正极或者负极相互连接在一起,有极性电容在逆序串联之后不会再具有极性,因而可以作为无极性电容来使用:
电容并联是指将电容器的正极与负极分别进行连接:
由于电容并联之后,相当于增大了金属极板的面积,所以并联之后的容值等于各个电容的容值之和,不过此时耐压值并未得到提高:
\[C = C_1 + C_2 + C_3\]
电容并联之后所形成的电路,主要具有如下三个特点:
一个较大容值的电容与一个较小容值的电容并联:将一个容值较大的电容器(例如电解电容)与一个容值较小的电容器(例如瓷片电容)并联在一起,大电容主要工作在低频状态,高频状态下虽然其容抗几乎为零,但是呈现出的感抗却非常大,此时总的阻抗依然会较大,所以大电容在高频情况下的阻抗会大于低频时的阻抗,主要用于滤除低频干扰信号。而并联的小电容则主要工作在高频状态,由于几乎不会存在感抗,所以小电容对于高频信号的容抗相对较小,高频干扰信号可以被有效的引入大地。
两个相同容值的电容并联:除了增加容值,减小安装体积之外,还可以提高电路的可靠性,即使其中一个电容开路,另外一个电容也可以让电路正常工作。除此之外,由于容值较小的电容,漏电流相对较小,因此并联之后可以避免更大容值电容器所带来的较大漏电流。
如果并联的两个相同容值电容器 \(C_1\)和 \(C_2\)分别采用正温度系数电容器(例如聚酯电容)和负温度系数电容器(例如聚丙烯电容),当外界环境温度发生变化时,两个电容的容值会呈现出此消彼长的关系,从而保持总电容\(C = C_1 + C_2\) 的基本恒定。
欧姆定律表述了电路当中的电流,如何由电压和电阻来决定。即导体上的电流\(I\)(安培),与导体两端的电压\(U\)(伏特)成正比,与导体的电阻\(R\)(欧姆)成反比:
\[电流 I = \frac{电压 U}{电阻 R}\]
伏安特性曲线是导体当中电压
与电流
的关系曲线,其中纵轴表示电流\(I\),而横轴表示电压\(U\)。
注意:如果元件的伏安特性体现为经过原点的一条直线,那么这样的元件就称为线性元件。
焦耳定律反映了电能与热能之间的转换关系,即电流通过导体产生的热量\(Q\)(焦耳),与通过电流\(I\)(安培)的二次方成正比,与导体的电阻\(R\)(欧姆)成正比,与通电时间\(t\)(秒)成正比:
\[热量 Q = 电流 I^2 \times 电阻 R \times 时间 t\]
焦耳简称焦J
,是能量和做功的国际单位,其值等于1
瓦的功率在 1
秒内所做的功 \(1 焦=1 瓦·秒\)。
把电源接入电路就会形成一个有电流通过的闭合电路,可以将闭合电路视为如下两个组成部分:
根据能量守恒定律,电源内电路提供的电能为 \(W\),等于外电路消耗的电能\(W_1\)与内电路消耗的电能 \(W_2\) 之和:
\[内电路提供的电能 W = 外电路消耗的电能 W_1 + 内电路消耗的电能 W_2\]
假设闭合电路当中通过的电流为 \(I\),内电阻为 \(r\),外电阻为 \(R\),结合上述方程与焦耳定律、电动势的定义就可以推导得到:
\[电流 I = \frac{电源电动势 E}{外电阻 R + 内电阻 r}\]
即闭合电路当中的电流 \(I\) 与电源的电动势 \(E\) 成正比,与内外电阻之和\(R + r\)成反比,这就是闭合电路的欧姆定律。
引入基尔霍夫定律之前,需要介绍几个与之相关的概念,下面电路当中的\(U_1\) 和 \(U_2\) 分别为电压源:
基尔霍夫电流定律(KCL):电路当中任意一个结点流出的电流,等于流入结点的电流之和:
\[\sum I_{流入} = \sum I_{流出}\]
使用基尔霍夫电流定律 KCL 列写电路方程的步骤如下所示:
基尔霍夫电流定律不仅适合于电路当中的任意一个结点,同样也适用于电路当中的任意一个闭合面,这个闭合面被称为广义结点:
例如上图当中的 A
、B
、C
三个结点所形成的三角形电路,就可以视为一个广义结点:
\[\begin{cases}I_A = I_{AB} - I_{CA} \\I_B = I_{BC} - I_{AB} \\I_C = I_{CA} - I_{BC}\end{cases}\impliesI_A + I_B + I_C = 0\implies\sum I = 0\]
基尔霍夫电压定律(KVL):沿着电路当中任意一条回路,按照指定方向绕行一周,各个部分电压的代数和恒等于零。
\[\sum U = 0\]
使用基尔霍夫电压定律 KVL 列写电路方程的步骤如下所示:
注意:基尔霍夫电压定律 KVL还可以推广应用于任意的开口电路。
▶【例题】求解下面电路的开口电压 \(U_{ab}\) ?
◉【解答】首先,标识出上面电路开口电压 \(U_{ab}\) 的参考方向,假设 \(U_{ab}\) 分别与支路 a
和b
组成一个闭合回路;然后,绘制出电路的绕行方向,并且取电压升为正,电压降为负;最后,就可以利用KVL 列写出如下的关系式:
\[U_S - I R_S - U_{ab} = 0\impliesU_{ab} = U_S - IR_S\]
利用等电位法求解等效电路的步骤如下所示:
高电位
到低电位
,采用英文字母逐个进行标识;等电位点
,并且逐一理清各个电阻连接的关系;下面左侧为原始的原理图,右侧为利用等电位法分析之后得到的等效电路:
▶【例题】下图左侧电路当中 \(R_1 = R_2 = R_3= 3Ω\),\(R_4 = R_5 = R_6 =6Ω\),求解 E
与 F
两端的电阻?
◉【解答】标识出原电路上的等势点a
、b
、c
,从高电势点 \(E\) 开始,首先将两个 a
点合并到一起,理顺电阻之后,标识电流在 a
点的去向,即分别经过 \(R_1\)、\(R_2\)、\(R_3\) 流向 b
点;然后理顺电阻并标识电流在 b
点的去向,即分别经过 \(R_4\)、\(R_5\)、\(R_6\) 流向 c
点,最后流出F
点。根据上图右侧的等效电路,就可以计算得到 E
与 F
两端的电阻 \(R =3Ω\)。
▶【例题】下图左侧电路当中 \(R_1 = R_3 =4Ω\),\(R_2 = R_5 = 1Ω\),\(R_4 = R_6 = R_7 = 2Ω\),求解 a
与 b
两点之间的电阻?
◉【解答】标识出原电路上的等势点a
、b
、c
、d
,首先合并等势点a
,电流从 a
点开始分为三路,分别经 \(R_2\) 流向 b
点,经 \(R_3\) 和 \(R_1\) 流向 d
点;然后合并等势点 b
,电流从 b
点开始分为两路,分别经过 \(R_5\) 和\(R_4\) 流向 c
点和d
点;最后合并等势点 c
,电流从 c
点也分为两路,分别经过 \(R_6\) 和 \(R_7\) 流向 d
点;根据上图右侧的等效电路,就可以计算得到 a
与b
两点之间的电阻 \(R =1Ω\)。
▶【例题】下图左侧电路当中 \(R_1 = R_2 = R_3= R_4 = R_5 = 30Ω\),求解 a
与 b
两点之间的电阻?
◉【解答】标识出原电路上的等势点a
、b
、c
,从高电势点 \(a\) 开始,标识出电流在 a
的去向,即分别经过 \(R_1\)、\(R_2\) 流向 b
点,以及分别经过\(R_4\)、\(R_3\) 流向 c
点;接下来,合并c
点之后理顺电阻,并且标识出电流在 c
点的去向,即经过 \(R_5\) 流向b
点;根据上图右侧的等效电路,就可以计算得到 a
与 b
两点之间的电阻 \(R =11.25Ω\)。
对称电路是一种能够上下
或左右
进行对称的电路,这种对称既体现在电路结构上,也体现在元件参数上,并且对称结点的电位相等,对称支路上的电流相同。
化简对称电路可以采用折叠法,即将电路的对称部分重合起来,然后求解等效电阻,并最终得到一个被精简掉一半的电路。
以上图左侧电路的 AOB
作为折叠线,由于各条之路均为 2个电阻的串联,所以等效之后采用 \(\frac{3\times 3}{3 + 3} = 1.5Ω\)电阻代替,进而最终得到右侧的等效电路。
如果相同电位 2个结点之间的电位差为零,那么就可以将这 2个结点视为直接短路。
根据电路的对称性,前述电路当中的 C、D
和E、F
分别为等电位点,可以直接对其进行短路处理。这样并不会改变各个结点的电位和各条支路上的电流分布,从而最终得到上图右侧的等效电路。
由于对称电路位于对称轴上的结点具有特殊性质,可以将其与联结该结点的对称支路断开,这种对称电路的等效方法称为断开法。
断开前述电路在对称轴上的结点 \(O\),得到 \(CO'E\) 和 \(DO''F\) 两条支路,其中 \(O'\) 与 \(O''\)为等电位点,这样同样不会改变电路上各个结点的电位以及各条支路上的电流分布。
可以将电阻 \(R_1\)、\(R_2\)、\(R_3\)、\(R_4\) 和内阻为 \(R_5\)的检流计(一种用于高精度测量电流大小的仪器)连接成如下的惠斯通电桥电路,该电路拥有4 个桥臂 \(R_1\)、\(R_2\)、\(R_3\)、\(R_4\);当这 4 个桥臂的电阻乘积相等时 \(R_1 \times R_2 = R_3 \timesR_4\),检流计的读数为零,这种状态称为电桥的平衡状态,相应的\(R_1 \times R_2 = R_3 \times R_4\)就被称为电桥的平衡条件。
当电桥处于平衡状态时,检流计显示 CD
支路的电流为零,说明2个结点的电位相等,可以将其直接进行短路连接,这样并不会改变电路当中各个结点的电位和支路电流的分布,此时A
、B
点之间的输入电阻 \(R_{AB} = (R_1 // R_2) + (R_3 // R_4) = \frac{R_1R_2}{R_1 + R_2} + \frac{R_3 R_4}{R_3 + R_4}\)
除此之外,在电桥平衡时,由于 CD
支路的电流为零,所以也可以对其进行开路处理,虽然同样不会改变电路当中各个结点的电位和支路电流分布,但是此时A
、B
点之间的输入电阻发生了变化 \(R_{AB} = \frac{(R_1 + R_2) + (R_3+ R_4)}{R_1 + R_2 + R_3 + R_4} = \frac{R_1 R_2 + R_1 R_4 + R_2 R_3 + R_3R_4}{R_1 + R_2 + R_3 + R_4}\):
总结:当电桥处于平衡状态时,如果将同电位的两个结点短路,可以使得原电路减少一个结点;而如果将同电位的两个结点开路,则可以使得原电路减少一个回路;这两种方法都可以用于求取
A
和B
两点之间的等效电阻,可以酌情选择使用。如果电桥不满足平衡条件,就不能采取上述方法进行等效电路的求解。
▶【例题】求解下图左侧电路 A
与 B
之间的输入电阻?
◉【解答】由于上图最左侧的电桥电路,满足 \(10Ω \times 15Ω = 5Ω \times 30Ω\)的电桥平衡条件,这里可以先将它转换为中间的电路形式,然后将CD
支路断开,从而得到最右侧的等效电路。根据该等效电路上各个电阻之间的串并联关系,就可以轻松的求解得到A
与 B
两点之间的等效电阻 \(R_{AB}\):
\[R_{AB} = [(5+15) // (10+30)] // 15 = \frac{120}{17} Ω\]
不含有电源
的电阻电路又称为无源二端网络,求解无源二端网络的输入电阻时,可以在下图所示电路的A
、B
端施加电压 \(V\)(该电压值可以随意选取,但是为了计算方便,通常选取整数,并且数值不要太大):
根据基尔霍夫定律求解出电流 \(I\),此时 A
、B
端之间的输入电阻为:
\[R_{AB} = \frac{V}{I}\]
▶【例题】求解下图左侧电路 A
与 B
之间的输入电阻?
◉【解答】向上图左侧的无源二端网络上施加 10V
电压,并且假设各条支路的电流分别为 \(I_1\)、\(I_2\)、\(I_3\)、\(I_4\),从而能够得到右侧的等效电路,然后根据基尔霍夫定律就可以求解得到:
\[R_{AB} = \frac{V}{I} = \frac{V}{I_1 + I_2 + I_4} = \frac{10V}{2A} = 5Ω\]
将 \(R_{ab}\)、\(R_{bc}\)、\(R_{ca}\)三个电阻按照如下方式联结,就可以构成 \(\Delta\) 型或者 \(\pi\) 型联结:
而将 \(R_{ab}\)、\(R_{bc}\)、\(R_{ca}\) 三个电阻按照以下方式联结,则构成\(Y\) 型或者 \(T\) 型联结:
对于外电路而言,在确保每个结点的电流、电位保持不变的前提下,上述的两种联结方式可以进行等效互换:
上图左侧为 \(\Delta\) 型或者 \(\pi\) 型联结 ──➔ \(Y\) 型或者 \(T\) 型联结:
\[Y形电阻 = \frac{\Delta 形相邻电阻乘积}{\Delta 形电阻之和}\implies\begin{cases}R_a = \frac{R_{ab} \cdot R_{ca}}{R_{ab} + R_{bc} + R_{ca}} \\R_b = \frac{R_{ab} \cdot R_{bc}}{R_{ab} + R_{bc} + R_{ca}} \\R_a = \frac{R_{ca} \cdot R_{ca}}{R_{ab} + R_{bc} + R_{ca}}\end{cases}\]
上图右侧为 \(Y\) 型或者 \(T\) 型联结 ──➔ \(\Delta\) 型或者 \(\pi\) 型联结:
\[\Delta 形电阻 = \frac{Y 形电阻两两乘积之和}{Y 型不相邻电阻}\implies\begin{cases}R_{ab} = \frac{R_a R_b + R_b R_c + R_c R_a}{R_c} \\R_{bc} = \frac{R_a R_b + R_b R_c + R_c R_a}{R_a} \\R_{ca} = \frac{R_a R_b + R_b R_c + R_c R_a}{R_b}\end{cases}\]
电源存在两种等效形式,一种以输出电压为主要特征,称为电压源;另外一种以输出电流为主要特征,称为电流源。
实际的电压源由内阻 \(R_S\) 与电压源 \(U_S\) 串联而成,下图右侧当中的 \(R_L\) 为负载电阻,\(I\)为电源向负载输出的电流,此时实际电源两端的电压 \(U = U_S - IR_S\),即电压源两端的电压 \(U\) 与负载电流 \(I\)呈线性关系,可以表示为下图右侧的直线:
注意:这条由电源端电压 \(U\) 伴随输出电流 \(I\)变化的伏安特性曲线,称为电压源的外特性曲线,简称为外特性。可以看到,当负载电流\(I\)增大时,电压源内阻的压降也会增大,而电压源的端电压则随之下降。
理想的电压源忽略了电压源的内阻 \(R_S = 0\),此时根据 \(U = U_S - IR_S\) 可以推导得到 \(U = U_S\),外电压 \(U\) 的大小与负载 \(R_L\) 无关,对应的外特性曲线为一条平行于\(I\) 轴的直线:
实际的电流源是由内阻 \(R_S\) 与电流源 \(I_S\) 并联而成,下图右侧中的 \(R_L\) 为负载电阻,这里 \(I\) 依然为电源向负载输出的电流,而 \(\frac{U}{R_S}\) 表示电源内阻 \(R_S\) 上经过的电流,由此就可以得到关系式\(I = I_S -\frac{U}{R_S}\),即电流源输出的电流 \(I\) 与负载 \(R_L\) 两端的电压 \(U\)呈线性关系,对应的外特性曲线如下图右侧所示:
注意:实际电流源输出的电流 \(I\) 总是小于电流源电流 \(I_S\),实际电流源的内阻通常都非常大。当负载发生变化时,电流源输出电流\(I\) 的大小取决于电流源内阻 \(R_S\),其阻值越大分得的电流就越小,电流源的输出就更加稳定。
理想电流源的内阻 \(R_S =\infty\),根据 \(I = I_S -\frac{U}{R_S}\) 可以推导得到 \(I =I_S\),输出电流 \(I\)的大小与负载 \(R_L\)无关,对应的外特性曲线是一条平行于 \(I\) 轴的直线:
根据实际电压源与电流源的外特性方程,可以推导得到能够让两者互换使用的等效变换条件:
\[\begin{cases}电压源 U = U_S - IR_S \implies I = \frac{U_S}{R_S} - \frac{U}{R_S} \\电流源 I = I_S - \frac{U}{R_S}\end{cases}\implies 等效变换条件\begin{cases}I_S = \frac{U_S}{R_S} \\U_S = I_S R_S\end{cases}\]
当实际电压源与电流源的内阻相等,并且满足 \(I_S = \frac{U_S}{R_S}\) 或者 \(U_S = I_S R_S\)的等效变换条件时,两种电源就可以互换使用。除此之外,进行电压源与电流源的等效变换时,还需要注意如下几点:
总结:两个电源并联时,需要将电压源转换为等效的电流源;而当两个电源串联时,则需要将电流源转换为等效的电压源。
受控源是一种输出量的大小与方向,受到电路当中其它位置电压或电流控制的电源,其拥有两个输入端(控制端)和两个输出端(受控端),根据输出端所呈现的特性,受控源还可以划分为如下四种:
电压
,所以控制支路为开路。如果控制端电压为\(u_1\),那么输出端电压就等于 \(\mu u_1\),这里的 \(\mu\)没有量纲,被称为转移电压比或者电压放大系数:电流
,所以控制支路为短路。如果控制端电流为\(i_1\),那么输出端电压就等于 \(r i_1\),这里的 \(r\)就称为转移电阻,单位为欧姆 Ω
: 电压
,所以控制支路为开路。如果控制端电压为\(u_1\),那么输出端电流就等于 \(g u_1\),这里的 \(g\)就称为转移电导,单位为西门子 S
: 电流
,所以控制支路为短路;如果控制端电流为\(i_1\),那么输出端电压就等于 \(\alpha i_1\),这里的 \(\alpha\)没有量纲,被称为转移电流比或者电流放大系数:注意:独立源作为电路的输入,起到对电路的激励作用,是电路得以正常工作的源泉。而受控源用于反映电路当中某个位置的电压或电流,对于另一个位置电压或电流的控制关系。概而言之,受控源并不是一种激励源,其体现的一种控制关系。
支路电流法是一种根据基尔霍夫电压与电流定律列写出的电路方程,其主要以各个支路电流
作为求解的未知量。
上面电路由两个电源并联组成,该电路当中存在 3 条支路,2个结点(a
和 b
);如果需要求解 3支路上的电流,就需要列写 3个独立方程(不能通过已有方程列写出来的方程称为独立方程)联立进行求解。
首先,选定未知支路电流的参考方向,并根据 KCL定律列写出如下两个电流方程,其中只有一个为独立方程:
\[\begin{cases}结点 a \implies I_1 + I_2 - I_3 = 0 \\结点 b \implies I_3 - I_1 - I_2 = 0\end{cases}\]
注意:通常情况下,具有 \(n\) 个结点的电路应用 KCL 定律只能列写出\(n - 1\) 个独立方程:
然后,针对上面电路里的 Ⅰ、Ⅱ、Ⅲ 三个回路,分别列写出三个 KVL电压方程,其中只有两个为独立方程:
\[\begin{cases}回路 Ⅰ \implies U_1 - I_1 R_1 - I_3 R_3 = 0 \\回路 Ⅱ \implies U_2 - I_2 R_2 - I_3 R_3 = 0 \\回路 Ⅲ \implies U_1 - I_1 R_1 + I_2 R_2 - U_2 = 0\end{cases}\]
注意:电路分析过程当中,基于网孔列写出的方程一定是独立方程。
提取上述 KCL 和 KVL方程当中的独立方程,可以得到如下的独立方程组:
\[\begin{cases}结点 a \implies I_1 + I_2 - I_3 = 0 \\回路 Ⅰ \implies U_1 - I_1 R_1 - I_3 R_3 = 0 \\回路 Ⅱ \implies U_2 - I_2 R_2 - I_3 R_3 = 0\end{cases}\]
联立求解上述方程组,就可以得到支路电流 \(I_1\)、\(I_2\)、\(I_3\);如果求解出结果为正,则表示该电流的实际方向与参考方向相同;如果求解出结果为负,则表示该电流的实际方向与参考方向相反。
最后,将采用支路电流法的分析步骤总结如下:
注意:支路电流法适用于支路较少的电路(支路数量过多,会增加列写的方程数量),并且在分析含有理想电流源的电路时,由于该支路电流为已知,所以列写回路方程时需要避开理想电流源所在的支路。
结点电压法以电路当中的结点电压作为待求量,适用于结点较少支路较多的电路:
首先,上图电路为四条支路并联的电路,虽然该电路的结点数量较少,但是支路数量较多。这里选择b
点作为参考点,两个结点 a
与 b
之间的电压 \(U_{ab}\)称为结点电压,方向为由 a
点指向b
点。已知各条支路的电流如上图所示,分别对结点a
列写 KCL 方程,对于各条支路列写 KVL方程,得到如下的方程组:
\[\begin{cases}列写结点 a 的 KCL 方程 \implies I_1 + I_2 - I_3 - I_4 = 0 \\列写 R_1 支路的 KVL 方程 \implies U_{S1} - R_1 I_1 - U_{ab} = 0 \\列写 R_2 支路的 KVL 方程 \implies -U_{S2} - R_2 I_2 - U_{ab} = 0 \\列写 R_3 支路的 KVL 方程 \implies R_3 I_3 - U_{ab} = 0 \\列写 R_4 支路的 KVL 方程 \implies R_4 I_4 - U_{ab} = 0\end{cases}\]
然后,通过求解上述的方程组,就可以得到求解结点电压的简便公式:
\[U_{ab} = \frac{\frac{U_{S1}}{R_1} + \frac{-U_{S2}}{R_2}}{ \frac{1}{R_1}+ \frac{1}{R_2} + \frac{1}{R_3} + \frac{1}{R_4} }= \frac{\sum{\frac{U}{R}}}{\sum{\frac{1}{R}}}\]
最后,将结点电压法分析电路的步骤总结如下:
注意:结点电压法适用于求解支路上的电压
以及电流
,特别是对于支路数量较多、结点数量较少的复杂电路。
下图左侧的电路当中存在两个电源,各个支路上的电流都是由两个电源共同作用产生。叠加原理是指任意一条支路上的电流,都可以视为该电路当中的各个电源分别作用时,在该支路上产生电流的代数和。
这里假设 \(I_1'\)、\(I_2'\)、\(I_3'\) 是电压源 \(U_1\) 单独作用时的支路电流,\(I_1''\)、\(I_2''\)、\(I_3''\) 则是电压源 \(U_2\) 单独作用时的支路电流,而 \(I_1\)、\(I_2\)、\(I_3\) 是 \(U_1\) 和 \(U_2\)两个电压源同时作用时的支路电流,根据叠加原理就可以得到这些支路电流的关系:
\[\begin{cases}I_1 = I_1' - I_1'' \\I_2 = I_2'' - I_2' \\I_3 = I_3' + I_3''\end{cases}\]
采用叠加原理计算复杂电路,就是将具有多个电源的复杂电路转化为几个单电源的电路来进行计算,但是在使用时需要注意以下几点:
具有两个端口的电路称为二端网络,根据内部是否含电源,可以进一步划分为无源二端网络、有源二端网络:
任何一个线性有源二端网络,对于外电路而言,都可以采用一个电压源 \(U_s\) 与内阻 \(R_s\)串联而成的组合电源模型来代替。电压源的电压等于有源二端网络的开路电压(即将负载断开之后,a
与 b
两端之间的电压),而内阻等于有源二端网络当中所有独立电源为零时的等效电阻(\(U_s = 0\) 时理想电压源短路,\(I_s = 0\)时理想电流源开路),这就是戴维南定理。
注意:根据戴维南定理得到的等效电路,就称为戴维南等效电路。
任意一个线性有源二端网络,都可以采用一个电流为 \(I_s\) 的理想电流源与内阻 \(R_s\)并联的电源模型来等效代替。电流源的电流 \(I_s\)等于二端网络端口短路时的短路电流,并联内阻 \(R_s\)等于线性有源二端网络去除独立电源之后(理想电压源短路,理想电流源开路)a
与 b
两端之间的等效电阻,这就是诺顿定理。
注意:一个有源二端网络即可以采用戴维南定理转换为等效电压源,也可以采用诺顿定理转换为等效电流源,两者对于外电路而言都是等效的。
如果电阻两端的电压与通过的电流成正比,说明其电阻值为一个常数,其两端的电压与电流关系遵循欧姆定律,称为线性电阻。如果该电阻值并非一个常数,而是会伴随着电压或者电流发生变化,两端的电压与电流关系也不遵循欧姆定律,这种电阻就称为非线性电阻。
非线性电阻的电压与电流关系,可以采用 \(U =f{I}\) 或者 \(I = f(U)\)的伏安关系曲线进行表示,下图为电灯泡钨丝(左)以及二极管(右)的伏安特性曲线:
因为非线性电阻会随着电压或者电流发生变化,所以计算其阻值时必须指定确切的电压或者电流,例如下图表达的就是工作点Q 位置的电阻:
非线性电阻拥有静态电阻和动态电阻两种表示方式:
注意:因为非线性电阻的阻值并非一个常数,所以在分析计算时通常只会采用图解法。
磁体是具有磁性的物质,磁体上磁性最强的部分称为磁极,同性磁极相互排斥,异性磁极相互吸引。当磁场内某一点,磁针静止时北极所指的方向,就是该点的磁场方向。
磁感线是一种用于描述空间当中磁场分布的闭合曲线,磁体外部的磁感线从磁体的北极出发回到南极,而磁体内部的磁感线则是从磁体的南极出发返回北极,下图是几种常见形状磁铁的磁感线分布情况:
直线电流的方向与磁感线方向之间的关系可以通过安培定则(也称为右手螺旋定则)来判定:用右手握住导线,让大拇指的方向与电流方向保持一致,此时弯曲四指所指的方向就是磁感线的环绕方向。
通常使用符号 ⊚表示电流垂直于平面指向外侧,而使用⊗表示电流垂直于平面指向内侧:
通常使用符号 \(\cdot\)表示磁感线垂直于平面指向外侧,而使用\(\times\)表示磁感线垂直于平面指向内侧:
注意:地磁场的磁感线从地理南极(地磁北极)出发,到达地理北极(地磁南极),两极的磁性最强,磁感线近乎垂直于地面,而赤道处的磁感线与地面近似平行。
安培力是磁场对于通电导线产生的作用力,如果将一段通电导线\(L\)放入磁场,当导线方向与磁场方向垂直时(下图左),导线所受的安培力最大;当导线方向与磁场方向一致时(下图中),其所受的安培力等于零;而当导线方向与磁场方向斜交呈\(\theta\)角时(下图右),安培力介于最大值与零之间。
当导线方向与磁场方向垂直时,通电导线受到的安培力\(F\) 与电流 \(I\) 和导线长度 \(L\) 呈正比:
\[安培力 F = 常量 B \times 电流 I \times 导线长度 L\]
上面公式中的 \(B\)是一个比例系数,对于磁场当中一个确定的点而言,其值为一个常量,所以上面的公式也可以变换为下面的形式:
\[磁感应强度 B = \frac{安培力 F}{电流 I \times 导线长度 L}\]
相同磁场的同一个位置,无论电流 \(I\)、导线长度 \(L\) 怎样变化,\(B\)的值总是确定的;而在不同磁场或者不同位置当中,\(B\) 的值也会有所不同。当 \(B\) 的值越大,在电流 \(I\) 和导线长度 \(L\) 一定的情况下,通电导线所受到的安培力\(F\)就越大,所表征的磁场也就越强,因此可以采用 \(B\)来描述磁场的强弱,称为磁感应强度。
磁感应强度的单位为特斯拉,简称为特T
,当通电导线与磁场垂直时,如果电流 \(I = 1A\),导线长度 \(L = 1m\),并且导线所受到的安培力恰好为\(F = 1N(牛)\),那么 \(1T = 1N/(A \cdotm)\)。磁感应强度是一个矢量,某一个点的磁场方向就是该点磁感应强度的方向。
以上讨论的是通电直导线与磁感应强度方向相互垂直的情况,当通电直导线与磁感应强度方向之间的夹角为\(\theta\) 的时候,可以将 \(B\)分解为两个分量:一个为水平分量 \(B \cos\theta\),另一个为垂直分量 \(B \sin\theta\)。因为水平分量对于电流的作用力为零,所以安培力完全由垂直分量所决定,此时安培力\(F\) 的大小等于:
\[安培力 F = 常量 B \times 电流 I \times 导线长度 L \times \sin \theta\]
通电导线与所受安培力的方向与磁场和电流方向之间的关系,可以采用左手定则来进行判断:张开左手,大拇指与其它四指处于相同平面并且互相垂直,让磁感线垂直穿入掌心,而其它四指指向电流的方向,此时大拇指所朝的方向就是导线所受安培力的方向。
洛仑兹力是指磁场对于运动电荷的作用力,其方向可以通过左手定则进行判定:伸开左手让磁感线进入掌心,四指朝向正电荷运动的方向,此时大拇指所朝的方向就是正电荷所受洛仑兹力的方向,负电荷在磁场当中受到的洛仑兹力与正电荷相反。
洛仑兹力的大小等于电荷的电量 \(q\)、电荷的速率 \(v\)、磁感应强度 \(B\),以及 v
与 B
之间夹角 \(\theta\)正弦的乘积。
\[洛仑兹力 f(牛顿) = 电量 q(库仑) \times 速率 v(米/秒) \times 磁感应强度B(特斯拉) \times 夹角 \sin \theta\]
注意:运动的电荷在磁场当中受到洛仑兹力影响,其运动方向将会发生偏转,
荧光示波器里的示波管
、电视机内的显像管
、电子显微镜
等正是基于这个原理进行工作的。
磁通量是一个用于表示磁场分布情况的物理量,其国际单位为韦伯(Wb
):
\[1Wb = 1Tm^2(T 为磁感应强度的单位\ 特斯拉,m^2 为面积的单位\ 平方米)\]
假设在匀强磁场当中有一个与磁场方向垂直,并且面积为\(S\)的线圈平面,磁场的磁感应强度为 \(B\):
那么磁感应强度 \(B\) 与面积 \(S\)的乘积就称为磁通量,采用 \(\Phi\) 进行表示:
\[磁通量 \varPhi = 磁感应强度 B \times 面积 S\]
如果穿过闭合电路的磁通量发生了变化,那么闭合电路当中就会产生电流,这种由于磁通量变化而产生电流的现象称为电磁感应,其所产生的电流称为感应电流。在电磁感应现象中,既然闭合回路当中存在感应电流,那么该电路当中就一定会存在电动势,这种由电磁感应产生的电动势称为感应电动势。
感应电动势大小与磁通量变化快慢有关系,用磁通量的变化率来描述磁通量变化的快慢,其值为磁通量的变化量与产生这个变化所用时间的比值。
如果时刻 \(t_1\) 的磁通量为 \(\varPhi_1\),时刻 \(t_2\) 的磁通量变为 \(\varPhi_2\),从 \(t_1\) 到 \(t_2\) 这段时间内磁通量的变化量就是 \(\varPhi_2 - \varPhi_1\),记为 \(\Delta \varPhi = \varPhi_2 -\varPhi_1\),由于该变化是在 \(\Delta t= t_2 - t_1\)时间段内发生的,所以法拉第电磁感应定律可以表述为:电路当中感应电动势的变化量,与穿过该电路的磁通量变化量呈正比。
\[感应电动势(伏特)\ E = \frac{磁通量变化量(韦伯)\ \Delta\varPhi}{时间变化量(秒)\ \Delta t}\]
一个闭合回路可以被视为一匝线圈,如果线圈的匝数为 \(n\),由于每一匝线圈的感应电动势都为 \(\frac{\Delta \varPhi}{\Deltat}\),并且每一匝线圈相互串联,整个线圈的电动势\(E\) 就等于:
\[感应电动势(伏特)\ E =\ 线圈匝数\ n \times \frac{磁通量变化量(韦伯)\\Delta \varPhi}{时间变化量(秒)\ \Delta t}\]
如果磁通量的变化是由于导体与磁体的相对运动而引发的,那么此时产生的电动势就称为动生电动势。当一个匀强磁场中的磁感应强度、导线、导线运动方向三者互相垂直时,感应电动势等于磁感应强度\(B\)、导线长度 \(L\)、导线运动速度 \(v\) 的乘积:
\[动生电动势 E(伏) = 磁感应强度 B(特斯拉) \times 导线长度 L(米) \times导线运动速度 v(米/秒)\]
如果导线运动方向与导线自身相互垂直,但是与磁力线方向存在着一个夹角\(\theta\),此时可以将速度\(v\)分解为垂直于磁力线的分量 \(v_1 = v \sin \theta\)和平行于磁力线的分量 \(v_2 =v \cos \theta\):
平行于磁力线的分量不会参与切割磁力线,也就不会产生感应电动势。而垂直于磁力线的分量会切割磁力线,产生感应电动势\(BLv_1\),又由于 \(v_1 = v \sin\theta\),所以此时产生的动生电动势应为:
\[动生电动势 E(伏) = 磁感应强度 B(特斯拉) \times 导线长度 L(米) \times导线运动速度 v(米/秒) \times 夹角 \sin \theta\]
当导线运动方向与磁力线方向存在夹角 \(\theta\)时,导线切割磁力线产生的感应电动势大小,与磁感应强度\(B\)、导线长度 \(L\)、运动速度 \(v\)、运动方向与磁力线方向的夹角\(\theta\)的正弦成正比。
归纳起来,感应电动势的产生主要存在如下两种方式:
楞次定律是指感应电流具有这样的方向,即感应电流的磁场总是会阻碍引起感应电流的磁通量发生变化。利用楞次定律可以判定各种情况下感应电流的方向,具体可以依照如下步骤进行:
注意:感应电流的磁场总是阻碍原磁通量的变化,主要是指阻碍变化,而非阻碍原磁场。即当原磁通量增加时,感应电流的磁场方向与原磁场方向相反;而当原磁通量减少时,感应电流的磁场与原磁场方向相同。阻碍并不是指阻止,原磁通量如果增加,感应电流的磁场只能阻碍而不能阻止原磁通量的增加,即原磁通量最后依然还是会增加。
伸开右手,使大拇指与其它四指处于相同平面并且相互垂直,让磁感线垂直穿入掌心,并使大拇指朝向导体运动的方向,此时其它四指所朝方向就是感应电流的方向,这就是右手定侧。
注意:不要混淆右手定则与左手定则,两个定则的应用可以简单的总结为因电而动用左手,因动而电用右手。
磁导率是一个用于衡量物质导磁能力的物理量,其单位为亨/米(H/m
),其值通常为一个固定的常数,指定物质的磁导率\(\mu\) 与真空磁导率\(\mu_0 = 4 \pi \times 10^{-7} H/m\)的比值,称为该物质的相对磁导率 \(\mu_r\):
\[相对磁导率 \mu_r = \frac{某种物质的磁导率 \mu_r}{真空的磁导率 \mu_0}\]
材料名称 | 铸铁 | 硅钢片 | 镍锌铁氧体 | 锰锌铁氧体 | 坡莫合金 |
---|---|---|---|---|---|
相对磁导率 | \(200 \sim400\) | \(7000 \sim1000\) | \(10 \sim1000\) | \(300 \sim5000\) | \(2 \times10^4 \sim 2 \times 10^5\) |
注意:对于非磁性材料而言,由于\(\mu \approx \mu_0 \implies \mu_r \approx1\),所以几乎不会具有磁化特性。
磁场当中某一个点的磁感应强度 \(B\)与相同点上磁导率 \(\mu\)的比值称为该点的磁场强度,其单位为安/米(A/m
),要注意磁场强度与磁感应强度分别属于不同的概念,使用时切忌不能混淆。
当线圈绕制在闭合的铁芯上时,由于铁芯的磁导率远远高于周围空气的磁导率,使得大部分磁通量集中到了铁芯内部,并且形成一个闭合通路,这种人为造成的磁通路径,就被称为磁路。
由于导体本身电流的变化而产生的电磁感应现象称为自感,当导体中的电流发生变化时,周围的磁场也会随之发生变化,并且由此引发磁通量的变化,从而在导体当中产生感应电动势,这个电动势会阻碍导体当中电流的变化,称为自感电动势。自感电动势同样与穿过线圈的磁通量变化率成正比,由于磁通量\(\Delta \varPhi\) 与磁感应强度 \(B\) 成正比,而 \(B\) 又与产生该磁场的电流 \(I\) 成正比,所以 \(\Delta \varPhi\) 与 \(\Delta I\)也成正比,由此就可以得到自感电动势 \(e_L\) 的计算公式:
\[自感电动势 e_L = 自感系数 L \times \frac{电流 \Delta I}{时间 \Delta t}\]
上面方程当中的 \(L\)称为线圈的自感系数,简称为自感或者电感,其大小由线圈本身的特性决定。线圈越长,匝数越多,截面积越大,其自感系数就会越大;除此之外,带有铁芯线圈的自感系数,比没有铁芯要更大。自感系数的单位为亭利,简称亨,符号为\(H\)。如果通过线圈的电流在1s
时间内改变 1A
时产生的自感电动势为1V
,那么该线圈的自感系数就等于 \(1H = \frac{1V \cdots}{A}\)。亭利这个单位值较大,通常会使用更小的毫亨(\(mH\))和微亨(\(\mu H\)):
\[1H = 10^3 mH = 10^6 \mu H\]
指定线圈的自感系数通常是固定的,如果一个指定线圈的截面积为\(S(m^2)\),长度为\(l(m)\),匝数为 \(N\),介质磁导率为 \(\mu(H/m)\),那么其电感值\(L(H)\) 就等于:
\[电感 L = \frac{磁导率 \mu \cdot 截面积 S \cdot 匝数 N^2}{长度 l}\]
电感器是基于自感原理制作的电子元件,最简单的电感线圈就是将导线空心的绕几圈,或者在磁芯上缠绕几周:
注意:电感元件可以划分为两大类:利用自感原理的电感器,利用互感原理的变压器。
电感两端的电压与通过电流的关系为 \(e_L = L\frac{\Delta I}{\Delta t}\),下图展示了电感器的几种电路符号:
注意:使用电感器时需要注意其工作频率,高频电感器的电感量较小,但是可以工作在较高的频率之下;而低频扼流圈的电感量较大,主要应用于低频电路当中。
感抗是指电感器对于交流电流存在的阻碍作用,其值与电感量大小以及频率高低有关。线圈的感抗\(X_L\) 与电感 \(L\) 和交流频率 \(f\) 之间存在如下关系:
\[感抗 X_L(欧姆) = 2 \pi \cdot 交流频率 f(赫兹) \cdot 电感 L(亨利)\]
由于感抗是由自感所引起的,线圈的电感 \(L\)越大,自感作用就越大,因而感抗也就越大;交流电的频率 \(f\)越高,电流的变化率越大,自感作用也就越强,因而感抗也就越大。除此之外,由于直流电的频率\(f =0\),所以电感呈现出通路,只存在可以忽略不计的线圈直流电阻;但是电感对于交流电存在着阻碍作用,感抗值远远大于线圈的直流电阻对于交流电流的阻碍作用,这就是电感器的通直隔交特性。
类似于电阻的串联,电感器串联之后的总电感量等于\(n\)个串联电感器的电感值之和:
\[L = L_1 + L_2 + ... + L_n\]
同样的,类似于电阻的并联,电感器并联之后的总电感量的倒数,等于\(n\)个并联电感器电感值的倒数之和:
\[\frac{1}{L} = \frac{1}{L_1} + \frac{1}{L_2} + ... + \frac{1}{L_n}\]
注意:实际电路设计当中,通常很少将电感器串联或者并联起来进行使用。
下面两个相互靠近的线圈,当第 1 个线圈当中通过电流 \(i_1\) 时,会在线圈中产生自感磁链 \(\Psi_{11}\),根据右手螺旋定则可以确定其方向;第1 个线圈产生的磁链会有一部分通过第 2个线圈,这部分磁链称为互感磁链 \(\Psi_{21}\)。同样的,当第 2 个线圈通过电流\(i_2\) 时,其所产生的磁链 \(\Psi_{22}\)也会有一部分通过第一个线圈,从而产生互感磁链 \(\Psi_{12}\),这种两个线圈相互感应的现象称为互感。
磁链是导电线圈所链环的磁通量,其单位与磁通量一样为韦伯(Wb
)。当一个线圈流过电流时,就会在线圈当中产生磁通\(\varPhi\),如果线圈的匝数为\(N\),并且通过每一匝的磁通量均为 \(\varPhi\),则通过线圈的磁链\(\Psi\) 等于:
\[磁链 \varPsi = 线圈匝数 N \times 每匝磁通量 \varPhi\]
针对上述示意图当中的两个线圈,互感磁链与产生该磁链电流的比值称为它们的互感系数,通常采用符号\(M\)进行表示,其与自感系数一样也采用亨利(H
)作为单位:
\[互感系数 M = \frac{互感磁链 \varPsi_{21}}{电流 i_1} = \frac{互感磁链\varPsi_{12}}{电流 i_2}\]
注意:互感系数只与两个回路的
结构
、位置
、介质磁导率
有关,而与回路当中的电流
无关。只有当介质为铁磁性材料时,互感系数才会与电流相关。
假设 \(L_1\)、\(L_2\)分别为两个线圈的电感值,则互感系数 \(M\) 还可以等于:
\[互感系数 M = 线圈耦合系数 K \sqrt{线圈 1 电感 L_1 \times 线圈 2 电感L_2}\]
上面公式当中的 \(K\)是表征线圈耦合程度的耦合系数,其取值可以为 \(0\) 或者 \(1\):
如果 \(i_1\) 随着时间发生变化,那么\(\varPsi_{21}\)也会随着时间变化。根据法拉第电磁感应定律,第 2个线圈将会产生感应电动势,这种由于互感产生的电动势称为互感电动势\(e_{21} = \frac{\Delta \varPsi_{21}}{\Deltat}\)。同理,当 \(i_2\)随着时间发生变化,同样也会在第 1 个线圈当中产生互感电动势 \(e_{12} = \frac{\Delta \varPsi_{12}}{\Deltat}\)。
根据互感系数 \(M =\frac{\Delta \varPsi_{21}}{i_1} = \frac{\Delta\varPsi_{12}}{i_2}\) 可以推导得到 \(\varPsi_{21} = Mi_1\) 和 \(\varPsi_{12} = Mi_2\),将它们代入上面 \(e_{21}\) 与 \(e_{12}\)的方程,就可以得到如下的方程组:
\[\begin{cases}第2个线圈的感应电动势 e_{21} = \frac{互感磁链变化 \Delta\varPsi_{21}}{时间变化 \Delta t} = 互感系数 M \times \frac{电流变化\Delta i_1}{时间变化\Delta t} \\第1个线圈的感应电动势 e_{12} = \frac{互感磁链变化 \Delta\varPsi_{12}}{时间变化 \Delta t} = 互感系数 M \times \frac{电流变化\Delta i_2}{时间变化 \Delta t}\end{cases}\]
观察上述方程组可以发现,线圈当中的互感电动势,与互感系数\(M\)和另一个线圈当中电流变化率 \(\frac{电流变化 \Delta i}{时间变化 \Deltat}\)的乘积成正比;互感电动势的方向,可以通过楞次定律进行判定。
互感线圈当中,与感应电动势极性始终保持一致的端点称为同名端,反之则称为异名端,电路原理图当中通常会使用圆点\(\cdot\)符号标识互感线圈的同名端。当电流 \(i\)通过线圈 1
并且随着时间逐步增大时,电流 \(i\)所产生的自感磁通与互感磁通也会随着时间增加。由于磁通的变化,线圈 1
当中就会产生自感电动势,而线圈 2
当中就会产生互感电动势。
当原电流增大时,反电动势会阻碍其增大,这样就可以判断出反向电动势产生的反向电流方向\(i_{反}\) 是从 1
流向2
,与原电流 \(i\)的方向相反。反向电动势产生于线圈 1
的两端,根据内电路当中电流是从负极流向正极的原理,可以绘制出线圈 1
两端电动势的正负极性,即2
端为正 1
端为负。
对于线圈 2
,当电流 \(i\)增大时,由于互感的作用,导致通过线圈 2
的磁通增加,根据楞次定律,可以判断出互感电流\(i_互\)的方向(下图左侧)。同样根据内电路当中电流从负极流向正极的原理,还可以绘制出线圈 2
两端电动势的正负极性,即4
端为正 3
端为负。由此可见 1
与3
而 2
与 4
的极性相同。采用同样的分析方法,就可以绘制出自感电动势与互感电动势的方向(下图右侧):
如果上图当中的电流 \(i\)并非增大而是在减小,那么各个端点的正负极性都会发生改变。但是无论电流\(i\) 如何变化,上面第一张示意图当中的1
与 3
和第二张示意图当中的 1
与4
的电动势极性始终会保持一致,属于同名端。
1
与 3
以及2
与 4
是同名端,而1
与 4
以及 2
与 3
是异名端;1
与 4
以及2
与 3
是同名端,而1
与 3
以及 2
与 4
是异名端;同名端关系只取决于两个耦合线圈的绕向与相对位置,与电压和电流没有关系,电路当中具有互感的两个线圈可以按照如下两种方式进行绘制:
上述判断同名端的方式,需要事先了解线圈的绕向,但是在实际情况下,线圈经过浸漆或者其它处理,外观上已经无法判断其具体绕向。在这种情况下,就需要采用实验法来进行判断:
上面电路当中,线圈 1
与电阻 \(R\)、开关 \(S\) 串联之后,连接至直流电源 \(E\),将线圈 2
两端连接至万用表的表笔,形成闭合回路。然后迅速闭合开关\(S\),使电流从线圈 1
的1
端流入,电流随着时间不断增大 \(\frac{\Delta I}{\Delta t} >0\),如果此时万用表显示正值,则线圈 1
的1
端与线圈 2
的 3
端属于同名端,反之 1
与 3
就是异名端。
将两个具有互感的线圈串联在一起,会存在着两种不同的连接方法:
下图当中的端点 1
与 3
,以及端点2
与 4
属于同名端。将2
和 3
连接到一起,这样的连接方式称为顺串。
假设线圈 1
的自感系数(电感)为 \(L_1\),线圈 2
的自感系数(电感)为\(L_2\),两个线圈的互感系数为\(M\),那么顺串之后的电感值\(L\) 就等于:
\[顺串电感 L = 线圈 1 的电感 L_1 + 线圈 2 的电感 L_2 + 2 \times 互感系数 M\]
下图当中的端点 1
与 4
,以及端点2
与 3
属于同名端。将2
和 3
连接到一起,这样的连接方式称为反串。
此时同样的,反串之后的电感值 \(L\) 就可以按照如下公式计算得到:
\[反串电感 L = 线圈 1 的电感 L_1 + 线圈 2 的电感 L_2 - 2 \times 互感系数 M\]
注意:如果两个互感线圈的同名端连接在一起,则两个线圈所产生的磁通总是大小相等方向相反,因而相互抵消,这样的线圈不会具有磁通,因而就不存在电感,仅仅只起到一个电阻的作用,该原理通常运用于无感电阻的制作。
假设两个互感线圈的互感系数为 \(M\),线圈 1
和 2
的电感分别为 \(L_1\) 和 \(L_2\),其并联时同样存在着顺并与反并两种连接方法。
将对应的同名端并联在一起称为顺并,两个线圈顺并之后的等效电感\(L = \frac{L_1 \cdot L_2 - M^2}{L_1 + L_2 - 2\cdot M}\):
而把对应的异名端并联在一起称为反并,两个线圈反并之后的等效电感\(L = \frac{L_1 \cdot L_2 - M^2}{L_1 + L_2 + 2\cdot M}\):
变压器是一种用于改变交流电电压的元件,其基本结构主要是由铁芯和铜制绕组两部分共同构成:
绕组与铁芯之间
、不同绕组之间
、绕组匝间
的绝缘必须保持良好,因为低压绕组与铁芯之间的绝缘较为简单,所以低压绕组靠近铁芯柱的内层,而高压绕组位于低压绕组的外侧;上图左侧是变压器的结构示意图,而右侧是它的电路符号。在初级绕组施加交变电压\(U_1\)之后,通过的交变电流会在铁芯当中产生交变的磁通量,该磁通量会分别穿过初级绕组与次级绕组,从而产生感生电动势。此时,如果次级绕组的负载电路是闭合的,那么就会在次级绕组当中产生交变电流,从而在铁芯当中产生交变的磁通量,该磁通量同样穿过初级绕组与次级绕组,并且分别引发感生电动势。这种交变电流在初级与次级绕组当中发生的互相感应现象就是互感现象,互感现象是变压器工作的基础原理。
初级绕组与次级绕组当中的电流共同产生的磁通量,绝大部分都会通过铁芯,仅仅会有一小部分泄露到铁芯之外,粗略计算时可以省略这些泄露掉的磁通量,即认为穿过两个线圈的交变磁通量相同,两个线圈每匝所产生的感生电动势相等。假设初级绕组的匝数为\(N1\),次级绕组的匝数为\(N2\),而穿过铁芯的磁通量为\(\varPhi\),那么初级与次级绕组当中产生的感生电动势\(e_1\) 与 \(e_2\) 分别等于:
\[\begin{cases}初级绕组感生电动势 e_1 = 初级绕组匝数 N_1 \frac{穿过铁芯的磁通量变化\Delta \varPhi}{所花费的时间 \Delta t} \\次级绕组感生电动势 e_2 = 次级绕组匝数 N_2 \frac{穿过铁芯的磁通量变化\Delta \varPhi}{所花费的时间 \Delta t}\end{cases}\implies\frac{初级绕组感生电动势 e_1}{次级绕组感生电动势 e_2} =\frac{初级绕组匝数 N_1}{次级绕组匝数 N_2}\]
初级绕组中的感生电动势 \(e_1\)起着阻碍电流变化的作用,与施加在初级绕组两端电压 \(U_1\)的作用相反,属于反电动势。由于初级绕组的电阻很小,如果忽略不计则有\(U_1 =e_1\)。此时次级绕组相当于一个电源,其感生电动势\(e_2\)相当于电源的电动势,由于次级绕组的电阻也很小,如果同样忽略不计,则次级绕组就会相当于一个没有内阻的电源,所以次级绕组的端电压\(U_2\) 等于感生电动势 \(e_2\),即 \(U_2 =e_2\),经过推导就可以得到关于变压比 \(n\) 的方程:
\[\frac{初级绕组两端电压 U_1}{次级绕组两端电压 U_2} =\frac{初级绕组匝数 N_1}{次级绕组匝数 N_2} = 变压比 n\]
由此可见,变压器初级与次级绕组的电压有效值之比等于两个线圈的匝数比\(n\),这个 \(n\) 被称为变压比:
变压器当中,次级绕组的输出电压一定是交流电压,该电压的频率与施加到初级绕组两端的交流电压频率相同。因为初级绕组产生的交变磁场变化规律与输入交流电压的变化规律相同,而次级绕组输出的交流电压变化规律也与磁场变化规律保持相同,所以输出电压与输入电压的频率相同。
如果向变压器的初级绕组施加直流电压,那么初级绕组当中流过的就是直流电流,此时初级绕组产生的磁线大小与方向均不会发生改变,导致次级绕组不能产生感生电动势,即次级绕组两端不会输出任何的电压。
变压器工作时的功率主要由次级绕组输出,由于变压器的线圈存在电阻,极小部分会损耗在变压器内部转换为热能,从而损耗掉一部分能量(称为铜损)。而铁芯在交变磁场当中反复进行磁化,也会损耗掉一部分能量导致铁芯发热(称为铁损)。变压器的能量损耗很小,效率很高,大型变压器的效率甚至可以达到97% ~ 99.5%
,所以实际计算通常会忽略掉这些损耗的能量,近似的认为变压器的输入与输出功率相等\(U_1 I_1 = U_2 I_2\),根据变压比方程\(\frac{U_1}{U_2} = \frac{N_1}{N_2}\)联立就可以得到:
\[\begin{cases}U_1 I_1 = U_2 I_2 \\\frac{U_1}{U_2} = \frac{N_1}{N_2}\end{cases}\implies\frac{初级绕组电流 I_1}{次级绕组电流 I_2} = \frac{次级绕组匝数N_2}{初级绕组匝数 N_1}\]
上述方程展现了变压器工作时,初级与次级绕组当中电流的关系,即初级绕组与次级绕组当中的电流有效值与线圈的匝数成反比。
注意:变压器的高压线圈匝数多通过的电流小,可以选择比较细的导线绕制;而低压线圈匝数少而通过的电流大,则应当选择较粗的导线进行绕制。
当负载运行时,变压器还具有变流作用,负载阻抗 \(Z_L\) 决定电流 \(I_2\) 的大小,而电流 \(I_2\)又决定了初级绕组的电流 \(I_1\)的大小。即初级绕组存在着一个等效阻抗 \(Z'\),其作用是将次级绕组的阻抗\(Z_L\)折合到初级绕组的电路当中:
当变压器的次级绕组连接至 \(Z_L\)以后,对于电源而言,相当于连接上阻抗为 \(n^2\cdot Z_L\) 的负载,而当变压器负载阻抗 \(Z_L\)确定时,调整变压器初级与次级绕组的匝数比 \(n\),就可以获得所需要的阻抗,具体可以参考如下的推导过程:
\[\begin{cases}次级绕组负载阻抗 Z_L = \frac{U_2}{I_2} \\初级绕组等效阻抗 Z' = \frac{U_1}{I_1}\end{cases}\implies\frac{Z'}{Z_L} = \frac{U_1}{U_2} \times \frac{I_2}{I_1} = \bigg(\frac{N_1}{N_2} \bigg) = n^2\impliesZ' = n^2 \cdot Z_L\]
注意:当电路输入端阻抗与信号源内阻相等时,信号源就可以将信号功率最大限度的传递给电路。同样的,当负载阻抗与电路的输出阻抗相等时,负载获得的功率最大。这种情况就称为阻抗匹配。实际电路当中,信号源与负载的阻抗并不总是匹配,因而需要在两者之间添加专用的阻抗匹配电路。
变压器初级绕组的输人功率为 \(P_1=U_1 I_1 \cos \phi_1\),其中 \(\phi_1\)是初级绕组当中电压与电流的相位差。变压器次级绕组的输出功率为\(P_2=U_2 I_2 \cos \phi_2\),其中 \(\phi_2\)是次级绕组当中电压与电流的相位差。由此,就可以得到变压器的损耗功率\(P_{损}\):
\[变压器损耗功率 P_{损} = 初级绕组输入功率 P_1 - 次级绕组输出功率 P_2\]
变压器次级绕组上的输出功率 \(P_2\)与初级绕组上的输入功率 \(P_1\)之比,称为变压器的效率 \(\eta\):
\[变压器效率 \eta = \frac{次级绕组输出功率 P_2}{初级绕组输入功率 P_1}\]
变压器制造厂商根据国家相关标准,会对变压器的工作与使用参数进行一系列的限制与规定,这些参数称为额定值,变压器的额定参数通常会采用下标\(N\) 来进行表示:
VA
。由于变压器效率极高,所以通常将初级与次级绕组的额定容量设计为相等;Hz
,我国规定的工业标准频率(简称工频)为50Hz
;发电机
、电动机
、变压器
的铁芯并非由整块金属构成,而是由许多硅钢薄片层叠而成。这是由于块状金属在变化的磁场当中,金属内部会产生感应电流,这些电流会在金属内部形成旋涡状的闭合回路,称为涡电流,简称为涡流。由于整块金属的电阻通常较小,所以涡流通常也会较强。
上面示意图当中,在块状的铁芯上面绕制了绝缘导线,当交流电通过导线时,穿过铁芯的磁通量不断发生变化,铁芯内部就会产生上图虚线所示的涡流。由于块状铁芯的电阻较小,所以内部涡流较强,从而导致铁芯大量发热,损耗了大量电能。为了减少这种涡流损失,通常会将涂有绝缘油漆的硅钢薄片层叠起来组成铁芯,这样涡流被限制在狭窄的薄片范围之内,回路的电阻较大,涡流大为减弱。
注意:铁芯采用的硅钢,电阻率比普通钢材更大,从而可以进一步的降低涡流损失。
由于变压器初级与次级绕组的铜质导线电阻造成的能量损耗称为铜损,当变压器空载时,由于初级绕组的电阻通常较小,空载电流与电压之间的相位差非常大(接近90°
),因此铜损可以被忽略,此时的损耗基本上等于铁损;而当变压器工作时,铜损主要取决于负载电流的大小,而负载电流的大小与负载的阻抗有关,因而铜损大小实质上由负载的大小与功率因数所决定。
由于变压器铁芯造成的能量损耗称为铁损,铁损包括磁滞损耗和涡流损耗两个部分。磁滞损耗是铁芯在反复磁化过程当中造成的损耗,其与铁芯材料的性质相关;涡流损耗则是由于铁芯当中感生电流(涡电流)产生焦耳热造成的损耗,采用喷涂有绝缘油漆的硅钢薄片层叠而成的铁芯,可以大为减少涡流损失;除此之外,铁损的大小还与电源电压的大小相关,当电源电压一定时,铁损基本为恒定量,而与负载电流无关,造成铁损基本等于其空载损失。
直流电是方向不会发生改变的电流,可以将其进一步划分为恒定直流电和脉动直流电两种类型。其中,方向
与大小
均不会发生改变的称为恒定直流电,而方向
不变大小
发生变化的则称为脉动直流电。
交流电是大小
与方向
都会发生改变的电流,同样可以进一步划分为纯交流电与非纯交流电两种类型。纯交流电的电流平均值为零,而非纯交流电的平均值不为零。
由于所有非正弦交流信号都可以使用多个正弦交流信号叠加而成,所以正弦交流电的应用较为广泛,它即可以通过发电机产生,也可以通过三极管、电感、电容组成的正弦波振荡器产生。
大小与方向均随时间按照正弦规律进行周期性变化的电流\(i\)、电压 \(u\)、电动势 \(e\)称为正弦交流电流/电压/电动势,它们在某一时刻 \(t\)的瞬时值,可以采用如下的三角函数方程来进行表示:
\[\begin{aligned}交流电流 & i = 交流电流峰值 I_m \times \sin(交流电角频率 \omega\times 时间 t + 初相位 \phi) \\交流电压 & u = 交流电压峰值 U_m \times \sin(交流电角频率 \omega\times 时间 t + 初相位 \phi) \\交流电动势 & e = 交流电动势峰值 E_m \times \sin(交流电角频率 \omega\times 时间 t + 初相位 \phi)\end{aligned}\]
直流电不随时间发生变化,通过其电流与电压的大小就可以进行描述;而交流电的大小与方向都会随着时间做周期性变化,描述时需要采用更多的物理量。
e
、电流 i
、电压 u
;m
进行表示,例如电动势 \(E_m\)、电流 \(I_m\)、电压 \(U_m\);正弦波的三要素分别为幅值、频率、初相位。
注意:一旦上述三个物理量确定,其正弦波也就确定,因而正弦交流电的分析就紧紧围绕这三个要素展开。
类似于其它表征周期性过程的参数,交流电使用了周期或者频率两个参数来表征变化的快慢:
s
);Hz
);其中,周期与频率的换算关系如下面的方程组所示:
\[\begin{cases}周期 T = \frac{1}{频率 f} \\频率 f = \frac{1}{周期T}\end{cases}\]
注意:我国交流电的工业标准频率(工频)为
50Hz
,其周期为0.02秒
,角频率为314 rad/s
。
角频率是一个用于描述交流电角度变化快慢的物理量,表征的是单位时间内变化的相角弧度值,通常使用符号\(\omega\)进行表示,单位为弧度/秒(rad/s
)。
\[角频率 \omega = \frac{2 \pi}{周期 T} = 2 \pi \cdot 频率 f\]
注意:角频率 \(ω\)、周期 \(T\),频率 \(f\)三个量当中只有一个属于独立量,它们都属于反映交流电变化快慢的物理量。
根据前述的交流电瞬时值表达式可以看出,交流电的瞬时值并非简单的由时间\(t\) 来决定,而是由 \(\omega t + \phi\)共同来确定的,这个值就称为交流电的相或者相位,相位是一个用于表征特定时刻在波形循环当中所处位置的物理量,其单位为弧度(rad
)。其中,\(\phi\) 是在时间 \(t = 0\)时刻的相位,称为初相位,初相位与计时起点相关。如果将下图当中波形的起始选取在A
点位置,那么电压的初相位 \(\phi= 0°\);如果波形起始选取在 B
点位置,则电压的初相位\(\phi = 90°\):
初相位可以是任意数值,但是习惯会让初相位的绝对值小于\(\pi\),例如下面图象所示:
两个交流电的相位之差称为相位差,采用 \(\Delta \phi\)进行表示。如果交流电的频率相同,则相位差就等于初相位之差。假设存在两个正弦交流电压\(e_1\) 与 \(e_2\),其相位分别为 \((\omega t + \phi_1)\) 和 \((\omega t + \phi_2)\),那么它们之间的相位差\(\Delta \phi\) 就等于:
\[相位差 \Delta \phi = e_1 的相位 (\omega t + \phi_1) - e_2 的相位 (\omegat + \phi_2) = e_1 的初相位 \phi_1 - e_2 的初相位 \phi_2\]
当相位差 \(\Delta \phi > 0\)的时候,\(e_1\) 会比 \(e_2\)先达到正负最大值
和零
,此时 \(e_1\) 比 \(e_2\) 超前 \(\Delta \phi\) 角,或者说 \(e_1\) 的初相位大于 \(e_2\) 的初相位;
当相位差 \(\Delta \phi < 0\)的时候,说明 \(e_1\) 的相位滞后于 \(e_2\) 的初相位:
当相位差 \(\Delta \phi = 0\)的时候,说明 \(e_1\) 和 \(e_2\)的变化步调一致,可以同时达到正负最大值
和零
,这种情况称为同相位:
当相位差 \(\Delta \phi = 180°(\pi)\)的时候,该情况称为 \(e_1\) 与 \(e_2\)反相,两个交流电的变化步调恰好相反。当一个到达正最大值,另一个则会到达负最大值;而一个减小至零,另一个则会增大至零:
当 \(\Delta \phi =90°(\frac{\pi}{2})\) 时,这种情况称为 \(e_1\) 与 \(e_2\) 正交,其特点是当\(e_1\)达到最大值时,\(e_2\)正好等于零:
正弦交流电可以分别采用函数法、图像法、向量图法来进行表征。其中,函数法是指利用三角函数方程来表示正弦交流特征的方法,例如前面介绍的交流电流
\(i = I_m \times \sin(\omega t +\phi)\)、交流电压
\(u= U_m \times \sin(\omega t + \phi)\)、交流电动势
\(e = E_m \times \sin(\omega t +\phi)\) 瞬时值表达式,就是采用了该种表示方法。
除此之外,正弦交流电还可以使用函数对应的图像来进行表示,其最大值
、周期
、初相位
、任一时刻瞬时值
都可以在图像当中表达出来,这就是更为形象直观的图像法:
由于正弦交流电的三要素在旋转的有向线段当中存在着一一对应关系,因而也可以采用旋转的有向线段来表示进行表示,而这种方式被称为相量图法。
在上面的示意图当中,从原点出发绘制一条有向线段,其长度等于正弦量的最大值\(I_m\),其与横轴的夹角等于正弦量的初相位\(\phi\),此时以角频率\(\omega\)逆时针进行旋转,则在任意一个瞬间,该有向线段 \(I_m\) 在纵轴上的投影就等于该正弦量的瞬时值\(i = I_m \sin(\omega t +\phi)\)。由于分析同频率正弦量的时候,只需要使用大小与相位两个要素,所以有向线段\(I_m\)可以直接用于表达正弦交流电。
通过上述旋转的有向线段来表示正弦量较为烦琐,通常只会使用初始位置为\(t = 0\)时刻的有向线段 \(I_m\)表征一个正弦量,其长度等于正弦量的幅值,与横轴正方向的夹角等于正弦量的初相位:
上述的有向线段围绕角频率做逆时针方向旋转,其在纵轴上的投影表示的是正弦量的瞬时值。由于实际问题当中,通常涉及的都是正弦量的有效值,因而为了方便起见,通常会让有向线段的长度等于正弦量的有效值(即下图当中的\(I\)),此时纵轴上的投影就不再表示正弦量的瞬时值:
这种采用具备大小与方向的有向线段来表征正弦量的方法,称为向量图表示法。这个具有大小与方向的有向线段称为向量,通常采用大写字母加符号\(\cdot\) 来进行表示。
注意:当使用向量图来表示正弦量的幅值与初相时,一般以
横轴 OX
的正方向作为参考,向量与横轴 OX
正方向的夹角表示初相;以横轴 OX
正方向作为起始,逆时针旋转相位角度为正,顺时针旋转相位角度为负,向量的长度表示正弦量的有效值或者最大值。
通过向量图可以清晰的表达出各个正弦量大小与相位的关系,例如下图左侧是正弦交流电压\(u\) 与电流 \(i\)的波形图,根据波形图当中展现的正弦量大小与相位绘制出右侧的向量图,可以看到\(u\) 超前 \(i\) 的相位为 \(\Delta\phi\)。由此可见,采用向量图来分析交流量的关系简单又明晰:
注意:向量图只能用于表征正弦周期量,除此之外,不同频率的正弦量不能绘制到同一张向量图。
如果交流电路当中只存在电阻元件,那么该电路就被称为纯电阻电路。
纯电阻电路当中,电流
与电压
在任意时刻的关系都遵守着欧姆定律。假设电阻为\(R\),添加在其两端的交变电压为\(u = U_m \sin \omegat\),此时通过该电阻的瞬时电流 \(i\) 等于:
\[瞬时电流 i = \frac{交变电压 u}{电阻 R} = \frac{电压峰值 U_m}{电阻 R}\sin (角频率 \omega \cdot 时间 t) = 电流峰值 I_m \cdot \sin (角频率\omega \cdot 时间 t)\]
如果纯电阻电路当中的电压与电流均采用有效值,那么其关系就会完全遵循欧姆定律:
\[电流有效值 I = \frac{电压有效值 U}{电阻 R}\]
注意:纯电阻电路当中的电流与电压保持同相,换而言之,电阻不会影响到电流与电压的相位关系。
纯电阻交流电路当中,当电流 \(i\) 流过电阻 \(R\)时,会导致电阻产生热量,电阻消耗功率将电能转化为热能,由于流过电阻的电流与电阻两端的电压伴随时间不断发生变化,所以电阻\(R\)消耗的功率也会随着时间不断变化。电阻当中某一时刻消耗的电功率称为瞬时功率,其值等于电压\(u\) 与电流 \(i\) 瞬时值的乘积,使用小写字母 \(p\) 进行表示:
\[瞬时功率 p = 瞬时电压 u \times 瞬时电流 i = 峰值电流 I_m \cdot 峰值电压U_m \sin^2 (角频率 \omega \cdot 时间 t)\]
根据交流电的最大值(峰值)与有效值之间的关系,可以得到:
\[瞬时功率 p = 有效电压 U \cdot 有效电流 I \cdot (1 - \cos (2 \times角频率 \omega \cdot 时间 t)\]
上述的方程说明,任意一个瞬间都恒有瞬时功率 \(p \ge0\),说明电阻总是在吸收功率,属于耗能元件。下图展示了瞬时功率\(p\) 伴随瞬时电压\(u\) 与瞬时电流 \(i\) 变化而发生变化的规律:
虽然瞬时功率可以表征电阻消耗功率的瞬时状态,但是不便于去表达与比较大小,所以工程实践当中,经常使用瞬时功率在一个周期内的平均值来表示功率,称为平均功率,通常采用大写字母\(P\)进行表示,日常讨论的功率主要就是指平均功率:
\[平均功率 P = 有效电压 U \times 有效电流 I = 有效电流 I^2 \times 电阻 R =\frac{有效电压 U^2}{电阻 R}\]
注意:平均功率的表达式与直流电路当中功率的表达形式完全相同,不同之处在于交流电路当中的
电流
与电压
要使用有效值。除此之外,该公式仅适用于纯电阻电路。
直流电路当中,影响电流
与电压
关系的只有电阻;而在交流电路当中,影响电流
与电压
关系的,除了电阻之外,还有电感和电容。其中,电感采用铜制导线进行绕制,铜的电阻率极小,因此线圈自身的电阻可以忽略不计,而认为线圈只具有电感特性,这种只具有电感特性的电路称为纯电感电路:
由于交流电通过电感线圈时,电流时刻在发生改变,导致电感线圈当中产生自感电动势,从而阻碍电流的变化,这样就形成了对于电流的阻碍作用。这种电感对于交流电的阻碍作用就称为感抗\(X_L\),其值与电感\(L\) 和频率 \(f\) 成正比:
\[感抗 X_L = 2 \pi \times 频率 f \times 电感 L\]
接下来,研究纯电感电路当中电流与电压的关系,下面电路当中的\(L\)是一个电阻可以忽略不计的电感线圈:
改变上图当中交流电源的电压,通过 \(L\)的电流就会随之发生改变,分析几组电流与电压的数值之后,就会发现纯电感电路当中的电流与电压成正比。这里采用\(\frac{1}{X_L}\)作为比例恒量,就可以得到纯电感电路当中欧姆定律的表达式:
\[电流 I = \frac{电压 U}{感抗 X_L}\]
上述表达式与直流电路上的欧姆定律相比,阻抗 \(X_L\) 相当于电阻 \(R\),不过这里的 \(X_L\)表示的是电感对于交流信号的阻碍作用。
当电感线圈两端添加上交流电压 \(u\),线圈当中就会通过交变电流,由于电流时刻在发生变化,导致线圈产生阻碍电流变化的自感电动势。因此,线圈当中电流的变化会滞后于线圈两端外加电压的变化。如果线圈通过的交流电流为\(i\)、电压为 \(u\)、产生的自感电动势为\(e_L\),则其正方向如下图所示:
根据基尔霍夫定律可以得到 \(u = -e_L\),再假设电流 \(i = I_m \sin \omegat\),经过推算就可以得到瞬时电压 \(u\) 的表达式:
\[\begin{aligned}瞬时电压 u = 峰值电流 I_m \cdot 角频率 \omega \cdot 电感 L \cdot\sin(角频率 \omega \cdot 时间 t + 90°) \\\xrightarrow{U_m = I_m \omega L = I_m X_L} 峰值电压 U_m \cdot\sin(角频率 \omega \cdot 时间 t + 90°)\end{aligned}\]
纯电感电路当中,电流的相位相比于电压会滞后90°
,如下图所示:
自感电动势本身就是由于电流的变化而产生,如果没有电流,也就不会产生自感电动势。电压\(u\) 与自感电动势 \(e_L\) 大小相等相位相反 \(u =e_L\),说明由于自感电动势具有阻碍电流变化的性质,导致电源的电压必须对其进行平衡。
注意:感抗只是
电压
与电流
的幅值或者有效值之比,而并不是其瞬时值之比\(X_L \neq\frac{u}{i}\)。由于电感电路与电阻电路存在区别,纯电感电路当中,电压与电流之间并不会存在比例关系,例如当电压\(u = U_m \sin \omega t\) 的时候,电流\(i = \frac{U_m}{X_L} \sin(\omega t - 90°) =I_m \sin(\omega t - 90°)\)。
电阻由导体本身的电阻率
、长度
、横截面积
所共同决定,而与其通过的电流无关,根据感抗的公式\(X_L = 2 \pi f L\)可以知道感抗与通过电流的频率相关。例如,自感系数为 1H
亨的线圈,对于频率为 \(f = 0\)的直流电,其阻抗 \(X_L = 0\);而对于50Hz
频率的工频交流电,对应的阻抗则为 \(X_L = 3.14 MΩ\);因此,电感线圈在电路当中具有通直流阻交流或者通低频阻高频的特性。
假设电流 \(i = I_m \sin\omega t\),而电压 \(u= U_m \sin(\omega t + 90°)\),则瞬时功率 \(p\) 等于:
\[p = u \cdot i = \{ I_m \sin \omega t \} \times \{ U_m \sin(\omega t +90°) \} = U_m I_m \sin \omega t \cos \omega t = \frac{U_m I_m}{2} \sin 2\omega t = UI \sin 2 \omega t\]
根据该公式可知,瞬时功率 \(p\) 是一个幅值大小等于\(U \cdot I\),并且以 \(2 \pi\)作为角频率,随着时间不断发生变化的物理量,其波形如下图所示:
在上图第 1 个和第 3 个的 \(\frac{1}{4}\) 周期之内,由于 \(u\) 与 \(i\) 的正负符号相同,瞬时功率 \(p\)为正(电流增大,磁场建立,线圈将电能转换为磁能)。而在第2 个和第 4 个的 \(\frac{1}{4}\)周期之内,由于 \(u\) 与 \(i\) 的正负符号相反,瞬时功率 \(p\)为负(电流减小,磁场消失,线圈将存储的磁能转换为电能),瞬时功率的正负可以按照如下方式进行简单直观的理解:
纯电感电路的平均功率 \(P =0\),不存在能量消耗,只存在电源与电感元件之间的能量互换,这种能量互换的规模就采用无功功率\(Q_L\)来进行衡量,其单位为乏(var
)或者千乏(kvar
),并且规定无功功率等于瞬时功率\(p\) 的幅值:
\[无功功率 Q_L = U \cdot I = I^2 X_L\]
本质上,电感元件属于一种储能元件,它与电源之间进行的是一种能量互换,由于电感元件本身没有消耗能量,所以被命名为无功功率。相应的,平均功率则会被称为有功功率。
对于一个只连接有电容器的电路,如果忽略连接导线的电阻不计,就可以称为纯电容电路。
交流电之所以能够通过电容器,是因为在电源的电压升高时,可以为电容器充电,电荷向电容器的极板聚集,形成充电电流;而当电源的电压降低时,电容器开始放电,电荷从电容器的极板释放出来,形成放电电流。电容器的充电与放电不断交替进行,于是电路上就产生了流动的电流。
对于导线当中形成电流的自由电荷,当电源的电压推动它们向某一个方向进行定向运动时,电容器两个极板积累的电荷会抵制其向该方向进行定向运动,从而导致电容对于交流电存在着阻碍作用,这种电容对于交流电的阻碍作用称为容抗,容抗\(X_c\) 的大小与频率\(f\) 和电容器的容值\(C\) 成反比:
\[容抗 X_C = \frac{1}{2 \pi \cdot 频率 f \cdot 电容 C}\]
分析下面电路,研究纯电容电路当中电流
与电压
之间的关系,如果改变电路两端的电压,那么电路当中的电流就会随之而改变:
分析几组电压
与电流
的数据之后就会发现,纯电容电路当中的电流\(I\) 与电压 \(U\) 成正比,这里以 \(\frac{1}{X_C}\)作为比例恒量,就可以得到纯电容电路当中欧姆定律的表达式:
\[电流 I = \frac{电压 U}{容抗 X_C}\]
上述方程当中的容抗 \(X_C\)相当于欧姆定律里的电阻 \(R\),用于表示电容对于交流电的阻抗作用大小。下图当中的电容元件已经连接到了正弦电源,电路当中的电流\(i\)与电容器两端的电压 \(u\) 的正方向如下图所示:
当电压发生变化时,电容器极板上的电量也会随之发生改变,在电路当中就会产生电流。如果在电容器两端添加一个正弦电压\(u= U_m \sin \omegat\),经过推算就可以得到电流 \(i\):
\[电流 i = 峰值电流 I_m \sin \times (角频率 \omega \cdot 时间 t + 90°)\]
上面方程当中的电流峰值 \(I_m = U_m \omegaC\),因而在纯电容电路当中,电流比电压的相位超前90°
,如下面的图形所示:
容抗与通过电流的频率相关,容抗与频率成反比,频率越高容抗越小。例如10pF
电容器,对于频率为 \(f =0\) 的直流电,阻抗 \(X_c\)为无穷大;而对于 f = 50Hz
的工频交流电,阻抗 \(X_C = 318Ω\);对于 500kHz
的交流电,则阻抗 \(X_C =0.0318Ω\),所以电容器在电路当中具有通交流隔直流或者通髙频阻低频的特性。
实际电路应用当中,电流通常既包含有交流成分,也会包含有直流成分。如果需要将交流成分输送至下一级电路,那么只需要在两级电路之间串联一个电容器,就可以使得交流成分顺利的通过,而直流成分被成功的阻止,这种用法的电容器称为隔直电容器:
如果只需要将低频成分传输至下一级电路,则只要在下级电路的输入端并联一个电容器,由于电容器对于高频成分的容抗较小,而对于低频成分的容抗较大,可以使得高频成分顺利的通过电容器,而让低频成分输入到下级电路,这种用法的电容器称为高频旁路电容器:
假设电压 \(u = U_m\sin(\omega t)\),而电流 \(i = I_m \sin(\omega t +90°)\),那么瞬时功率 \(p\) 就等于:
\[\begin{aligned}瞬时功率 p &= 电压 u \times 电流 i \\&= \{ 峰值电压 U_m \cdot \sin (角频率 \omega \cdot 时间 t) \} \times\{峰值电流 I_m \cdot \sin(角频率 \omega \cdot 时间 t + 90°) \} \\&= 峰值电压 U_m \cdot 峰值电流 I_m \cdot \sin (角频率\omega \cdot时间 t) \cdot \cos (角频率\omega \cdot 时间 t) \\&= \frac{峰值电压 U_m \cdot 峰值电流 I_m}{2} \cdot \sin (2 \times角频率 \omega \cdot 时间 t) \\& \xrightarrow{\frac{U_m I_m}{2} = UI} 瞬时功率 p = 电压 U \cdot电流 I \cdot \sin(2 \times 角频率 \omega \cdot 时间 t)\end{aligned}\]
由上述推导结果可以了解,瞬时功率 \(p\) 是一个幅值为 \(U \cdot I\),并且以 \(2 \omega\)的角频率随时间变化的物理量,其波形变化如图所示:
在第 1 与第 3 个的 \(\frac{1}{4}\)周期当中,电压值增高,电容元件充电,此时电容元件会从电源获取电能,并且将其储存在元件内部的电场当中,所以\(p\) 为正。而在第 2和第 4 个的 \(\frac{1}{4}\)周期内,电压值开始降低,此时电容元件释放出充电时储存的电能,所以 \(p\) 为负。
纯电容电路当中,平均功率 \(P =0\),即有功功率等于零,说明电容元件并不消耗能量,电源与电容元件本身之间只是发生了能量转换,这个能量转换的规模就采用无功功率\(Q\)来进行表示,其值等于瞬时功率 \(p\) 的幅值。
通常会将电容上的无功功率称为容性无功,其值为负;而将电感的无功功率称为感性无功,其值为正,这样电容上的无功功率\(Q_C\) 就可以等于:
\[电容无功功率 Q_C = - 电压 U \times 电流 I = - 电流 I^2 \times 容抗 X_C\]
90°
,而电容元件则是电压滞后于电流90°
;下图是一个电阻、电感、电容元件串联组成的交流电路,电路当中的各个元件都通过相同的电流,电流与电压的正方向如下图所示,分析该电路可以应用到前述的纯电阻、纯电感、纯电容电路理论。
根据基尔霍夫定律可以得到 \(u = u_R + u_L + u_C\),假设电流 \(i = I_m \sin \omega t\)为参考正弦量,则电阻元件上的电压 \(u_R\)与电流同相,从而可以得到:
\[u_R = I_m R \sin \omega t = U_{Rm} \sin \omega t\]
接下来,由于电感元件上的电压 \(u_L\) 超前于电流 \(90°\),由此就可以得到:
\[u_L = I_m \omega L \sin(\omega t + 90°) = U_{Lm} \sin(\omega t + 90°)\]
类似的,由于电容元件上的电压 \(u_L\) 滞后于电流 \(90°\),同样也可以得到:
\[u_C = \frac{I_m}{\omega C} \sin(\omega t - 90°) = U_{Cm} \sin(\omega t -90°)\]
然后,根据阻抗的电压
与电流
关系,就可以分别得到电阻
、电容
、电感
的阻抗:
\[\begin{cases}\frac{U_{Rm}}{I_m} = \frac{U_R}{I} = R \\\frac{U_{Lm}}{I_m} = \frac{U_L}{I} = \omega L = X_L \\\frac{U_{Cm}}{I_m} = \frac{U_C}{I} = \frac{1}{\omega L} = X_C\end{cases}\]
因为同频率的正弦量相加,所得到的仍然是同频率的正弦量,所以电源电压\(u\) 等于:
\[u = u_R + u_L + u_C = U_m \sin(\omega t + \phi)\]
观察可以发现,这个电压的幅值为 \(U_m\),与电流之间的相位差为 \(\phi\),这里利用向量图来求解幅值\(U_m\) 与相位差 \(\varPhi\):
如果将电压 \(u_R\)、\(u_L\)、\(u_C\) 表示为向量 \(\dot{U_R}\)、\(\dot{U_L}\)、\(\dot{U_C}\),将这些向量相加就可以得到电源电压\(u\) 的向量 \(\dot{U}\)。由电压向量 \(\dot{U}\) 和 \(\dot{U_R}\) 以及 \((\dot{U_L} + \dot{U_C})\)所组成的直角三角形,称为电压三角形,利用它就可以求解得到电源电压的有效值\(U\):
\[U = \sqrt{U_R^2 + (U_L - U_C)^2} = \sqrt{(IR)^2 + (L X_L - L X_C)^2} = I\sqrt{R^2 + (X_L - X_C)^2}\]
上式也可以写做 \(\frac{U}{I} = \sqrt{R^2 +(X_L -X_C)^2}\),此时电路当中电压
与电流
的有效值(幅值)之比就等于\(\sqrt{R^2 + (X_L -X_C)^2}\),其单位同样为欧姆,同样对于电流存在着阻碍作用,称为电路的阻抗,使用\(|Z|\) 进行表示:
\[|Z| = \sqrt{R^2 + (X_L - X_C)^2} = \sqrt{R^2 + (\omega L -\frac{1}{\omega C})^2}\]
由此可见,电路的阻抗 \(|Z|\)、电阻 \(R\) 以及 \((X_L -X_C)\)三者之间的关系同样可以采用阻抗三角形来进行表示:
而电源电压 \(u\)与电流 \(i\)之间的相位差,可以通过电压三角形来获得:
\[\tan \phi = \frac{U_L - U_C}{U_R}\implies\phi = \arctan \frac{U_L - U_C}{U_R} = \arctan \frac{X_L - X_C}{R}\]
阻抗 \(|Z|\)、电阻 \(R\)、感抗 \(X_L\)、容抗 \(X_C\) 表示了电压 \(u\) 及其分量 \(u_R\)、\(u_L\)、\(u_C\) 与电流 \(i\)之间的大小与相位关系。随着电路参数的不同,电压 \(u\) 与电流 \(i\) 之间的相位差 \(\phi\) 也会有所不同,因而可以认为 \(\phi\)角的大小是由电路的负载参数所决定的。
从上面这个推导公式还可以看到,当频率一定时,不仅相位差\(\phi\)的大小取决于电路参数,而且电流是滞后还是超前于电压也与电路的参数有关:
在电阻 \(R\)与电感 \(L\)串联的交流电路当中,电源电压 \(\dot{U}\) 等于电阻的电压降\(\dot{U_R}\)与电感的电压降 \(\dot{U_L}\) 之和:
\[电源电压 \dot{U} = 电阻的电压降 \dot{U_R} + 电感的电压降 \dot{U_L}\]
根据 RLC 串联电路的相位关系,电阻的电压降 \(\dot{U_R}\) 与电流 \(\dot{I}\) 同相,电感电压降 \(\dot{U_L}\) 超前于电流90°
,由此就可以绘制出对应的相量图。然后将 \(\dot{U_R}\) 与 \(\dot{U_L}\)的向量相加之后,就可以得到外加电压 \(\dot{U}\)。
从向量图当中可以看出 \(U \neq U_R +U_L\),即电源电压的有效值不等于电阻与电感两端电压的有效值之和。
已知电压 \(u\)与电流 \(i\)的变化规律与相互关系之后,就可以求解出瞬时功率 \(p\):
\[p = ui = U_m I_m \sin(\omega t + \phi) \sin \omega t\impliesp = UI \cos \phi - UI \cos(2 \omega t + \phi)\]
电阻元件会消耗电能,通过计算可以得到电阻元件的平均功率,公式当中的\(\cos \phi\)称为功率因数:
\[P = UI \cos \phi\]
对于电感和电容元件,由于会存储与释放电能,并且与电源之间存在着能量互换,相应的无功功率可以根据\(Q_L = UI = I^2 X_L\) 和 \(Q_C = -UI = -I^2 X_C\) 得到,考虑到 \(U_L\) 与 \(U_C\) 的相位相反,于是就可以得到:
\[Q = (U_L - U_C) I = I^2(X_L - X_C) = UI \sin \phi\]
上述的两个公式,是计算正弦交流电路当中平均功率(一般功率)和无功功率的一般公式。
注意:一个交流电源的输出功率,不仅与其端电压与输出电流的有效值乘积相关,还与负载的参数相关。如果负载的参数不同,那么电压与电流之间的相位差\(\phi\)也就会不同,在相同的
电压
\(U\) 与电流
\(I\)之下,电路的有功功率与无功功率同样也会有所不同。
视在功率 \(S\)是一个用于表示交流电器设备容量的物理量,其值等于电压有效值\(U\) 与电流有效值\(I\) 的乘积:
\[视在功率 S = 电压有效值 U \times 电流有效值 I = 电流有效值 I^2 \times|电路阻抗 Z|\]
生产实践里的交流电气设备,通常是按照额定工作电压\(U_N\) 与额定工作电流\(I_N\)来设计使用。相应的,这些交流电气设备的容量就可以使用额定视在功率\(S_N = U_N \times I_N\)来进行标识,其单位为伏安(VA
)或千伏安(kVA
)。
平均功率 P、无功功率Q、视在功率 S三个功率之间存在着如下的计算关系:
\[视在功率 S = \sqrt{平均功率 P^2 + 无功功率 Q^2}\]
显然,上述公式也可以采用功率三角形来进行表示,功率/电压/阻抗的三角形都是相似的,这里分别将它们标识在下面的图形当中:
注意:功率 \(P\)、\(Q\)、\(S\)都并非正弦量,所以不能采用向量来进行表示。
本节内容介绍了电阻、电感、电容元件串联的交流电路,实际生活当中比较常见的是电阻与电感元件的串联电路(忽略电容)和电阻与电容元件的串联电路(忽略电感)。
直流电路的电动势
、电压
、电流
大小与方向均不会发生变化,采用的分析定理有欧姆定律、基尔霍夫定律、叠加原理、戴维南定理等。直流电路当中,电容器会阻断电流,而电感器则会正常导通。除此之外,直流电路并不会存在相位的问题,也不会存在无功功率与视在功率,而只存在有功功率的概念。
正弦交流电路当中的电压
与电流
会按照正弦规律进行交替变换,其方向在一个周期内被划分为正半周和负半周两个部分,而大小由零变化到峰值又变回零。正弦量拥有振幅(峰值)、周期、初相位三个要素。正弦交流电路当中,电感会让电流滞后,而电容会使电流超前,由于两者都是储能元件,理想状态下即不会消耗功率也不会产生热量。
注意:实际电路当中,通常同时存在着直流和交流信号,此时需要将电路划分为直流和交流两个部分来进行计算,最后再将计算得到的结果进行叠加。
当电阻 R、电感 L、电容C 并联时,如果 R
、L
、C
元件两端的电压有效值为 \(U\),那么总电流 \(I\) 、总阻抗 \(|Z|\)与每条并联支路上电流
与电压
的关系为:
\[\begin{cases}电容支路电流 I_C = \frac{有效电压 U}{容抗 X_C} \\电感支路电流 I_L = \frac{有效电压 U}{感抗 X_L} \\电阻支路电流 I_R = \frac{有效电压 U}{电阻 R}\end{cases}\implies\begin{cases}总电流 I = \sqrt{I^2_R + (I_L - I_C)^2}\\\frac{1}{总阻抗 |Z|} = \sqrt{(\frac{1}{R})^2 + (\frac{1}{X_L} -\frac{1}{X_C})^2}\end{cases}\]
直流电路的功率等于电流与电压的乘积,但是在计算交流电路的平均功率(有功功率)时,还需要考虑到电压
与电流
之间的相位差\(\phi\),即 \(P = UI \cos \phi\),该公式当中的 \(\cos \phi\)就称为电路的功率因数。
根据前面的内容可以了解,电路的功率因数取决于负载参数。当属于电阻性负载的时候,电压
与电流
同相,其功率因数等于1
。而对于其它类型负载,既存在电阻也存在着电抗,其电压
与电流
之间存在着相位角\(\phi\),通常这种电感性负载的功率因数较低,一般介于0.5 ~ 0.6
之间,说明交流电源的额定容量无法被充分利用,输出了大量的无功功率,导致供电效率降低。
除了电压
与电流
之间相位角导致的功率因数下降以外,输入电流
或者电压
的波形失真也是引起功率因数下降的重要原因。例如开关电源采用了桥式整流和电容滤波电路来实现AC/DC转换,由于滤波电容的充放电作用,其两端的电压呈现出锯齿状纹波。滤波电容上电压的最小值与最大值相差不大,根据桥式整流二极管的单向导电性,只有在AC电路上的电压瞬时值高于滤波电容上的电压时,整流二极管才会由于正向偏置而导通。而当AC输入电压的瞬时值低于滤波电容上的电压时,整流二极管就会由于反向偏置而截止。
换而言之,在 AC电路上电压的半个周期范围之内,二极管仅在其峰值附近才会导通,导通角约为70°
度。虽然 AC的输入电压仍然大体保持正弦波形,但是 AC的输入电流却呈现出高幅值的尖峰脉冲,如下图所示:
这种严重失真的电流波形当中包含有大量的谐波成份,容易导致电路功率因数的严重下降。
为了提高负载的功率因数,通常会采取补偿措施,最为简单的方法是在电感性负载的两端并联上电容器,这种方法称为并联补偿,其电路图(左侧)与向量图(右侧)如下所示:
其中,\(\phi_1\)为感性负载电流 \(\dot{I_1}\) 与输入电压\(\dot{U}\) 之间的相位差。而 \(\phi\)则是并联电容器以后,电流 \(\dot{I}\) 与输入电压 \(\dot{U}\) 之间的相位差。
并联电容器之后,电感性负载的电流 \(I_1 = \frac{U}{\sqrt{R^2 + X_L^2}}\)与功率因数 \(\cos \phi_1 =\frac{R}{\sqrt{R^2 + X_L^2}}\)均未发生变化,但是电压
\(u\) 与电流
\(i\) 之间的相位差 \(\phi\) 变小(即 \(\cos \phi\) 变大)。
注意:此处讨论的功率因数提高,是指提高电源的功率因数,而非提高某个电感性负载的功率因数。
如果电容值选取适当,还可以使得 \(\phi =0\)。当电感性负载并联上电容器之后,减少了电源与负载之间的能量互换,此时电感性负载所需的无功功率,主要由电容器提供。换而言之,能量的互换主要发生在电感性负载与电容器之间,从而使得电源得到更为充分的利用。
注意:并联电容器之后,由于有功功率并没有发生改变,所以电容器并不消耗电能。
除了并联补偿方法之外,还可以采用专门的功率因数校正电路(PFC,PowerFactorCorrection),它不同于传统的并联补偿,主要是针对非正弦电流波形而采取的提高线路功率因数,迫使AC电流追随电压波形的瞬时变化轨迹,并使得电流
与电压
保持相同的相位,最终让整个电路呈现纯电阻性的措施。
当电阻 R
与电容C
串联之后(左图),由于电容 C
对于各种频率信号的容抗各不相同,所以整个 RC电路的阻抗特性曲线如(右图)所示:
RC串联电路会对各个频率的信号呈现出不同的阻抗,当信号频率大于转折频率\(f_0\) 以后,电容 C
的容抗 \(X_C = \frac{1}{2 \pi fc}\)几乎为零,由 RC 串联电路的阻抗公式 \(|Z| =\sqrt{R^2 + X_C^2}\) 可以知道 \(|Z|\approx R\),此时 RC 串联电路的总阻抗主要由电阻R
的大小来决定。
而当信号频率小于转折频率 \(f_0\) 时,由于信号频率已经比较低,电容C
的容抗较大,不能被忽略,此时 RC串联电路的总阻抗为电阻 R
与电容 C
的阻抗之和。又由于电容C
的容抗会随着频率的降低而增大,所以特性曲线当中频率 \(f < f_0\)的一段是上升的,频率越低阻抗就越大。RC 串联电路的转折频率 \(f_0\) 可以通过下面的公式进行确定:
\[f_0 = \frac{1}{2 \pi RC}\]
通过上面方程可以看到,当电阻 R
保持不变时,增大电容 C
会降低转折频率\(f_0\),而当电容C
减小时,则会增大转折频率 \(f_0\)。相应的,通过改变电阻R
的大小也可以调整转折频率 \(f_0\) 的大小。
下图所示是 RC 并联电路(左侧)及其对应的阻抗特性曲线(右侧):
该电路的阻抗特性曲线上也存在着一个转折频率 \(f_0\),其值同样可以通过下面的公式计算得到:
\[f_0 = \frac{1}{2 \pi RC}\]
C
相当于开路,整个电路的阻抗由电阻R
所决定;R
和电容 C
阻抗的并联值。由于频率升高之后电容 C
的容抗下降,所以 RC 并联电路总阻抗的斜率也在下降;RC串并联电路(左图)及其阻抗特性曲线(右图)如下图所示,此处不再进行专门的分析与讨论:
滤波器是一种可以通过或者阻止特定频带信号的电路,可以分为无源滤波器和有源滤波器两种类型,分别拥有RC 和 LC两种电路形式。根据滤波信号的不同,可以再进一步划分为高通
、低通
、带通
三种子类型。
低通 RC 滤波器:当输入信号 \(u_i\) 上低于转折频率 \(f_0\)的信号进入电路时,电容 C
呈现出较大的容抗,不具备分流的作用,低频信号经过电阻R
正常输出。而当输入信号 \(u_i\) 上高于 \(f_0\) 的信号进入时,电容C
的容抗较小,这些高频信号在经过电阻R
之后,由电容 C
分流接地,所以该电路具备通低频阻高频的作用,此处转折频率\(f_0 = \frac{1}{2 \pi RC}\):
高通 RC 滤波器:当输入信号 \(u_i\) 中低于转折频率 \(f_0\) 的信号进入时,电容C
的容抗较大,输出电压 \(u_o\)减小,并且频率越低输出越小。而当高于转折频率 \(f_0\) 的信号进入时,电容C
的容抗较小,不会对信号产生衰减作用,从而实现了通高频阻低频的作用,这里的转折频率同样可以由\(f_0 = \frac{1}{2 \pi RC}\)求解得到:
带通 RC滤波器:只会让特定频带的信号通过,而频带之外的信号将会被阻止。将高通与低通滤波器组合到一起,设置适当的电路参数,就可以得到所需要的带通RC 滤波器。
除此之外,还有由电感 L
和电容 C
构成 LC滤波器,由于电感的感抗会随着频率的增加而增加,而电容的容抗会随着频率的增加而减小,因此LC 低通滤波器的串臂接电感,并臂接电容,而 LC高通滤波器当中电感与电容的位置正好相反,LC带通滤波器则同样是 LC 低通与高通两种滤波器的组合运用。
将下图的开关扳到电池组一侧,对电容器进行充电;然后再将开关扳到电感线圈一侧,让电容器通过电感线圈进行放电,此时会发现电流表上的指针左右摆动,表明电路当中产生了大小与方向做周期性变化的交变电流。
这种能够产生大小与方向呈周期性变化电流的电路称为振荡电路,上述电路就构成了一个简单的振荡电路,采用示波器观察振荡电流可以发现:LC回路当中产生的振荡电流与电压按照正弦规律进行变化。
接下来,分析 LC 回路当中产生振荡电流的完整过程:
如果振荡过程当中不存在能量损失,振荡过程能够得以持续进行,并且振幅保持不变,这种振荡称为无阻尼振荡。
电磁振荡在实际应用当中总会存在着能量损失,部分能量会被电路上的电阻转化为热能,这样振荡电路的能量逐渐损耗,振荡电流的振幅逐渐减小,直至最后完全停止下来,这种振荡就称为阻尼振荡。
注意:实际应用当中为了获得这种振幅保持不变的等幅振荡,可以通过晶体管将电源的能量周期性的补充至振荡电路,以补充振荡过程当中的能量损耗。
振荡电路当中发生无阻尼振荡的周期与频率,称为该振荡电路的固有周期(简称为周期
)和固有频率(简称为频率
)。当添加至电容器上的电压恒定时,电容器的电容越大,其容纳的电荷就越多,放电与充电的时间就越长,周期也就越长,频率就会越低;电感器线圈的电感值越大,阻碍电流变化的作用就会越强,放电与充电所需的时间也就会越长,因而周期就会越长,频率也就会越低。周期\(T\)(秒)和频率\(f\)(赫兹)分别与自感系数\(L\)(亨利)和电容\(C\)(法拉)的关系如下面方程组所示:
\[\begin{cases}周期 T = 2 \pi \sqrt{电感 L \times 电容 C} \\频率 f = \frac{1}{2 \pi \sqrt{电感 L \times 电容 C}}\end{cases}\]
注意:由此可见,改变电容或者电感,就可以调整振荡电路的周期与频率。
下图描述了一个 LC串联谐振电路,假设信号电压为 \(u\),频率为 \(f\),当电路里的感抗 \(X_L\) 和容抗 \(X_C\) 相等 \(2\pi f L = \frac{1}{2 \pi f C}\) 时,那么 \(\phi = \arctan \frac{X_L - X_C}{R} =0\),此时输入信号电压 \(u\)与电流 \(i\)同相,该串联电路产生谐振现象,称为串联谐振。
由于 \(2 \pi f L = \frac{1}{2 \pi fC}\)是产生串联谐振的条件,由此就可以得到谐振频率 \(f_0\):
\[信号频率 f = 谐振频率 f_0 = \frac{1}{2 \pi \sqrt{电感 L \times 电感 C}}\]
从上面的方程可以看到,谐振频率 \(f_0\) 只与电感L
和电容 C
的大小有关,而与电阻 R
无关。当输入的信号频率 \(f\)等于该电路的固有谐振频率 \(f_0\)时,电路就会发生串联谐振现象。由此可见,通过调节电感L
与电容 C
以及输入的信号频率 \(f\),都可以使得电路发生谐振。
R
。L
上的电压等于电容 C
上的电压(电感 L
上的电压超前于电流90°
,而电容 C
上的电压滞后电流 90°
),因而信号电压 \(\dot{U}\) 与电阻 R
上的电压 \(\dot{U_R}\)保持一致:L
与电容C
上的电压都将会高于信号电压,但是电压过高会导致元件损坏,因而通常需要避免发生串联谐振。但是在无线电射频应用当中,经常会利用串联谐振来进行选频。注意:由于串联谐振时电感
L
与电容C
上的电压会超过信号电压许多倍,所以串联谐振也被称做电压谐振。
电感 L
的电压 \(U_L\) 以及电容C
的电压 \(U_C\)与信号电压 \(U\)的比值使用品质因数 \(Q\) 来进行表示:
\[品质因数 Q = \frac{电容电压 U_C}{信号电压 U} = \frac{电感电压U_L}{信号电压 U} = \frac{1}{\omega_0 CR} = \frac{\omega_0 L}{R}\]
品质因数 \(Q\)简称为 \(Q\)值,表征的是发生谐振时,电容或电感元件上的电压是输入信号电压的 \(Q\) 倍。例如品质因数 \(Q = 100\),而输入电压 \(U =6mV\),那么电路发生谐振时,电容或者电感元件上的电压为 \(U_L = U_C = 600mV\)。
无线电射频接收机选择信号时,就运用到了串联谐振原理。下图是接收机当中的输入电路,其作用是将目标频率信号,从天线所接收到的诸多频率信号当中选择出来:
该电路主要由天线线圈 \(L_1\),以及电感线圈 \(L\) 与可变电容器 \(C\)组成的串联谐振电路所共同构成。天线接收到的各种不同频率信号会在LC 谐振电路当中产生 \(e_1\)、\(e_2\)、\(e_3\) 等感应电动势:
上图当中的 \(R\) 是电感线圈 \(L\)的电阻,通过调节可变电容 \(C\)的容值,就可以将目标信号的频率调整至串联谐振频率,此时 LC回路当中该频率的电流最大,可变电容器 \(C\)两端的该频率电压也就最高。而其它频率由于未能达到谐振,在回路当中产生的电流较小,从而起到了选择信号和抑制干扰的作用。
除此之外,当谐振曲线比较尖锐时,稍微偏离谐振频率,信号会就大大减弱。换而言之,谐振曲线越尖锐,选择性也就越强。为了定量描述信号选择性的优劣程度,此处引入了通频带宽度的概念:
电流 \(I\) 达到其最大值 \(I_0\) 的 70.7%
位置(\(\frac{1}{\sqrt{2}}\))时,其上限(\(I_0\))与下限(\(0.707 I_0\))之间所对应的频率宽度 \(f_1 + f_0 + f_2\)就称为通频带宽度。通频带宽度越小,说明谐振曲线就越尖锐,电路的频率选择性也就越强。谐振曲线的尖锐或者平坦,与品质因数Q 的值密切相关:
假设电路的电感值 L
和电容值 C
不变,只改变电阻值 R
,那么根据 \(Q = \frac{1}{\omega_0 CR} = \frac{\omega_0L}{R}\),品质因数 Q 的值越大,电阻值R
就会越小,谐振曲线就会越尖锐,信号选择性也就会越强。
下图是一个 LC 并联谐振电路,其中 R
表示的是电感 L
的直流电阻:
LC 并联谐振电路的谐振频率 \(f_0\),可以通过下面的公式计算得到:
\[谐振频率 f_0 = \frac{1}{2\pi \sqrt{电感 L \times 电容 C}}\]
通过上面的方程可以看出,LC 并联谐振电路的谐振频率与 R
无关,而只会与电感 L
和电容 C
相关,当信号频率等于该电路的固有谐振频率\(f_0\) 时,就会发生并联谐振现象。
Q
倍,但是两者的方向相反大小近似,其差值为回路总电流。由于电容与电感支路当中的电流达到最大值,所以并联谐振也被称为电流谐振。Q
值具备不同的曲线,Q
值较大的曲线更为尖锐。谐振频率 \(f_0\)位置,电路的阻抗最大。当信号频率 \(f\)高于或者低于谐振频率时,电路的阻抗将会下降,并且偏差越多阻抗就会越小:注意:同样可以利用并联谐振时阻抗较高的特点,对信号进行选择,并且将干扰信号滤除。
陷波器广义上也属于一种滤波器,其作用是阻碍特定频带的信号,而该频带之外的信号则能够顺利通过,因而也被称为吸收电路。
下面是 LC串联谐振陷波器电路(左侧)及其输出信号特性曲线(右侧),输出信号\(u_o\) 在频率 \(f_0\)位置较弱,说明该频率的信号已经被阻隔:
由于 LC串联谐振电路在谐振时的阻抗最小,假设谐振频率为 \(f_0\),此时输入信号当中的 \(f_0\)频率信号被该电路分流至地。而对于远远高于或低于 \(f_0\) 频率的信号,由于 LC电路失去谐振能力,电路的阻抗较大不能对地分流,从而只会吸收以 \(f_0\) 为中心频率的较小频带信号。
下面是 LC并联谐振陷波器电路(左侧)及其输出信号特性曲线(右侧):
由于 LC 并联谐振电路的阻抗 \(|Z|\) 为最大值,\(|Z|\) 又与下方的电阻 \(R\)构成分压电路,此时输出信号 \(u_o = \frac{R}{R+|Z|}u_i\),可见在谐振频率\(f_0\) 位置,由于阻抗 \(|Z|\) 最大,所以输出信号 \(u_o\)最小,即输入信号的衰减较大。而对于输入信号 \(u_i\)当中频率远远高于或者低于谐振频率 \(f_0\) 的信号,由于电路失去谐振效应,阻抗\(|Z|\)变得非常小,所以输出电压与输入电压近似相等 \(u_o \approx u_i\)。
下面是 桥 T式谐振陷波器电路(左侧)及其等效电路(中间),以及它们的输出信号特性曲线(右侧):
上图左侧是一个由电阻 \(R\) 和电容 \(C\)构成的三角形电路,通过三角形到星形的等效变换,可以将其转换为中间的等效电路,该电路的谐振频率\(f_0\)可以通过下面的公式计算得到:
\[谐振频率 f_0 = \frac{1}{2\pi \sqrt{电感 L \times (2 \times 电容 C)}}\]
上图中间的等效电路当中,\(-\frac{R}{4}\)是一个负电阻,当 \(r =\frac{R}{4}\) 的时候,该回路谐振时的总电阻为零,对于频率为 \(f_0\) 的信号体现出了极强的隔离能力。
下面是 并联桥 T式陷波器电路(左侧)及其输出信号特性曲线(右侧):
并联桥 T 式是在桥 T式陷波器电路的基础上,在原来的电感L
上面并联了电容器 \(C_1\),从而构成了一个 LC并联谐振电路,其谐振频率为 \(f_{02}\)。当输入信号频率低于 \(f_{02}\) 时,该 LC并联谐振电路失去谐振能力,此时电路呈现出感性,可以将其等效为一个电感L
。这个等效电感 \(L\)与电阻 R
以及两个电容C
构成了一个桥 T 式陷波电路,其吸收频率为\(f_{01}\),并且 \(f_{01} <f_{02}\)。由此可见,该并联桥 T式陷波器会阻隔频率为 \(f_{01}\) 的信号,而对频率为 \(f_{02}\) 的信号则会起到提升的作用。
移相电路可以使得输出信号的相位滞后或者超前于输入信号指定角度,本小节将会介绍几种常用的移相电路。
RC 移相电路主要由电阻 R
和电容 C
两个元件组成,流经电阻 R
的电流与其两端的电压相位相同,而流过电容 C
的电流超前于电压 90°
,RC移相电路正是利用电容器的这个特性来实现移相的。
下图左侧是 RC 超前移相电路,该电路当中 \(u_i\) 为输入信号电压,而 \(u_o\) 为输出信号电压(也就是电阻R
两端的电压)。这个电路能够让 \(u_o\) 信号的相位超前于 \(u_i\),移相电路的分析通常需要应用到右侧的向量图:
根据向量图可以清楚的看到,\(\dot{U_C}\) 与 \(\dot{U_i}\) 的夹角为 \(\phi\),即 \(\dot{U_o}\) 超前于 \(\dot{U_i}\) 了 \(\phi\)角。说明输入信号添加到该电路之后,输出信号被超前移相了 \(\phi\),所以该电路属于超前移相电路。分析该向量图还可以知道,通过改变\(\dot{U_R}\) 或者 \(\dot{U_C}\) 的大小,就可以改变移相角 \(\phi\),只要适当选取电阻R
与电容 C
的值,就能够获取90°
范围之内的相位超前量。
下图左侧是 RC 滞后移相电路,该电路与 RC超前移相电路的主要区别在于互换了电阻R
与电容 C
的位置,输入电压依然为 \(u_i\),而输出电压 \(u_o\) 则来自于电容C
两端的电压 \(u_c\),该电路能够使得输出信号 \(u_o\) 的相位滞后于输入信号 \(u_i\)。
根据向量图可以知道,\(\dot{U_o}\) 与\(\dot{U_i}\) 的夹角为 \(\phi\),并且 \(\dot{U_o}\) 滞后于 \(\dot{U_i}\),说明输入信号进入该电路之后,输出信号被滞后移相了\(\phi\),所以该电路属于滞后移相电路。除此之外,还可以从向量图当中发现,通过改变\(\dot{U_R}\) 与 \(\dot{U_C}\) 的大小,就可以调整相位角 \(\phi\),即适当选取电阻R
与电容 C
的值,就能够获取90°
范围以内的相位滞后量。
下图左侧是 RL 超前移相电路,电感L
可以让电压超前于电流90°
,恰好与电容的特性相反,该电路当中输入电压为\(u_i\),输出电压 \(u_o\) 取自于电感L
的两端:
观察向量图可以看到,\(\dot{U_o}\)超前于 \(\dot{U_i}\) 了 \(\phi\) 角,通过调整 \(\dot{U_R}\) 或者 \(\dot{U_L}\) 的大小,就可以改变移相角 \(\phi\),因此只要适当选取电阻R
与电感 L
的值,就能够获得90°
范围以内的相位超前量。
下图左侧是 RL 滞后移相电路,该电路的输出电压 \(u_o\) 取自于电阻R
的两端,而不像上面的 RL超前移相电路那样取自电感 L
两端。
分析上图右侧的向量图可以发现,输出信号 \(\dot{U_o}\) 滞后于输入信号 \(\dot{U_i}\) 的角度为 \(\phi\) ,该电路的最大滞后相移量为90°
。
下图左侧的 LC并联谐振移相电路主要由电感 L
与电容 C
构成,其中电感 L的值可以进行微调,该电路的谐振频率为 \(f_0\),下图右侧为该谐振电路的相频特性曲线。
0
;-90°
),表示滞后相移;+90°
),表示超前相移;该电路移相的原理为:如果需要对输入频率为 \(f_i\)的信号进行滞后相移,那么只需要调整电感 L
的值,使得该电路的谐振频率 \(f_0 <f_i\),从而实现对频率 \(f_i\)信号的滞后相移。反之,如果需要对输入信号 \(f_i\)进行超前相移,同样只需要调整电感 L
的值,使得电路的谐振频率 \(f_0 >f_i\),从而就可以实现对于频率 \(f_i\) 的超前相移。
注意:对于 LC并联谐振电路,当输入信号频率 \(f_i\) 等于该谐振频率 \(f_0\)时,谐振电路呈现出阻性;当 \(f_i\) 大于 \(f_0\)时,则该电路呈现容性;而当 \(f_i\) 小于 \(f_0\)时,该电路就会呈现感性。
串联谐振移相电路与上述并联谐振移相电路的不同之处在于,当输入信号频率\(f_i > f_0\)时,就会发生滞后相移;而当 \(f_i < f_0\)时,发生的是超前相移。与并联谐振移相电路一样,只需要通过调节电感L
,就能够改变 LC串联谐振电路的谐振频率大小,从而获得 \(-90° \sim +90°\) 范围内的相移。
注意:LC 串联谐振电路的输入信号频率\(f_i\) 等于其谐振频率 \(f_0\)时,谐振电路呈现出阻性;当 \(f_i\) 大于 \(f_0\) 时呈现感性;而当\(f_i\) 小于 \(f_0\)时就会呈现出容性。
当交流信号通过导线时,由于导线上各个部分的电流密度分布不均匀,导致内部的电流密度较小,而表面的电流密度较大,这种现象就称为趋肤效应。产生趋肤效应的原因主要是由于感抗的作用,导线内部比表面具有更大的电感,对于交流信号的阻碍作用更大,从而使得电流密集于导线的表面。
趋肤效应会致使导线的有效横截面积减小,导线对于交流信号的阻碍较大。交流信号的频率越高,趋肤效应就越加明显。当频率提高至一定程度以后,就可以认为电流完全从导线表面流过。因而在设计高频交流电路的时候,必须要考虑趋肤效应的影响。解决办法是通过增加导体的表面积,从而尽量克服趋肤效应带来的不良影响。
复数具有多种表示形式,其代数形式正如下面公式所展示的那样:
\[复数 A= 实部 a + 虚数单位 j \times 虚部b\]
其中,a
为复数的实部, b
为复数的虚部,j
是虚数单位 \(j =\sqrt{-1}\)。除此之外,复数还可以采用复平面上的有向线段来进行表示:
上图当中的横坐标为实数轴(单位为+1
),纵坐标为虚数轴(单位为+j
),两条轴构成的平面称为复平面。
复数 \(A = a + jb\)就是复平面上横坐标为 a
纵坐标为 b
的一个点,其中 a
作为复数的实数部分,其值等于复数A
在实数轴上的投影;而 b
作为复数的虚数部分,其值等于复数 A
在虚数轴上的投影。除此之外,复平面上矢量OA 的长度采用 r
进行表示,称为复数的模,而矢量与实轴正方向的夹角 \(\phi\),称为复数的辐角。上面的图形当中,复数A
的实部a
、虚部b
、模r
、辐角 Φ
之间存在着如下关系:
\[\begin{cases}实部 a = 模 r \times \cos 辐角 \phi \\虚部 b = 模 r \times \sin 辐角 \phi\end{cases}\ \ \ \ \ \ \ \ \\begin{cases}模 r = \sqrt{实部 a^2 + 虚部 b^2} \\辐角 \phi = \arctan \frac{虚部 b}{实部 a}\end{cases}\]
根据上面的方程组,就可以将 \(A = a +jb\) 改写为如下复数的三角形式:
\[复数 A = 模 r \cdot \cos \phi + 虚数单位 j \cdot 模 r \cdot \sin \phi\]
除此之外,根据欧拉公式 \(\cos \phi = \frac{e^{j \phi} + e^{-j\phi}}{2}\) 和 \(\sin \phi = \frac{e^{j\phi} - e^{-j \phi}}{2j}\)还可以得到复数的指数形式:
\[复数 A = 模 r \times e^{虚数单位 j \times 辐角 \phi}\]
为了便于书写和表达,复数的指数形式还可以变换为极坐标形式:
\[复数 A = 模 r \times \angle 辐角 \phi\]
综上所述,复数 \(A\)的多种表达方式都可以总结为下面的等式:
\[A = a + jb = r \cos \phi + j r \sin \phi = re^{j \phi} = f \angle \phi\]
注意:无论复数采用哪种表达形式,只要拥有模\(r\)、辐角 \(\phi\)(或是实部 \(a\) 与虚部 \(b\))两个要素就可以确定其对应的复数。
当复数进行相加或者相减运算的时候,通常采用其代数形式,即实部与实部相加减,虚部与虚部相加减:
\[\begin{aligned}A_1 = a_1 + jb_1 \\A_2 = a_2 + jb_2\end{aligned}\impliesA_1 \pm A_2 = (a_1 \pm a_2) + j(b_1 \pm b_2)\]
而复数的乘除法运算,通常会选择使用指数形式或者极坐标形式。当两个复数相乘时,其模值相乘,辐角相加;而当两个复数相除时,其模值相除,辐角相减:
\[\begin{aligned}A_1 = r_1 e^{j \phi_1} = r_1 \angle \phi_1 \\A_2 = r_2 e^{j \phi_2} = r_2 \angle \phi_2\end{aligned}\implies\begin{cases}A_1 \times A_2 = r_1 r_2 e^{j(\phi_1 + \phi_2)} = r_1 r_2 \angle(\phi_1+ \phi_2) \\\frac{A_1}{A_2} = \frac{r_1}{r_2} e^{j(\phi_1 + \phi_2)} =\frac{r_1}{r_2} \angle(\phi_1 - \phi_2)\end{cases}\]
电路分析时,经常需要使用到 \(j\)的乘方运算,由于虚数单位 \(j= \sqrt{-1}\),所以就可以得到下面的一系列结果:
\(j^2 =-1\) | \(j^3 =-j\) | \(j^4 =-j\) | \(\frac{1}{j}= \frac{j}{j^2} = -j\) |
---|
根据欧拉公式可以知道 \(e^{j \frac{\pi}{2}}= \cos \frac{\pi}{2} + j \sin \frac{\pi}{2} = +j\),换而言之\(e^{j \frac{\pi}{2}}\) 就是 \(+j\) 的复数形式,同理还可以得到 \(e^{-j \frac{\pi}{2}}\) 为 \(-j\) 的复数形式。
由此就可以得出结论:复数 \(A\) 乘以\(+j\)等于该复数对应矢量在复平面上,从原矢量位置逆时针旋转\(\frac{\pi}{2}\) 角度;同理,复数\(A\) 乘以 \(-j\)等于该复数对应矢量在复平面上,从原矢量位置顺时针旋转\(\frac{\pi}{2}\)角度,具体可以参考下面的图形:
正弦量主要是由幅值(或有效值)、频率、初相位三个要素决定,正弦交流电路当中,由于电压与电流均属于同频率的正弦量,因而如果需要求解电压或者电流,只需要获得其幅值/有效值
和初相位
即可,而复数正好可以代表这两个要素。
假设电流 \(i\) 的瞬时表达式为 \(i = I_m \sin(\omega t + \phi) = \sqrt{2} I\sin(\omega t + \phi)\),将电流的有效值向量 \(\dot{I}\) 放置到复平面:
结合前面讨论的知识,就可以获得该正弦量的复数表达形式 \(\dot{I}\):
\[\dot{I} = a + jb = I(\cos \phi + j \sin \phi) = I e^{j \phi} = L \angle\phi\]
由于 \(\dot{I}\)是复数,其模值等于正弦量的有效值 \(I\),辐角等于正弦量的初相角 \(\phi\),这个复数就称为有效值向量。同理,复数\(\dot{I}_m\)则被称作电流的最大值向量。
注意:为了区别于普通的复数,表示正弦量的复数通常需要添加\(\dot{}\) 符号。
纯电感电路当中,假设回路电流 \(i = I_m \sin\omegat\),由于纯电感电路当中电流比电压滞后90°
,所以电压 \(u = U_m \sin (\omega t +90°)\),该等式当中的 \(U_m = I_m \omegaL\),即 \(U_m = I_m X_L\):
电流 \(i\)和电压 \(u\)瞬时表达式对应的复数形式,可以参考下面的推导过程:
\[\begin{cases}\dot{I} = I e^{j 0°} = I \angle 0° \\\dot{U} = U e^{j 90°} = U \angle 90°\end{cases}\implies\frac{\dot{U}}{\dot{I}} = \frac{U}{I} e^{j90°}\]
由于纯电感电路电压
与电流
的有效值符合欧姆定律,即\(U = I X_L\),而 \(X_L =\frac{U}{I}\),从而可以得到纯电感电路欧姆定律的向量复数表达式:
\[\frac{\dot{U}}{\dot{I}} = \frac{U}{I} e^{j90°} = j X_L\implies\dot{U} = j I X_L = j \dot{I} \omega L\]
纯电容电路当中,假设输入电压 \(u = U_m \sin\omegat\),由于纯电容电路当中电流比电压滞后90°
,所以电流 \(i = I_m \sin (\omega t + 90°)\):
电流 \(i\)和电压 \(u\)的瞬时表达式所对应的复数形式,同样可以参考下面的推导过程:
\[\begin{cases}\dot{U} = U e^{j 0°} = U \angle 0° \\\dot{I} = I e^{j 90°} = I \angle 90°\end{cases}\implies\frac{\dot{U}}{\dot{I}} = \frac{U}{I} e^{-j90°}\]
由于纯电容电路电压
与电流
的有效值符合欧姆定律,即\(U = I X_C\),而 \(X_C =\frac{U}{I}\),从而就可以得到纯电感电路欧姆定律的向量复数表达式:
\[\frac{\dot{U}}{\dot{I}} = \frac{U}{I} e^{-j90°} = - j X_C\implies\dot{U} = - j I X_C = - j \frac{\dot{I}}{\omega C} = \frac{\dot{I}}{j\omega C}\]
下图左侧 RC 电路上的 \(\dot{U_1}\)是输入信号电压,\(\dot{U_2}\)是输出信号电压,而右侧是该电路对应的向量图:
根据上述电路,可以求解出该电路的输出电压 \(\dot{U_2}\) 等于:
\[\dot{U_2} = \dot{I} \times \frac{1}{j \omega c} = \frac{\dot{U_1}}{R +\frac{1}{j \omega C}} \times \frac{1}{j \omega C} = \frac{\dot{U_1}}{1 +j \omega RC}\]
通常情况下,输出电压 \(\dot{U_2}\) 与输入电压\(\dot{U_2}\)的比值称为这个电路的传递函数:
\[\frac{\dot{U_2}}{\dot{U_1}} = \frac{1}{1 + j \omega RC} =\frac{1}{\sqrt{1 + (\omega RC)^2}} \angle - \arctan(\omega RC) =T(\omega) \angle \phi(\omega)\]
可以看到在上述方程当中,传递函数的结果也是一个复数。而等式当中的\(T(\omega) = \frac{U_2}{U_1} =\frac{1}{\sqrt{1 + (\omega RC)^2}}\)是输出电压与输入电压有效值的比值,也是角频率 \(\omega\) 的函数。而 \(\phi(\omega) = - \arctan(\omega RC)\)则是输出电压与输入电压之间的相位差,同样也是角频率\(\omega\)的函数。稍加归纳,即可以得出如下的结论:
当输出电压下降至输入电压的 0.707
倍时,两者的相位差为\(-\frac{\pi}{4}\)。实际应用当中,为了使输出电压不至于下降过大,特规定该值为最低限度,此时对应的\(\omega_0\)称为截止角频率,其频率特性曲线如下图所示:
可以看到,当 \(\omega <\omega_0\) 的时候,\(T(\omega)\)的变化不大;而当 \(\omega >\omega_0\) 时,\(T(\omega)\)下降明显;表明该电路可以通过低频信号,而且能够抑制高频信号,这也就是前面内容介绍过的低通滤波器。
一个线圈在磁场里转动,电路当中只会产生一个交变电动势,此时发出的交流电称为单相交流电。如果在磁场里有三个互成角度的线圈同时转动,那么电路当中就会产生三个交变电动势,此时发出的交流电流称为三相交流电。
下图是三相发电机的示意图,在铁芯上固定着AX、BY、CZ三个线圈,它们之间互成 120°
角。转动铁芯就会带动三个线圈在磁场当中匀速的转动,从而发出最大值
与频率
都相同,但是相位
并不相同(相位之间互差120°
)的三个电动势。
取上图当中的 \(t = 0\)时刻作为时间起点,这三个电动势可以分别被表示为 \(e_A\)、\(e_B\)、\(e_C\):
\[\begin{cases}e_A = E_m \sin \omega t \\e_B = E_m \sin (\omega t - 120°) \\e_C = E_m \sin (\omega t - 240°) = E_m \sin (\omega + 120°)\end{cases}\]
三相交流电依次出现正最大值的顺序称为相序,顺时针按照A → B → C顺序循环的相序称为顺序或者正序,而按照A → C → B顺序循环的相序称为逆序或者负序。相序是由发电机转子的旋转方向决定的,多数情况下会选择使用顺序。
电源(例如交流发电机)的三相绕组通常采用星形连接方法,将绕组的X
、Y
、Z
三个末端连接在一起形成公共点,称为电源的中性点或者零点,用英文字母N 进行表示。然后从A
、B
、C
三个首端以及中点N引出四条导线与外电路相连接,从而构成一个三相四线制电源:
其中,从首端引出的三条导线称为相线或者端线,俗称为火线,分别用字母\(A\)(黄)、\(B\)(绿)、\(C\)(红)表示,而从中性点引出的导线称为中线或者零线,采用字母\(N\)(黑) 进行表示。
从三相四线制电源当中可以获得相电压和线电压两种电压形式:
相线
与中线
之间的电压,其参考方向是从相线
指向中线
,有效值采用\(U_A\)、\(U_B\)、\(U_C\) 进行表示,或者一律采用 \(U_p\) 进行表示;线电压与相电压之间的换算关系为\(U_l = \sqrt{3}U_p\),线电压与相电压之间的关系可以采用下面的向量图进行表示:
从上图可以看到,三个线电压之间的相位差仍然为120°
,它们分别比三个相电压超前了30°
。如果相电压是对称的,那么线电压一定也是对称的,根据向量图可以得到三个线电压与三个相电压之间的换算关系:
\[\begin{cases}U_{AB} = 2 U_A \cos 30° = 2 \times \frac{\sqrt{3}}{2} U_A = \sqrt{3} U_A\\U_{BC} = \sqrt{3} U_B \\U_{CA} = \sqrt{3} U_C\end{cases}\]
注意:我国的低压三相供电标准为 50Hz380V/220V,其中的
220V
是指相电压,而380V
是指线电压(\(380 V =\sqrt{3} \times220V\)),工程上讨论三相电源的电压大小时,通常指的是电源的线电压。
交流用电设备(负载)可以划分为单相负载(使用单相电源供电的用电设备)和三相负载(使用三相电源供电的用电设备)两种类型,三相供电系统当中的负载具有星形(\(Y\))和三角形(\(\Delta\))两种基本接法。
下图所示的三相四线制电路当中,假设其线电压为380V
,负载连接要根据其额定电压来决定。通常情况下,电灯(单相负载)的额定电压为220V
,需要连接在火线与中线之间。由于电灯负载使用量较大,不能集中连接在一相当中,而应当比较均匀的分布在各相,这种连接方法就被称为星形连接。
三相四线制电路当中,负载的星形连接可以采用下图进行表示:
电路当中的 \(Z_A\)、\(Z_B\)、\(Z_C\) 分别为 \(A\)、\(B\)、\(C\)相的负载,并且 \(Z_A = Z_B =Z_C\),它们既可以是三相交流电机的三相绕组,也可以是由三个单相负载组成的三相负载。三个负载的一端连接到火线A、B、C,另外三个端连接为公共端,称为负载中点N,然后将其与电源的中点 \(N'\) 进行连接。
如果忽略输电线路上的阻抗压降,那么每相负载的电压就等于对应电源的相电压,即电源线电压的\(\frac{1}{\sqrt{3}}\) 倍:
\[电源的相电压 U_p = \frac{1}{\sqrt{3}} 电源的线电压 U_l\]
三相电路当中的电流也有相电流与线电流之分,每相负载当中的电流\(I_p\)称为相电流,每条火线当中的电流 \(I_l\)称为线电流。当负载为星形连接时,相电流就等于线电流\(I_p = I_l\)。
对称三相负载星形连接的电路,其各相负载电流的幅度相等,各相电流的相位依次相差120°
,因而三个相电流 \(I_A\)、\(I_B\)、\(I_C\) 是对称的,而中线电流\(I_N\) 等于0
。正是由于中线电流为0
,所以动力用电通常会省去中线,而直接采用三相三线制星形供电方式。尽管没有中线,但是由于负载具备对称性,从而保证了负载中点\(N'\) 和电源中点\(N\) 的电位相等。
阻抗不相等的三相负载称为三相不对称负载,该场景主要发生在三相四线制低压民用供电线路当中,由于各个家庭拥有的电器数量不同,使用时间又较为随意,因而供电线路会处于三相不对称负载的运行状态。此时,各相的电流不相等,中线电流也不为零。
正是由于中线的存在,即使三相负载不对称,负载的三个相电压仍然等于对称的电源相电压,因而能够保证负载的正常工作。但是如果中线发生断开事故,就会导致其中一相或者两相的电压升高,造成负载的相电压不等于电源的相电压,进而导致负载损坏或者无法正常工作,同时还会致使负载中点(零线)带电。
注意:三相负载越不对称,这个现象就越为严重,民用供电线路当中出现大范围烧毁家用电器的事故,多数情况就是由于中线断路导致的。
负载三角形连接的三相电路可以采用下图电路进行表示,该电路当中的\(Z_{AB}\)、\(Z_{BC}\)、\(Z_{CA}\)为每相的负载。
当负载进行三角形连接时,由于各相负载都直接连接到电源的线电压,所以负载的相电压等于电源的线电压。因而无论负载对称与否,其相电压总是对称的:
\[U_{AB} = U_{BC} = U_{CA} = 线电压 U_l = 相电压 U_p\]
负载三角形连接时的相电流 \(I_p\) 与线电流 \(I_l\)并不相同,如果负载对称,那么线电流就是相电流的\(\sqrt{3}\)倍,并且线电流的相位滞后于相电流30°
,即 \(I_l = \sqrt{3}I_p\)。
注意:三相电动机的绕组即可以连接为三角形,也可以连接为星形,而照明负载通常都连接为具有中线的星形。
无论负载是星形连接还是三角形连接,其总有功功率\(P\)等于各相有功功率之和,而不管其三相负载对称与否:
\[总功率 P = P_A + P_B + P_C = U_A I_A \cos \phi_A + U_B I_B \cos \phi_B +U_C I_C \cos \phi_C\]
上面方程当中的 \(U_A\)、\(U_B\)、\(U_C\)是三相负载的相电压,而 \(I_A\)、\(I_B\)、\(I_C\)是三相负载的相电流,\(\phi_A\)、\(\phi_B\)、\(\phi_C\)则是三相负载相电压
与相电流
之间的相位差。
当三相负载对称时,每一相的有功功率都相等,因而三相总功率\(P\) 等于:
\[总功率 P = 3 \times 相电压 U_p \times 相电流 I_p \times \cos 相位差 \phi\]
注意:当对称负载是星形连接时,线电压\(U_l = \sqrt{3}U_p\),线电流 \(I_l =I_p\);当对称负载是三角形连接时,线电压\(U_l = U_p\),线电流\(I_l = \sqrt{3} I_p\)。
三相电路的无功功率用于衡量三相电源与负载之间能量交换的大小,根据能量守恒定律,三相电路的无功功率\(Q\) 等于三相负载的无功功率之和:
\[无功功率 Q = Q_A + Q_B + Q_C = U_A I_A \sin \phi_A + U_B I_B \sin \phi_B+ U_C I_C \sin \phi_C\]
当负载对称时,无功功率 \(Q\) 与相电压 \(U_p\) 以及相电流 \(I_p\) 之间具备 \(Q = 3 U_p I_p \sin \phi\) 的关系。
注意:无功功率如果没有被负载完全消耗,那么就只能在电路当中反复传送(时而从电源传送到负载,时而又从负载传送至电源),无功功率的这种来回传送不仅会占用电网资源,还会加大传输线路的损耗。
三相电路的视在功率就是三相电路可以提供的最大功率,通常情况下就是电网的容量:
\[视在功率 S = \sqrt{P^2 + Q^2} = 3 U_p I_p = \sqrt{3} U_l I_l\]
注意:上面的公式表明,提高功率因数并且减少无功功率,就可以充分发挥电网的供电能力。
触电的危险程度与这些因素紧密相关:通过人体的电流与电压、电流作用时间的长短、频率高低、电流经过人体的途径、人体的电阻:
人体触电主要有单相与双相两种触电形式:
下图是三相电源中性点不接地时的示意图,虽然此时供电线路没有与大地直接连接,但是线路与大地之间却存在着电容效应(分布电容)。供电线路越长,分布电容越大,对于50Hz
工频而言产生的容抗就越小。如果发生漏电事故,电流将会通过人体、大地、分布电容构成回路:
如果将负载的外壳通过导线与大地进行连接,那么发生触电事故时,人体的电阻\(R_r\) 将会与接地电阻 \(R_d\) 并联。人体的电阻较低时约有1000Ω
,而接地装置的接地电阻应当低于4Ω
,显然由于 \(R_r >>R_d\),漏电电流的绝大部分将会被接地电阻 \(R_d\)分流,此时通过人体的电流较小,从而有效保障了人身安全,这种措施就称为保护接地:
注意:人工接地体通常需要采用钢管或者角钢植入地下
4m
以上,保护接地仅适于中性点不接地的供电网络。
大多数三相四线制供电系统当中,三相电源(发电机)的中性点都是通过接地导线与大地进行可靠连接,此时负载的金属外壳并不会直接接地,而是连接到零线上面,这种措施称为保护接零:
当电器发生漏电时,相线通过漏电的金属外壳与零线连通构成回路。由于该回路的电阻较小,导致漏电电流较大,致使相线上的保险丝FU
熔断,进而切断电源保护人身安全。
如果保护接零系统当中的零线断开,那么非但不会起到保护作用,还会在三相负载不平衡时,引起各相电压不相等,造成用电设备无法正常工作或者烧毁,为此供电系统专门引入了多点重复接地作为保护措施:
正常情况下,重复接地电阻 \(R_c\) 与中性点接地电阻\(R_o\)并联,从而降低接零系统的电阻,提高保护能力。当零线断开时,故障电流就会通过重复接地电阻\(R_c\)构成回路,使得保险丝能够及时熔断,进而起到漏电保护的作用。
本节内容主要分析 RC 与 RL线性电路的过渡过程,主要讨论两个方面的问题:
电压
与电流
随时间变化的规律;当从一种稳定状态转换至另外一种新的稳定状态时,并不会发生跃变,而是需要经历一定的时间与过程,这个物理过程就称为过渡过程。电路当中产生过渡过程的原因主要有如下两个:
L
或者电容 C
等动态元件,这是产生过渡过程的内因;开启
与闭合
、元件的接通
与断开
等,这是产生电路过渡过程的外因;之前小节内容讨论的都是稳定状态下的电路,此时电路当中的电压
与电流
已经达到某一个稳态值(对于交流电路而言,指其幅值达到稳定),这就是所谓的稳态,而电路在过渡过程当中的工作状态被称为暂态过程。
一个处于稳定状态下的电路,如果电路当中的电源、元件参数、电路结构发生改变,那么电路的工作状态也会发生变化,该电路就会从原来的稳定状态进入另外一种新的稳定状态,这就是所谓的换路。发生换路之后,在过渡过程开始的瞬间,电路当中的电容电压与电感电流统称为电路的初始条件或者初始值,而确定电路初始值的依据就是换路定则。
下图所示的 RC 电路当中,开关S
闭合之前,电容两端的电压 \(u_C =0\),此时电容器极板上的电荷 \(q = 0\);当开关S
闭合之后,由于电场能量 \(W = \frac{1}{2}C u_C^2\)不会发生突变,所以电压 \(u_C\) 也就不会突变,电容器两端的电压会从0
逐步转变为等于 \(U\):
而下图所示的 RL 电路当中,开关S
闭合之前,电路当中的电流 \(i_L = 0\),电感线圈的磁通\(\phi = 0\);当开关S
闭合以后,由于磁场能量 \(W =\frac{1}{2}L i_L^2\) 不会发生突变,所以电流 \(i_L\) 也就无法突变,而必须从 0
逐步变化为 \(\frac{U}{R}\):
简便起见,我们可以认为换路是在一瞬间完成的,通常会将换路瞬间作为计时的起点\(t =0_+\),而将换路前的时刻记为 \(t =0_-\),换路之后的初始时刻则记为 \(t = 0_+\),进而可以得出如下两条结论:
注意:换路定则仅仅只适用于换路一瞬间的状态。
电路的初始值就是换路之后 \(t = 0_+\)时刻的电压
与电流
值,可以根据换路定则和基尔霍夫定律,按照下面步骤进行求解:
C
短路;如果\(u_C(0_+) = U\),则可以用一个电压为U
的电压源代替电容;如果 \(i_L(0_+) = 0\),就将电感器L
开路;如果 \(i_L(0_+) =I\),则采用一个电流为 \(I\)的电流源代替电感;注意:在换路的一瞬间,仅有电容电压与电感电流无法跃变,而电容电流与电感电压是可以发生跃变的;而对于纯电阻电路,电流和电压都可以发生跃变。
电路的稳态值是指换路之后,达到新的稳定状态时的电压
与电流
值,通常情况下采用\(u(\infty)\)、\(i(\infty)\) 进行表示。
直流状态下的 RC 与RL电路,在电路达到新的稳定状态时,电容器相当于开路,而电感器相当于短路。由此,就可以绘制出\(t = \infty\)时的等效电路,再通过直流电路的分析方法进行计算即可。
下图是一个 RC 串联电路,换路之前,开关S
处于位置 1,电源对电容进行充电,当充至\(u_C = U\) 之后,在 \(t = 0\) 时刻,将开关S
从位置 1 拨到位置2,使得电路断开电源,此时电容 C
会经过电阻 R
进行放电:
接下来,讨论放电过程当中,电路的电压
和电流
随时间
的变化规律。当开关S
从位置 1 拔动至位置 2时,电容器 C
开始放电,此时电容器两端电压 \(u_C\) 的变化规律如下所示:
\[u_C = U_e^{-\frac{t}{\tau}}\]
假设电流的正方向如上图箭头所示,此时放电电流的变化规律如下面方程所示:
\[i = \frac{U}{R} e^{-\frac{t}{\tau}}\]
在上面的等式当中,常数 \(e= 2.718\),而 RC 电路的时间常数 \(\tau = RC\)(具有时间量纲)。时间常数 \(\tau\)会影响电容两端的电压 \(u_C\) 和电流 \(i\),并且决定电路放电时间的长短。如果 \(\tau\)越大,就说明电容与电阻较大(电容越大,存储电荷越多;电阻越大,放电电流越小);反过来,如果\(\tau\)越小,就说明电容与电阻较小(放电时间更短,放电电流较大)。
换路之后,当 \(t = \tau\)的时刻,根据 \(u_C =U_e^{-\frac{t}{\tau}}\) 可以得到 \(u_C(\tau) = U_e^{-1} = \frac{U}{2.718} =0.368U\),此后每经过一个时间常数 \(\tau\),电容电压就会衰减至原值的0.368
倍:
\[\begin{aligned}u_C(2\tau) = 0.368 u_C(1\tau) = 0.135U \\u_C(3\tau) = 0.368 u_C(2\tau) = 0.050U \\u_C(4\tau) = 0.368 u_C(3\tau) = 0.018U \\u_C(5\tau) = 0.368 u_C(4\tau) = 0.007U\end{aligned}\]
理论上,电路只有经过 \(t = \infty\)时间才能达到稳定,但是实际上只经过了 \(t =5\tau\) 之后,电容电压就已经衰减至原值的0.7%
。通常认为换路之后经过 \(5\tau\)时间,电容的放电就已经基本结束,电容上的电压
与电流
变化曲线如下图所示:
电容放电的快慢可以通过改变电路的时间常数来进行控制,下图给出了\(\tau_1 > \tau_2 > \tau_3\)三种不同时间常数下 \(u_C\)的变化曲线:
当 RC串联电路的开关闭合之后,就会开始对电容器进行充电,此时可以划分为零状态和非零状态两种情况来进行分析。
换路之前,电路当中所有的储能元件均未储存能量,此时属于电路的零状态,即初始状态为零\(u_C(0_-) =0\)。当开关 S
闭合以后,电压源开始对电容器进行充电,经过推算,零状态下电容器两端电压\(u_C\) 的变化规律如下所示:
\[u_C = U(1 - e^{-\frac{t}{\tau}})\]
假设充电电流的正方向如上图所示,同样经过推算,就可以总结出充电电流\(i\) 的变化规律:
\[i = \frac{U}{R} e^{-\frac{t}{\tau}}\]
换路之后,当 \(t = \tau\)的时刻,根据公式 \(u_C = U(1 -e^{-\frac{t}{\tau}})\) 就可以得到 \(u_C(\tau)\) 至 \(u_C(5\tau)\):
\[u_C(\tau) = U(1 - e^{-1}) = U(1 - 0.368) = 0.632 U\implies\begin{cases}u_C(2\tau) = 0.865U \\u_C(3\tau) = 0.950U \\u_C(4\tau) = 0.982U \\u_C(5\tau) = 0.993U\end{cases}\]
电路在理论上只有经过 \(t = \tau\)时间才能达到稳定,实际上在经过 \(t =5\tau\) 之后,电容的电压就已经上升至电压源 \(U\) 的99.3%
。因而通常认为,换路之后经过 \(5\tau\)时间,电容器的充电就已经基本结束,电容电压 \(u_C\) 和电阻电压 \(u_R\)的变化曲线如下图左侧所示,而电流 \(i\)的变化曲线如下图右侧所示:
注意:电容器充电的快慢可以通过改变电路的时间常数来实现,时间常数越小充电越快,时间常数越大则充电越慢。
换路之前,电路当中的储能元件已经储存有能量,此时就处于电路的非零状态。对于本节内容开头的电路而言,假设在换路之前,电容器已经存在\(U_0\)电压,根据推算,就可以得到换路之后电容器的充电电压\(u_C\) 和充电电流\(i\):
\[\begin{cases}u_C = U + (U_0 - U) e^{- \frac{t}{\tau}} \\i = \frac{U - U_0}{R} e^{-\frac{t}{\tau}}\end{cases}\]
充电电压 \(u_C\)(下图左侧)和充电电流\(i\)(下图右侧)的波形图分别如下所示:
下图就是一个由电阻 R
和电容 C
构成的微分电路:
A
所示的周期性矩形脉冲时,微分电路就会输出下图B
所示的正负尖峰脉冲;接下来,简要介绍微分电路的工作过程。当输入信号 \(u_1\)脉冲出现的一瞬间,由于电容 C
两端的电压不能发生突变,所以呈现出短路状态,导致脉冲被添加到电阻R
上面,此时 R
上的电压 \(u_2\) 为最大。因为 RC 时间常数 \(\tau = RC\)非常小,所以在脉冲没有消失之前,电容 C
就已经充满了电荷,呈现开路状态。由于没有充电电流经过电阻R
,所以电压 \(u_2\)等于零,该过程会产生上图 B
所示波形里的正尖峰脉冲。同时,这个过程还会为电容C
充上左正右负的电压,电压大小为输入信号\(u_1\) 脉冲的幅值 \(U\)。
当输入信号 \(u_1\)脉冲消失的一瞬间,\(u_1\)等于零,此时相当于输入端接地。由于电容两端的电压无法突变,此刻电阻R
上的电压 \(u_2\)为负的最大电压值 \(-U\),即电容C
充上了左正右负的电压。又由于电容C
的左端接地,所以 \(u_2\)为负电压。因为 \(\tau = RC\)比较小,所以电容 C
通过电阻 R
很快放电完毕,而 \(u_2\) 又为零,从而得到上图 B
所示波形当中的负尖峰脉冲。
当第 2 个脉冲到来的时候,电阻 R
上面又会获得正尖峰脉冲。而当 \(u_1\)脉冲消失的时候,又会获得负尖峰脉冲。这样就可以通过微分电路,将矩形脉冲转换为正负尖峰脉冲。
下图就是一个由电阻 R
和电容 C
构成的积分电路:
A
所示的周期性矩形脉冲时,积分电路将会输出下图B
所示的锯齿波;接下来,简要介绍积分电路的工作过程。当输入的矩形脉冲信号\(u_1\) 出现时,输出 \(u_2\) 产生的电流会经过电阻R
对电容 C
进行充电,使得电容 C
上面的电压 \(u_2\) 逐渐增大。当脉冲消失之后,\(u_1\) 等于零,电容C
上面已经充满的电压又会经过电阻R
进行放电。但是由于时间常数 \(\tau = RC\)比较大,所以放电过程较为缓慢。当第 2个脉冲到来的时候,又会对电容 C
继续进行充电,使得输出电压 \(u_2\) 增大。通过观察就可以发现上图B
所示波形当中,输入脉冲越密集,输出电压 \(u_2\) 就会越大。
下图是一个由电阻 R
和电感 L
组成的 RL串联电路:
当开关 S
没有闭合的时候,电感器 \(L\)当中没有存储能量。而将开关 S
闭合以后,电路将会与恒定电压为 \(U\)的电压源导通,此时根据推算,电感器两端的电压\(u_L\)与电路当中的电流 \(i\)分别等于:
\[\begin{cases}u_L = U_e^{-\frac{t}{\tau}}\\i = \frac{U}{R}(1 - e^{-\frac{t}{\tau}})\end{cases}\]
上面方程组当中的 \(\tau\)同样具有时间的量纲,被称为 RL 电路的时间常数,\(u_L\) 与 \(i\) 的变化曲线如下图所示:
对于下图所示的 RL电路,在换路之前,开关 S
与位置2
导通,整个电路处于稳态,此时电感器L
当中的电流 \(I =\frac{U}{R}\),电感器储存了磁场能量:
当 \(t = 0\)时刻,将开关 S
从位置 2
放回到位置 1
,电路就可以变换为下面的形式:
由于电感器 L
上的电流无法突变,所以电感上电流的初始值为 \(i_L(0_+) = i_L(0_-) =\frac{U}{R}\),随后电感器当中存储的能量会不断通过电阻R
进行释放。电感值 L越大,电感器上面储存的电量就会越多,释放能量所需要的时间也就会越长,电阻R
越大,能量的衰减也就会越慢。经过推算,当开关S
从位置 2
回到位置 1
的时候,如果选定上图箭头所示的方向为正方向,那么电感器上面电流\(i_L\) 与电压 \(u_L\) 的变化规律为:
\[\begin{cases}i_L = \frac{U}{R} e^{-\frac{t}{\tau}}\\u_L = - Ue^{-\frac{t}{\tau}}\end{cases}\]
上面方程组当中的 \(u_L\)为负值,说明电感上面电压的方向与参考方向相反,\(i_L\) 与 \(u_L\) 的变化曲线如下图所示:
如果上面 RL 电路当中的开关 S
从电源断开,而并没有进行短路,那么此时电流的变化率\(\frac{\Delta I}{\Delta t}\)将会非常大,进而导致线圈产生的自感电动势 \(e_L = L\frac{\Delta I}{\Delta t}\)也会很大,该自感电动势可能导致开关击穿损毁,所以往往会在把线圈从电源断开的同时,对线圈进行短路,使得电流得以逐渐减小。
除此之外,还可以应用其它保护措施,例如在电感线圈的两端并联上续流二极管(下图左),或者接入阻容吸收电路(下图右):
]]>温度漂移
、传输线
、反射
、耦合电流
、功率分配
、趋肤效应
、介电损耗
和通孔
等,并且给出了每个常见问题的实用设计方案。全书分为四个部分,其中第一部分电流的性质介绍了电流的基本定义,第二部分基本电路中电流的流动包括了电阻电路、电抗(电容、电感)电路、以及阻抗相关的内容,第三部分则介绍了电压源与电流源,第四部分电路板上的电流则介绍了PCB 上引入的各种信号完整性问题。
电流是由电子的流动而产生,1A
电流指的是1S
时间内通过某个位置 1C
的电荷(即 \(6.25 \times 10^{18}\)个电子)。物质的原子当中包含有 3种基本粒子:质子(带 1个单位正电荷)、中子(不带电荷)、电子(带1个单位负电荷),其中质子和中子耦合在原子核,而电子则围绕着原子核做圆周运动。自然界当中的稳定元素都呈现电中性,因而任何元素原子当中的质子与电子数量必然相等。
价带(ValenceBand)是价电子
所占据的能量范围,而导带(ConductionBand)则是自由运动的电子
所具有的能量范围;价带当中只拥有一个电子的元素,更容易脱离价带进入导带形成自由电子,从而表现为导体;而价带当中拥有多个电子的元素,由于电子则难以脱离价带,从而表现为绝缘体;
注意:电子带有负电荷,同种电荷相互排斥,异种电荷相互吸引。
可以将带电粒子想象为一个球体,电场将会由该带电粒子向外呈辐射状分布:
当电子移动产生电流,电流的周边就会产生磁场。这个磁场围绕着电流呈同心圆形式分布,其方向可以通过右手定则来确定:将右手拇指
指向电流方向,右手其它手指
就会沿着磁场的方向进行弯曲:
注意:电流是单位时间内通过导体某个横截面的电荷量,而电压是电路中自由电荷定向移动形成电流的原因。物理上规定电流的方向是正电荷定向运动的方向,该方向与电子的运动方向相反。
导体的价带上面电子非常松散,绝缘体的价带则几乎被电子填满,而硅、锗等元素的价带正好只被电子填充了一半,二者都有4 个价电子位于能够容纳 8个电子的能带之上,这些元素就被称为半导体。
锑
、砷
、磷
等少量价带上只存在5个电子的元素添加到硅和锗当中,就会产生多余的电子,称为N 掺杂(N 表示 Negative 负),进而得到N 型半导体;直流 DC是沿着一个方向运动的电流,但是直流并非恒流,其大小可以由电路来决定;而交流 AC 的方向随着时间呈周期性变化。
阶跃函数是一种特殊的连续时间函数,表达的是从0
到 1
的跳变过程,属于奇异函数。电路分析当中,阶跃函数是研究动态电路阶跃响应的基础。电流或者电压从一个量值变换为另外一个量值的过程,被称作阶跃函数变化,下图展示了一个从低值到高值变化的阶跃函数:
方波是交流电的一种特殊形式,是一种规则的、重复的阶跃变化:
脉冲波看起来像是丢失了部分波形的方波,或者是一种占空比非常低的方波:
瞬态表示的是两种相邻稳定状态之间变化的物理量,例如下图表示的是由电容器上电压
的阶跃变化(上方曲线),所引起的流进电容器的瞬态电流
(下方曲线)变化:
正弦波
和余弦波
都属于三角函数波形,其它复杂波形到三角函数波形的转换都是通过傅里叶定理完成:任何信号曲线,都可以通过足够数量,具有不同频率(谐波)与相移的三角函数波形叠加而成。
利用傅里叶变换,可以将一个方波表示为余弦波的无穷级数:
\[Square(\theta) = \cos(\theta) - \frac{\cos(3 \theta)}{3} + \frac{\cos(5\theta)}{5} - \frac{\cos(7 \theta)}{7} + ...\]
上述傅里叶级数中的每一项都代表着一个基波频率为 \(\theta\)的谐波,当使用余弦函数表示方波时,其中只会包含奇次谐波。下图通过多个谐波来表示一个方波,其中的谐波项越多,波形就会越接近方波:
当傅里叶级数的谐波项达到 101
次的时候,波形就已经非常接近于一个标准的方波:
任何波形都可以分解为一系列正弦谐波项,每个谐波项都可以进行单独分析,然后再将结果叠加就可以确定电路的响应。如下分别是锯齿波
、三角波
、脉冲波
三种常见复杂波形的傅里叶级数:
相对介电常数 \(\epsilon_\tau\)表达的是材料存储电荷的能力,某种物质当中电磁场的传播速度等于光速
除以该物质相对介电常数
的平方根:
\[信号传播速度 = \frac{11.8}{\sqrt{\epsilon_\tau}} 英寸/纳秒\]
设计高速电路板时,通常会存在如下几种常见的走线形式:微带线 a
、嵌入式微带线 b
、带状线 c
、双带状线 d
、不对称带状线 e
,其中微带线当中信号的传播速度相对要快于带状线。
电路能够容忍轻微的信号时序差异,但是如果时序的差异过大,就容易发生采样错误。例如下图中间部分的信号,相对其它信号出现了严重的不一致,导致系统时钟采样信号时发生了跳变:
注意:通过设置走线长度可以控制信号的时序,一些 EDA工具当中可以方便的设置蛇形走线来提供等长的布线。只要蛇形走线具有相应的参考层,并且仅局限于带状线信号层,则不会引发EMI 电磁干扰问题。
信号的频率可以采用三种方式进行描述:
Hz
,用符号 \(f\) 表示,上图波形频率为 3Hz,即 \(f=3\);360°
变化,那么 3 个周期内就会经历 \(360° \times 3 = 1080°\);1
弧度等于圆周上长度等于半径的弧所形成的角度,定义为1 rad
;圆的周长为 \(2 \pi r\),其中 \(r\) 为半径,则 360°
圆周的弧度值等于 \(\frac{周长}{半径} = \frac{2\pi r}{r} = 2 \pi\) 弧度。
因为 \(360°\) 是 \(2 \pi\) 弧度,所以正弦波在 1 秒内可以经过\(2 \pi f\)弧度,这就是电子学当中经常使用到的角频率 \(\omega\),表示的是正弦波在 1秒钟内经过的弧度数。
\[\omega = 2 \pi f\]
正弦波通常使用 \(\sin(2\pi ft)\)或者 \(\sin(\omega t)\)格式进行表示,这里的 \(2 \pi f\) 或者\(\omega\) 表示的是 1秒之内的周期数,\(t\)表示的是以秒为单位的时间变量。具有 \(\sin(n\omega t)\)波形的谐波信号,其频率是基波波形 \(\sin(\omega t)\) 的 n
倍,谐波频率与基波频率存在着简单的倍数关系。下图是某个信号的基波及其 4次谐波:
占空比是指信号处于高电平状态的时间百分比,下图分别表示的是50%
(左)和 25%
(右)占空比的方波信号:
频率是单位时间内电流方向循环改变的次数,但是频率并非高速电路设计当中的主要问题,信号的上升时间才是真正的麻烦所在。下图的正弦波与方波信号具有相同的频率,但是它们的上升时间并不相同:
信号的上升时间是指从波形 10%
位置上升至90%
位置所需要的时间长度,而下降时间则是从信号90%
位置下降至 10%
位置所需的时间长度:
如果电路当中信号变化速度较快,例如电流在 1
纳秒内从0 mA
变化到 10 mA
,则可以将其表示为电流变化量\(\Delta i\) 除以时间变化量 \(\Delta t\),当此处的 \(\Delta t\)小到可以忽略的时候,就可以得到其微分形式 \(\frac{di}{dt}\),这就是信号完整性问题产生的原因所在。在高速电路当中,\(dt\)项可以等同于信号的上升或者下降时间。
频率与周期的关系为 \(频率 =\frac{1}{周期}\),例如具有 1MHz
频率的正弦波周期为百万分之一秒,即 1us
或者1000ns
。
电子学当中的相位通常是指三角函数波形,两个三角函数波形之间的时间差称为相移。如果两个三角函数波形的波峰位于相同的时间点,则认为两者的相位完全相同,称为同相(下图左侧),否则称为不同相(下图右侧);
90°
;90°
;振幅是指振动的物理量可能达到的最大值,用于表示振动的范围和强度的物理量。
分贝(dB)是一种基于对数的比率度量单位,其结果与功率密切相关,对应的基本单位是贝尔,两者换算关系如下所示:
\[1 贝尔 = 10 分贝\]
1
贝尔被定义为功率 \(P_1\) 与 \(P_2\) 比值的对数:
\[1 贝尔 = log(\frac{P_2}{P_1})\implies1 分贝 = \frac{1}{10} 贝尔 = log(\frac{P_2}{P_1}) \cdot \frac{1}{10}\]
时间常数表示物理量从最大值衰减到最大值的 \(\frac{1}{e}\)时所需要的时间,该参数在电子学当中与波形发生改变的时间长度有关,即一个波形变化占据全部波形变化的比例。
由于温度引起电子运动而发出的信号,称为热噪声。由于似乎是由所有频率的信号构成,如同白色光线由所有颜色构成一样,所以也被称为白噪声。通常情况下,信号比噪声更大,可以通过信噪比对两者进行比较。
电流必须在一个闭合的回路当中进行流动,电流在该回路当中必须处处恒定。
上面电路当中存在 a
、b
、c
三个回路,基于欧姆定律可以分别得到:
\[\begin{cases}i_1 = \frac{V}{R_1} = \frac{10}{1000} = 10mA \\i_2 = \frac{V}{R_2} = \frac{10}{5000} = 2mA\end{cases}\impliesi = i_1 + i_2 = 12mA\]
欧姆定律:电压 V(单位为伏V)等于电流 I(单位为安 I)乘以电阻R(单位为欧姆 Ω):
\[电压 V = 电流 I \times 电阻 R\]
注意:欧姆定律作为点概念,适用于电路某个时间的某个特定点。
基尔霍夫电流定律:流入某个结点的电流必须等于流出该结点的电流:
流入上部结点的电流为 \(i\),流过电阻\(R_1\) 的电流为 \(i_1\),流过电阻 \(R_2\) 的电流为 \(i_2\),根据基尔霍夫电流定律可以得到 \(i = i_1 +i_2\)。根据欧姆定律和基尔霍夫电流定律,可以推导出n
个电阻并联的等效电阻\(R_{eq}\) 求解公式:
\[\begin{cases}i_1 = \frac{V}{R_1} \\i_2 = \frac{V}{R_2} \\i = \frac{V}{R_{eq}} \\\end{cases}\implies\frac{V}{R_{eq}} = \frac{V}{R_1} + \frac{V}{R_2}\implies\frac{1}{R_{eq}} = \frac{1}{R_1} + \frac{1}{R_2}\impliesR_{eq} = \frac{1}{\frac{1}{R_1} + \frac{1}{R_2}} = \frac{R_1 R_2}{R_1 +R_2}\impliesR_{eq} = \frac{R_1 R_2 ... R_n}{R_1 + R_2 ... R_n}\]
基尔霍夫电压定律:一个回路上的电压之和必然等于零;
将顺时针作为上图电路的参考方向,电阻 \(R_1\) 上的电压降为 \(V_1\),而电阻 \(R_2\) 上的电压降为 \(V_2\),电压源上的电压为 \(-V\),根据基尔霍夫电压定律就可以得到 \(V_1 + V_2 +(-V) =0\)。结合欧姆定律和基尔霍夫电压定律,同样可以推导出n
个电阻串联的等效电阻\(R_{eq}\) 的求解公式:
\[V_1 + V_2 +(-V) = 0 \implies V = V_1 + V_2\implies\begin{cases}V_1 = i R_1 \\V_2 = i R_2 \\V = R_{eq}\end{cases}\impliesiR_{eq} = i R_1 + i R_2 \implies R_{eq} = R_1 + R_2\impliesR_{eq} = R_1 + R_2 ... R_3\]
导体材料对于电流的阻力称为电阻率,例如铜在20°C
室温下的电阻率为 \(1.724 \muΩ \cdotcm\)。将电阻率除上材料的横截面积,就可以得到单位长度材料的电阻:
\[R = \frac{电阻率 \rho}{横截面积 A}\]
PCB 铜泊走线宽度 10mil
,厚度0.65mil
,则横截面积 \(10mil\times 0.65mil =6.5 mil^2 = 0.000419354cm^2\),将铜的电阻率代入上面公式,就可以得到每厘米走线长度的电阻\(R\) :
\[R = \frac{1.724}{0.000419354} = 4114 \mu Ω/cm\]
注意:焊锡的电阻率是铜的
10~15
倍,因此焊接时需要保持铜质导线之间拥有足够的接触面积。
电阻与电流、电压的关系遵循着欧姆定律 \(R=\frac{V}{I}\),除此之外,电阻还会受到信号频率的影响:
电阻的所有频率效应都是由寄生的电感与电容所引起的,并非电阻的性质,电阻本身是独立于频率的,任何在频率范围内绘制成直线的阻抗曲线都表示的是纯电阻:
对于交流的电压信号,通过电阻的电流与电压是完全相同的相位,下图是通过电阻的电流信号(上)与电压信号(下)的相位。
电路当中两个电阻 \(R_1\) 和 \(R_2\) 串联的等效电阻 \(R_{eq}\) 等于 \(R_{eq} = R_1 + R_2\):
电路当中两个电阻 \(R_1\) 和 \(R_2\) 并联的等效电阻 \(R_{eq}\) 等于 \(R_{eq} = \frac{R_1 R_2}{R_1 + R_2}\):
功率与能量是密切相关的两个概念,其中功率是做功的速率,而能量是功率经过一段时间之后积累的结果。电子学当中的功率可以通过电压
乘以电流
求解得到:
\[功率 P = 电压 V \times 电流 I\]
结合欧姆定律,还可以得到如下的功率计算公式:
\[\begin{aligned}功率 P &= \frac{电压 V^2}{电阻 R} \\功率 P &= 电流 I^2 \times R\end{aligned}\]
当电流经过电阻时,将会消耗 \(I^2 R\)的功率,这些消耗的功率会以电阻发热的形式体现,这也正是PCB 走线容易发热的原因所在。
任何电源都可以等效为开路电压 \(E\) 与输出阻抗 \(R_S\) 的串联,而 \(R_L\)为负载电阻,此时电路所消耗的总功率等于\(I^2 R_S + I^2R_L\)。当负载电阻 \(R_L\) 等于输出阻抗 \(R_S\)时,负载可以从信号源获得最大的输出功率,即阻抗匹配。
首先,将两个电阻 \(R_1\) 和 \(R_2\) 串联在一起;然后,将电压 \(E\)添加在串联电阻的两端,此时两个电阻结合处的输出电压为 \(E_{out}\),该电路就称为电阻分压电路:
此时,输出电压 \(E_{out}\)与输入电压 \(E\) 的比值,等于输出端电阻\(R_2\) 与总电阻 \(R_1 + R_2\) 的比值:
\[\begin{cases}回路电流\ i = \frac{E}{R_1 + R_2} \\输出电压\ E_{out} = I \times R_2\end{cases}\implies\frac{E_{out}}{E} = \frac{R_2}{R_1 + R_2}\]
电容的单位是法拉
(F),当电容极板上 1库伦
电荷在极板之间产生 1伏特
的电压时,就称该电容为1F
:
\[电容\ C = \frac{电荷量\ Q}{电压\ V}\]
电子学术语当中,1F
法拉的电容值比较大,通常采用微法(\(\muF,10^{-6}F\))、纳法(\(nF,10^{-9}F\))、皮法(\(pF,10^{-12}F\))。电容极板上的电压会伴随充电时间的增加而变大:
\[\frac{dV}{dt} = \frac{i}{C}\]
最初时刻,电子开始流动到电容极板上,由于电容器一个极板的电子会显著多于另一个极板,导致电容极板之间存在着电荷差,进而产生电压;随着时间的推移,电容器极板之间的电压与驱动电压相同,此时将不会再有更多的电子在极板之间流动。
由于交流电流的极性反复在发生改变,电容器反复进行充放电,因而电流可以自由的进行流动。
交流电路当中,阻抗Z是电阻 R
与电抗 X
的总和,即 \(Z = R +jX\),而电抗是阻抗复数公式的虚数部分。电容与电感对于电流所起到的阻碍作用称作电抗,同样采用欧姆
作为计量单位,通常使用符号X
来表示。其中,电容的电抗称为容抗,表示为\(X_C\);而电感的电抗称为感抗,表示为\(X_L\);
流过电容器的电流大小,取决于电流的频率和电容的大小,并且能够引起电路电流与电压的相位变化。前面已经讨论过,角频率是正弦波在1 秒钟内所经过的弧度数,即 \(\omega = 2 \pif\),由此就可以推导得到容抗的公式:
\[X_c = -\frac{1}{\omega C} = - \frac{1}{2\pi f C}\]
注意:上面容抗公式中出现的负号,表示通过电容器的电压发生了
-90°
的相移。
欧姆定律同样适用于电抗 \(电压 V = 电流 I \cdot 容抗X_C\),其中电压的单位为伏特V
,电流的单位为安培A
,容抗的单位为欧姆 Ω
。
下图为 0.01 uF
电容器的容抗与频率关系曲线,观察可以发现,当频率较高时,电容的容抗比较小;而当频率较低时,电容的容抗比较大;
流过的电流曲线为三角波,此时的输出电压曲线为方波:
流过电流曲线为正弦波,则此时的输出电压曲线为滞后于电流90°
的正弦波:
电容的串并联关系与电阻正好相反,电容\(C_1\) 和 \(C_2\) 串联之后的等效电容为\(C = \frac{C_1 \cdot C_2}{C_1 +C_2}\):
而 \(C_1\) 和 \(C_2\)电容并联后的等效电容为 \(C =C_1 + C_2\):
电磁感应现象是指因磁通量变化而产生感应电动势的现象,例如:闭合电路的一部分导体在磁场里做切割磁感线运动时,导体中就会产生感应电流和感应电压。法拉第电磁感应定律是指电路当中感应电压\(\epsilon\)与穿过该电路的磁通变化率\(\varPhi\) 呈正比:
\[感应电压\ \epsilon = \frac{\Delta \varPhi}{\Delta t}\]
电感的单位是亨利 H
,常用的单位有毫亨mH
、微亨 uH
、纳亨 nH
。当流过1H
亨利电感器的电流,以 1A
安培每秒的速度进行变化时,就会产生 1V
伏特的电压:
\[电感\ L = \frac{电压\ V}{电流变化量\ di / 时间变化量\ dt}\]
直流信号通过电感器时,不会产生反向的感生电流,所以理想电感器对于直流不会产生阻抗:
交流信号通过电感器时,变化的磁场会产生出反向的感生电流,会阻止电感器的导通:
注意:信号频率越高,电感器对于交流信号的阻抗就越大。
当线圈中有电流通过时,就会在线圈中形成感应电磁场,而感应电磁场导致线圈当中产生感应电流,从而抵制通过线圈的电流,这种电流与线圈之间的相互作用称为感抗,采用符号\(X_L\)进行表示。感抗的大小取决于电感量的大小以及通过信号的频率:
\[X_L = \omega L \xrightarrow{\omega = 2 \pi f} X_L = 2 \pi f L\]
欧姆定律同样适用于电感,通过电感的电压 \(V\)(伏特 V
)等于电流 \(I\)(安培 A
)乘以感抗 \(X_L\)(欧姆 Ω
):
\[V = I \cdot X_L\]
当频率较低时,感抗较小;而当频率较高时,则感抗将会增大,即感抗伴随着频率的升高而增大:
当经过电感的电流为三角波,则电感两端的电压呈现为方波:
当流经电感的电流为正弦波,则电感两端的电压曲线为超前于电流曲线90°
的正弦波:
电感的串并联关系与电阻完全相同,电感\(L_1\) 和 \(L_2\) 串联之后的等效电感为 \(L_{eq} = L_1 + L_2\):
而 \(L_1\) 与 \(L_2\) 并联之后的等效电感为 \(L_{eq} = \frac{L_1 \cdot L_2}{L_1 +L_2}\):
恒定的电流会在导体截面均匀分布,而交变电流会让导体出现自感电动势,从而抵抗电流的通过,该电动势的大小正比于导体单位时间所切割的磁通量。
以圆形截面的导体为例,越靠近导体的中心位置,所受到自感电动势的影响就越大;而越靠近导线表面的位置,所受到自感电动势的影响就越小,进而导致趋近导体表面处的电流密度较大(上图阴影的深浅就就体现了电流密度)。
注意:由于自感电动势会随着频率的提高而增加,所以趋肤效应也会随频率的提高而增强,造成导体当中通过电流的有效截面积减小,电阻增大。
对于包含电容
、电感
、电阻
元件的无源一端口网络,其端口可能会呈现出容性、感性、阻性,当电路端口的电压\(U\) 和电流 \(I\)出现相同的相位,电路呈现阻性时,就称为谐振现象,这样的电路就称为谐振电路。
对于一个由电感 \(L\) 与电容 \(C\) 串联起来组成的电路:
这个电路的总电抗可以通过 \(X_{总} = X_C +X_L\) 计算得到:
\[X_{总} = X_C + X_L\implies\begin{cases}X_C = - \frac{1}{\omega C} = -\frac{1}{2 \pi f C} \\X_L = \omega L = 2 \pi f L\end{cases}\impliesX_{总} = X_C + X_L = -\frac{1}{\omega C} + \omega L\]
此时如果 \(\frac{1}{\omega C} = \omegaL\),就可以推导得到:
\[\omega = \frac{1}{\sqrt{LC}} = 2 \pi f\]
当电容值为 0.01uF
,而电感值为 10nH
时,代入上面方程可以求解得到频率 \(f\)的值为 16MHz
,即通过频率为 16MHz
的信号时,这个 LC 串联电路的阻抗等于零:
\[f = \frac{1}{2 \pi \sqrt{LC}} = \frac{1}{2\pi \sqrt{0.01\times10^{-6}\times 10 \times^{-9}}} = 16MHz\]
下图左右两侧曲线,分别为感抗和容抗曲线,两者相交于16MHz
位置,由于两者的符号相反,所以正好完全抵消,电抗急剧下降到零:
由电感
和电容
组成的串联电路,当容抗 \(X_C\) 与感抗 \(X_L\)相等时,电路当中电压与电流的相位相同,电路总体呈现阻性,这种现象就称为串联谐振。此时,电路的总阻抗最小,电流将会达到最大值,电感和电容上会产生高于电源许多倍的电压,因而也被称为电压谐振。此时,容抗\(X_C\) 与感抗 \(X_L\)相等时的频率点,就称为谐振点。
相应的,电感与电容并联之后的电抗与电阻的并联相类似:
此时该电路的总电抗 \(X_{总}\) 可以通过下面的过程推导得到:
\[X_{总} = \frac{1}{\frac{1}{X_L} + \frac{1}{X_C}} =\frac{1}{\frac{L}{\omega L} - \omega C} = \frac{\omega L}{1 - \omega^2LC}\]
此时,当并联的电容值为 0.01uF
,而电感值为10nH
时,谐振点依然为16MHz
,但是在此时电抗将会趋于无穷大:
由电感
与电容
组成的并联电路当中,当电容的容值使得电路上的电压
与电流
处于相同的相位,电源提供的电能全部被电阻所消耗,成为电阻电路时,就被称为并联谐振。此时电路的总阻抗最大,而总电流最小,但是支路的电流可能大于总电流,因而并联谐振也被称作电流谐振。
阻抗是电阻和电抗共同作用的结果,通常使用字母Z
来进行表示,其复数表达式为:
\[Z = R + jX\]
上面方程当中的 \(R\)表示电阻分量,\(X\)表示电抗分量,而 \(j\)的值为 \(\sqrt{-1}\)称为虚数单位。
阻抗是通过从原点指向电阻
\(R\) 与电抗
\(X\) 交点的向量来进行表示的。
上图坐标轴当中的原点、\(X\)轴、\(R\)轴构成了一个直角三角形,根据三角函数的关系可以得到:
\[Z = \sqrt{R^2 + X^2}\]
例如在下面电路当中,\(100Ω\) 电阻与\(0.02 \mu F\) 电容串联在一起:
如果此时频率 \(\omega =10^6\),从而可以得到如下推导过程:
\[\begin{cases}R = 100Ω \\X_C = -\frac{1}{\omega \times 0.02 \times 10^{-6}}\end{cases}\implies\begin{cases}R = 100Ω \\X_C = -\frac{1}{10^6 \times 0.02 \times 10^{-6}}\end{cases}\implies\begin{cases}R = 100Ω \\X_C = -50Ω\end{cases}\]
根据上面的推导结果,就可以将上面电路的阻抗关系绘制到如下坐标轴上:
根据上述阻抗向量公式,可以得到该电路的阻抗为 \(Z = \sqrt{100^2 + (-50)^2} =111.8\)。此时,如果将频率改变为 \(\omega = 10^7\),则会使得容抗 \(X_C = -\frac{1}{10^7 \times 0.02 \times 10^{-6}} =-5Ω\),此时该电路的阻抗应为:
\[\begin{cases}R = 100Ω \\X_C = -5Ω\end{cases}\impliesZ = \sqrt{100^2 + (-5)^2} = 100.1\]
由此,就可以得到频率为 \(\omega =10^7\) 时,串联 \(100Ω\) 电阻与\(0.02 \mu F\) 电容的阻抗图:
可以看到,高频状态下的容抗值会比较小,决定阻抗值大小的主要是串联的电阻。
阻抗的相位角就是下图当中的 \(\theta\) 角,是阻抗向量与 \(R\)横轴之间的夹角。如果这个角为负
(阻抗向量指向下方),那么该电路是容性。如果这个角为正
(阻抗向量指向上方),那么该电路为感性。
阻抗的相位角存在着 3 种特殊情形:
+90°
:阻抗向量与 X
轴正半轴重合,电路表现为纯感性;-90°
:阻抗向量与 X
轴正半轴重合,电路表现为纯容性;0°
:阻抗向量与 R
轴重合,电路表现为纯阻性;结合三角函数的知识,角 \(\theta\)的正切是对边
与邻边
的比值,由此可以知道角 \(\theta\)等于对边
与邻边
比值的反正切:
\[\tan(\theta) = \frac{X}{R}\implies\theta = \tan^{-1}(\frac{X}{R})\]
对于前述的示例电路,可以计算得到如下结果:
\[\begin{cases}当 \omega = 10^6 时:\tan^{-1}(\frac{-50}{100}) = \tan^{-1}(-0.5) =-26.6° \\当 \omega = 10^7 时:\tan^{-1}(\frac{-5}{100}) = \tan^{-1}(-0.05) =-2.9°\end{cases}\]
阻抗的相位角代表了该电路电压
与电流
之间的相位差,相位角为负则表示当前电路的电压滞后于电流的相位,当频率增加之后,由于高频信号的电容效应会下降,电压相位的滞后程度也会减少。
下图是频率为 \(\omega = 10^6\)时,电路当中各处电压的波形:
下图是频率为 \(\omega = 10^7\)时,电路当中各处电压的波形:
分析上述两组图形,可以得出如下三点结论:
90°
度;26.6°
度;而当频率等于 \(\omega = 10^7\)时,总电压 \(V_{Total}\) 仅滞后于电流2.9°
度;对于下面这个仅由电阻
、电感
、电容
组成的简单RLC 电路:
列写感抗 \(X_L\)、容抗 \(X_C\)、总阻抗 \(X_{总}\) 的方程,联立之后可以得到:
\[\begin{cases}X_L = j \omega L \\X_C = \frac{1}{j \omega L} \\X_{总} = j \omega L + \frac{1}{j \omega L}\end{cases}\implies\begin{cases}X_L = j \omega L \\X_C = -\frac{j}{j \omega C} \\X_{总} = j(\omega L - \frac{1}{\omega C})\end{cases}\impliesZ = R + j(\omega L - \frac{1}{\omega C})\]
假设电阻 \(R = 10 Ω\)、电感 \(L = 10 nH\)、电容 \(C = 0.01 \mu F\)、频率 \(\omega =10^7\),根据上述的推导结果可以得到:
\[\begin{cases}R = 10 Ω \\L = 10 nH \\C = 0.01 \mu F \\\omega = 10^7\end{cases}\impliesZ = 10 - j9.9\]
根据前面得到的阻抗 \(Z = \sqrt{R^2 +X^2}\) 与阻抗角 \(\theta =tan^{-1}(\frac{X}{R})\) 公式,还可以推导得到:
\[\begin{cases}Z = 14.0716Ω \\\theta = -44.712°\end{cases}\]
如果此时将频率提高至 \(\omega =10^8\),就会推导得到:
\[\begin{cases}Z = 10Ω \\\theta = 0°\end{cases}\]
已知频率 \(\omega = 2 \pif\),由于此时 \(\omega =10^8\),所以频率 \(f = \frac{10^8}{2\pi} = 16MHz\),这与之前讨论过的 LC电路的谐振频率相同,从而可以得到如下结论:
0°
;下图左侧是上述串联 RLC电路的阻抗与频率的关系,而右侧体现的则是相移与频率的关系:
分析上述图像还可以得到如下两个结论:
谐振频率
位置的阻抗最小,相移为零;分析电阻与电抗电路当中的电压电流,需要处理一些涉及到相移的微妙问题。当频率\(\omega = 10^7\) 时,阻抗 \(Z = 14.0716Ω\),阻抗的相位角 \(\theta = -44.712°\)。这里从相移为0°
的正弦波电压开始分析,先使得最大电压等于10V
,这样就可以得到此时的总电压 \(V_总 = 10\sin(\theta)\),再结合欧姆定律就可以得到:
\[I = \frac{V}{Z} = 0.71065 \sin(\theta + 44.712)\]
由于该电路为容性,电流超前于电压,电压的相移为负,所以\(\theta\)的正弦函数为正。该电路上电感、电阻、电容三个元件上的电压分别等于电流乘以它们各自的电阻或者电抗:
\[\begin{cases}V_R = I \times R = 7.1061 \sin(\theta + 44.712) \\V_L = I \times X_L = 0.07106 \{sin(\theta + 134.712)\} \\V_C = \frac{I}{X_C} = 7.1061 \{sin(\theta - 45.288)\}\end{cases}\]
下图绘制了包括上述 \(V_总\)、\(V_R\)、\(V_L\)、\(V_C\)四个波形在两个周期内的时序关系,注意它们之间的相位关系:
电阻
、电容
、电感
、变压器
在内的基本元器件;接下来介绍了半导体电子技术,并且详细分析了二极管
、晶体管
、晶闸管
等半导体元件的性能与参数,以及运算放大器
、滤波电路
、振荡电路
、定时器
、稳压电路与电源
等经典的模拟电路。最后介绍了数字电子技术相关的内容,从基本的逻辑门
电路入手,重点讨论了组合逻辑电路和时序逻辑电路,以及相关的触发器
,寄存器
、计数器
、缓冲器
、锁存器
、收发器
,乃至于存储器与微控制器。除此之外,该书还简单介绍了线性函数、二次函数、指数/对数函数、三角函数、复数、微积分等数学预备知识。电子元器件的选型与运用是硬件工程师日常工作当中最为主要的内容,希望本篇文章能够对广大电子爱好者有所帮助。
本章节内容主要用于归纳电子技术相关的常用数学基础知识。
英文 | 大写 | 小写 | 音标 | 英文 | 大写 | 小写 | 音标 |
---|---|---|---|---|---|---|---|
Alpha | Α | α | /ˈælfə/ | Beta | Β | β | /ˈbetə/ |
Gamma | Γ | γ | /ˈɡæmə/ | Delta | ∆ | δ | /ˈdeltə/ |
Epsilon | Ε | ε | /ˈepsɪlɑːn/ | Zeta | Ζ | ζ | /ˈzeɪtə/ |
Eta | Ε | η | /ˈiːtə/ | Theta | Θ | θ | /ˈθeɪtə/ |
Iota | Ι | ι | /aɪˈoʊtə/ | Kappa | Κ | κ | /ˈkæpə/ |
Lambda | Λ | λ | /ˈlæmdə/ | Mu | Μ | µ | /mjuː/ |
Nu | Ν | ν | /njuː/ | Xi | Ξ | ξ | /ksaɪ/ |
Omicron | Ο | ο | /ˈɑːməkrɑːn/ | Pi | Π | π | /paɪ/ |
Rho | Ρ | ρ | /rəʊ/ | Sigma | Σ | σ | /ˈsɪɡmə/ |
Tau | Τ | τ | /tɔːˌtaʊ/ | Upsilon | Υ | υ | /ˈʊpsɪlɑːn/ |
Phi | Φ | φ | Phi | Chi | Χ | χ | /kaɪ/ |
Psi | Ψ | ψ | /psaɪ/ | Omega | Ω | ω | /oʊˈmeɡə/ |
单位前缀 | 符号 | 乘方 | 音标 | 单位前缀 | 符号 | 乘方 | 音标 |
---|---|---|---|---|---|---|---|
tera | T | \(×10^{12}\) | /ˈterə/ | milli | m | \(×10^{−3}\) | /ˈmɪli/ |
giga | G | \(×10^9\) | /ˈɡɪɡə/ | micro | µ | \(×10^{−6}\) | micro |
mega | M | \(×10^6\) | /ˈmeɡə/ | nano | n | \(×10^{−9}\) | /ˈnænoʊ/ |
kilo | k | \(×10^3\) | /ˈkilo/ | pico | p | \(×10^{−12}\) | /ˈpiːkoʊ/ |
centi | c | \(×10^{−2}\) | /ˈsentɪ/ | - | - | - | - |
线性函数 \(y = mx +b\) 会在坐标轴上绘制出一条直线,这条直线的斜率\(\frac{\Delta y}{\Delta x}\) 等于\(m\),垂直截距等于 \(b\):
二次函数 \(y = ax^2 + bx +c\)会在坐标轴上绘制出一条抛物线,这条抛物线的大小受到\(\alpha\) 值的影响,其横坐标为 \(-\frac{b}{2a}\),而纵坐标为 \(-\frac{b^2}{a+c}\),方程的根位于抛物线与横轴的交点,可以通过公式\(x = \frac{-b \pm \sqrt{b^2 -4ac}}{2a}\) 计算得到:
形如 \(y=a^x(a>0,且a \neq 1)\)的函数称为指数函数,其中的 \(x\) 为自变量,函数的定义域为 \(R\)。
\(x^0 =1\) | \(\frac{1}{x^n} = x^{-n}\) | \(x^{1/n} =\sqrt[n]{x}\) | \(x^m \cdotx^n = x^{m+n}\) | \((xy)^n = x^n\cdot y^n\) | \((x^n)^m =x^{n \cdot m}\) |
---|
如果 \(a^y = x(a>0,且 a \neq1)\),那么 \(y\) 就叫做以 \(a\) 为底 \(N\) 的对数,记作 \(y = log_a x\),其中 \(a\) 称为对数的底数,而\(x\) 称为真数。
10
为底的对数 \(\log_{10} x\) 记为 \(\lg x\);2.71828...
作为底数的对数 \(\log_e x\) 记为 \(\ln x\);根据对数的定义,就可以得到对数与指数之间的关系:\(a^y = x(当 a>0 且 a \neq 1 时)\iff y = \log_ax\)。
\(\log_b 1 =0\) | \(\log_b b =1\) | \(\log_b 0 =\begin{cases} +\infty b < 1 \\ -\infty b > 1\end{cases}\) |
---|---|---|
\(\log_b(x\cdot y) = \log_b x + \log_b y\) | \(\log_b(\frac{x}{y}) = \log_b x - \log_by\) | \(\log_b (x^y)= y \log_b x\) |
对于半径为 \(R\) 的圆形,弧长 \(S\) 所对应的圆心角弧度 \(\theta = \frac{弧长 S}{半径 R}\),此时\(1 弧度 = \frac{180°}{\pi} =57.296°\),而 \(1° = \frac{\pi}{180°} =0.17453 弧度\):
当半径 \(R\) 从 \(x\)正半轴开始逆时针方向旋转时,\(\theta\)为正角,而顺时针方向旋转时,\(\theta\) 为负角。
\(\sin \theta= \frac{y}{R}\) | \(\cos \theta= \frac{x}{R}\) | \(\tan \theta= \frac{y}{x}\) | \(\cot \theta= \frac{x}{y} = \frac{1}{tan \theta}\) | \(\sec \theta= \frac{R}{x} = \frac{1}{\cos \theta}\) | \(\csc \theta= \frac{R}{y} = \frac{1}{\sin \theta}\) |
---|
下图为正弦函数曲线 \(y = A\sin\theta\),为了方便改变函数的垂直水平位置
、周期
、相位
,可以将其改写为\(y = A \sin(Bx + C) + D\) 的形式,其中\(A\) 表示幅值,而\(2 \pi / B\) 表示周期\(T\),\(C\) 表示相移,\(D\) 表示垂直位移。
电子学当中,可以将电压表示为 \(V(t) = V_0\sin(\omega t + \varPhi) + V_{dc}\),其中 \(V_0\) 为峰值电压,\(V_{dc}\) 为直流分量,\(\varPhi\) 为相移,\(\omega\) 为角频率 \(rad/s\)。除此之外,余弦函数曲线\(y = A \cos \theta\) 与 \(y = A \sin \theta\) 相差了 \(\frac{\pi}{2}\) 幅度或者 \(90°\) 度相移:
正弦函数与余弦函数之间的关系如下面表格所示:
\(\sin(\frac{\pi}{2} \pm x) = + \cos x\) 或者\(\sin(90° \pm x) = + \cos x\) | \(\cos(\frac{\pi}{2} \pm x) = \pm \sin x\)或者 \(\cos(90° \pm x) = \pm \sinx\) |
---|---|
\(\sin(\frac{3\pi}{2} \pm x) = - \cos x\)或者 \(\sin(270° \pm x) = - \cosx\) | \(\cos(\frac{3\pi}{2} \pm x) = \pm \sin x\)或者 \(\cos(270° \pm x) = \pm \sinx\) |
斜率反映了直线相对于水平面的倾斜度,一条直线与某平面直角坐标系横坐标轴的正半轴所形成角的正切值,就等于该直线的斜率。
\[直线的斜率 = \frac{直线某点在\ y\ 轴的变化量\ \Delta y}{直线某点在\ x\轴的变化量\ \Delta x}\]
假设函数 \(f(x)\)的图形为一条曲线,此时存在着一个点沿着这条曲线移动,经过该点绘制切线,当该点沿着曲线运动时,切线的斜率不断发生变化。实际生活当中,切线的斜率有着极为重要的意义,例如:
微分学作为作为计算斜率的途径之一,可以用于计算曲线上任意一点位置的切线斜率。例如函数\(y = x^2\),通过微分计算可以得到 \(y\) 的导数 \(y' = \frac{dy}{dx} =2x\),通过它可以获得曲线 \(y\)上任意一点位置的斜率。如果此时需要求解 \(x =2\) 位置的斜率,将 \(x = 2\)代入至 \(\frac{dy}{dx}\)表达式,就可以得到斜率等于 \(4\)。
当计算某个函数的导数时,假设 \(P(x,y)\) 为曲线 \(y = f(x)\)上面的一点,而 \(Q(x + \Delta x, y + \Deltay)\) 为曲线上的另外一点,此时 \(P\) 点与 \(Q\) 点之间的直线斜率为 \(\frac{f(x + \Delta x) - f(x)}{\Deltax}\):
将具体函数代入上面等式,例如对于函数 \(f(x)= x^2\),那么 \(f(x + \Delta x) = (x +\Delta x)^2\),此时完整的表达式可以记为 \(\frac{[(x + \Delta x)^2 - x^2]}{\Deltax}\)。接下来固定 \(x\) 的值,令\(\Delta x\) 趋近于0
,如果斜率趋近于某一个只依赖于 \(x\) 的值,则称该值为曲线在 \(P\) 点处的斜率。
曲线在 \(P\) 点位置的斜率是一个关于\(x\) 的函数,定义域为极限里存在的每个\(x\) 值,那么斜率就可以表示为 \(f'(x)\)、\(\frac{dy}{dx}\)、\(\frac{df}{dx}\)三种形式,这三种表达方式均称为 \(f(x)\)的导数:
\[f'(x) = \frac{dy}{dx} = \lim_{\Delta x \rightarrow 0} \frac{f(x +\Delta x) - f(x)}{\Delta x}\]
对于上述示例当中的函数 \(f(x) =x^2\),求取极限之后,可以得到其导数为 \(f'(x) = \frac{dy}{dx} =2x\)。实际计算当中,使用上述极限公式计算较为繁琐,通常会直接应用下面表格当中的求导法则与函数导数:
\(\frac{d}{dx}a = 0\) | \(\frac{d}{dx}x^n = nx^{n - 1}\) | \(\frac{d}{dx}e^x = e^x\) | \(\frac{d}{dx}\ln x = \frac{1}{x}\) | \(\frac{d}{dx}\sin x = \cos x\) |
---|---|---|---|---|
\(\frac{d}{dx}\cos x = -\sin x\) | \(\frac{d}{dx}au(x) = a \frac{d}{dx} u(x)\) | \(\frac{d}{dx}(u + v) = \frac{du}{dx} +\frac{dv}{dx}\) | \(\frac{d}{dx}\Bigl(\frac{u}{v}\Bigl) =\frac{v(du/dx) - u(dv/dx)}{v^2}\) | \(\frac{d}{dx}\left \lbrace u(v(x)) \right \rbrace = \frac{du}{dx} \cdot\frac{dv}{dx}\) |
注意:上面表格当中的 \(a\) 和 \(n\) 是常数,而 \(u\) 和 \(v\) 表示函数。
微分学的目标是寻找函数的导数,而积分学的任务则是寻找导数的原函数。通常约定\(y = f(x)\)形式为函数,而 \(\frac{dy}{dx} = \frac{df(x)}{dx}\)形式为导数,形如 \(\int dy =\int f(x)dx\) 的称为积分。其中,\(\int\) 称为积分符号,而\(f(x)\)称为被积函数,\(dx\)称为积分变量。实质上积分可以被视为一个求和计算的过程,例如求解下图以曲线作为边界的阴影区域面积:
已知等式 \(\frac{dy}{dx} =f(x)\),通过积分计算就可以得到 \(y\):
\[\frac{dy}{dx} = f(x) \implies \int dy = \int f(x)dx\xrightarrow{对等式两侧进行积分}y \pm C = \int f(x) dx \implies y = \int f(x) dx + C\]
最后推导出等式 \(\int dy = y \pmC\),通过逆运算可知任何 \(y \pmG\) 形式的函数,求导之后均等于 \(y\)。其中 \(C\) 的值可正可负,习惯上采用等号左侧加\(C\)的形式,这种形式的积分称为不定积分。例如已知 \(\frac{dy}{dx} =2\),可以通过如下推导过程求解得到 \(y\):
\[dy = 2dx \implies \int dy = \int 2dx \implies y = 2x + C\]
实际情况经常期望得到一个不包含常数的确定解,为了去掉常数项,就需要利用到边界条件。这里仍然以\(\frac{dy}{dx} = 2\) 为例,如果只关注\(\frac{dy}{dx}\) 在区间 \(1 \sim 5\)范围内的值,就可以利用定积分来进行计算:
\[y = \int^{b}_{a} f(x) dx = F(x) {\vert}^b_a = F(b) - F(a)\]
上面公式当中的 \(F\)代表不含积分常数的定积分,而 \(a\) 和 \(b\) 限定了 \(F\) 当中 \(x\)的取值区间,将已知条件代入方程可以得到:
\[y = \int^{5}_{1} 2dx = 2x {\vert}^5_1 = 2 \times 5 - 2 \times 1 = 8\]
对于更为复杂的函数,求解积分需要耗费较长时间推导其原函数。实际工作当中,更多会直接应用下面表格当中的积分公式进行分析讨论:
\(\int dx = x+ C\) | \(\int a f(x)dx = a \int f(x) dx\) | \(\int(du(x)\pm dv(x)) = \int du(x) \pm \int dv(x)\) | \(\int udv =uv - \int vdu\) |
---|---|---|---|
\(\int u^n du= \frac{u^{n+1}}{u+1} + C \ (n \neq 1)\) | \(\int\frac{1}{u} du = \ln u + C\) | \(\int \ln xdx= x \ln x - x + C\) | \(\int sin xdx= -cos x + C\) |
\(\int \cosxdx = \sin x + C\) | \(\int x \sinxdx = \sin x - x \cos x + C\) | \(\int x \cosxdx = \cos x + x \sin x + C\) | \(\sin x \cosx = \frac{1}{2} \sin^2 x + C\) |
\(\int e^u dx= e^u + C\) |
注意:上面表格当中的 \(u\) 和 \(v\) 分别表示 \(x\) 的函数。
利用复数及其对应的算术运算法则来模拟与求解正弦电路相关的问题,可以避免复杂的微分方程计算过程。复数\(z = a + ib\)主要由实部和虚部两部分所共同组成:
上面公式当中的 a
称为实部,b
称为虚部,i
称为虚数单位(\(i =\sqrt{-1}\))。电路分析当中,为了避免虚数单位i
与电流符号 \(i\) 相互混淆,而改用 j
来代替虚数单位i
。除此之外,复数还可以在采用直角坐标系上的图像(下图左侧)来进行表示,其中横轴表示实部a
,而纵轴表示虚部b
(下图右侧),即复数的直角坐标系形式:
注意:可以将直角坐标系里的复数视为一个由
0
指向P
点的矢量,对应的模值为 \(r = \sqrt{a^2 +b^2}\),其与正实轴之间的夹角 \(\theta = \arctan(\frac{b}{a})\)。
将复数用于电路分析,必须对其进行形式上的改变。将 a
更换为 \(r \cdot \cos \theta\),而b
更换为 \(r \cdot \sin\theta\),进而得到 \(z = r \cdot \cos\theta + j \times r \cdot \sin\theta\),这就是复数的三角形式:
复数的三角形式满足 \(e^{j \theta} = \cos\theta + j \sin \theta\) 的关系,首先分别对 \(e^{j \theta}\)、\(\cos \theta\)、\(j \sin \theta\) 取幂级数,然后将 \(\cos \theta\) 与 \(j \sin \theta\)的幂级数相加,最后就可以证明其结果与 \(e^{j\theta}\)的幂级数相等,从而就可以得到复数的指数形式:
\[z = r \cdot e^{j \theta}\]
上面的复数指数形式,还可以进一步简写为由矢量 \(r\) 与角度 \(\theta\)两部分组成的极坐标形式:
\[z = r \cdot \angle \theta\]
注意:复数的极坐标形式可以视为其指数形式的简写,相对而言,极坐标形式更为直观,计算起来也更加便捷。
终上所述,一共获得了复数的四种基本表示形式(标准形式
、直角坐标系形式
、三角形式
、指数形式
),每一种形式在电路分析当中都具有相应的特殊用途:
\[\begin{aligned}复数的直角坐标系形式:&z = a + ib \\复数的三角形式:&z = r \cdot \cos \theta + j \times r \cdot \sin\theta \\复数的极坐标形式:&z = r \cdot \angle \theta \\复数的指数形式:&z = r \cdot e^{j \theta}\end{aligned}\]
下图直观的展示了复数在各种形式之间的转换关系:
如下的表格,比较全面的总结了复数在各种形式下的加、减、乘、除四则运算法则:
而接下来的表格,展示了复数在计算过程当中,一些经常被使用到的关系方程式:
\(X(度) =\frac{180°}{\pi} X(弧度)\) | \(X(弧度) =\frac{\pi}{180°} X(度)\) | |||
---|---|---|---|---|
\(j =\sqrt{-1}\) | \(j^2 =-1\) | \(\frac{1}{j}= -j\) | \(\frac{1}{A +jB} = \frac{A - jB}{A^2 + B^2}\) | |
\(e^{j(0°)} =1\) | \(e^{j(90°)} =j\) | \(e^{j(180°)}= -1\) | \(e^{j(270°)}= -j\) | \(e^{j(360°)}= 1\) |
\(1 \angle 0°= 1\) | \(1 \angle 90°= j\) | \(1 \angle180° = -1\) | \(1 \angle270° = -j\) | \(1 \angle360° = 1\) |
\(Z^2 = (re^{j\theta})^2 = r^2 e^{j2 \theta}\) | \(Z^2 = (r\angle \theta)^2 = r^2 \angle 2 \theta\) |
注意:如果需要在电路分析过程当中进行复数运算,那么可以直接套用上述公式简化计算量。
▶【例题】应用复数的四则混合运算,求解下面复数的直角坐标形式与极坐标形式结果?
\[\frac{(2 + j5)+(3 - j10)}{(3 + j4)(2 + j8)}\]
◉【解】直接运用之前表格当中列出的关系式,就可以得到下面的推导过程:
\[\frac{(2 + j5)+(3 - j10)}{(3 + j4)(2 + j8)}\implies \frac{5 - j5}{(3 + j4)(2 + j8)}\implies \frac{7.07 \angle 45.0°}{(5 \angle 53.1°)(8.25 \angle 76.0°)}\implies \frac{7.07 \angle 45.0°}{41.25 \angle 129.1°}\implies 0.17 \angle - 84.1°\]
◉【解】上述步骤所获得的计算结果,可以按照题设要求转换为三角形式或者直角坐标形式:
\[0.17 \angle −84.1° = 0.17 \cos (−84.1°) + j0.17 \sin (−84.1°) = 0.017 −j0.17\]
注意:进行复数的除法或者乘法运算时,最佳实践是将复数转换为指数形式。而对于复数的加法与减法运算,最佳实践是将其转换为直角坐标系形式。
形如等式 \(|Z| = \sqrt{(R_e Z)^2 + (I_mZ)^2}\) 或者 \(arg(Z) =\arctan(\frac{I_m Z}{R_e Z}) = \tan^{-1} (\frac{I_m Z}{R_e Z})\)表示的依然是一个复数,该等式当中的 \(|Z|\)是复数的幅值或者模,\(I_m Z\) 是复数的虚部,而\(arg(Z)\) 表示的是 \(Z\) 的幅角或者 \(\theta\)相位角。如果按照这个对应规则,那么对于复数 \(Z = 3 + j4\) 而言:
\[\begin{cases}R_e Z = 3 \\I_m Z = 4 \\|Z| = \sqrt{(3)^2 + (4)^2} = 5 \\arg(Z) = \arctan(\frac{4}{3}) = 53.1°\end{cases}\]
注意:电路分析过程当中,引入复数的概念,可以有效简化交流电路的分析计算过程。
电流是单位时间内通过某一横截面 A的总电荷,这里的横截面可以理解为导体上的一个薄片:
如果在 \(\Delta t\)时间内,通过某一横截面的电荷量为 \(\DeltaQ\),那么就可以定义平均电流 \(I_{ave}\) 等于:
\[I_{ave} = \frac{\Delta Q}{\Delta t}\]
如果电流随着时间变化,那么可以定义 \(\Delta\rightarrow 0\)时的电流值为瞬时电流,即瞬时电流是电荷通过某一横截面的变化率:
\[I = \lim_{\Delta \rightarrow 0} \frac{\Delta Q}{\Delta t} =\frac{dQ}{dt}\]
电流的单位称为安培 A
,其值等于1C/s
库伦每秒,除此之外,常用的单位还有毫安、微安、纳安:
\[\begin{aligned}1A &= 1C/s \\1 mA &= 10^{-3}A \\1 \mu A &= 10^{-6}A \\1 nA &= 10^{-9}A \\\end{aligned}\]
电流是由导体内自由电子的定向移动而形成的,每个自由电子的电荷量为\(-1.602 \times 10^{-19}C\)。由于导体当中的质子与电子数量相等符号相反,因而整体呈现电中性:
\[\begin{cases}Q_{electron} &= -1.602 \times 10^{-19} C \\Q_{proton} &= +1.602 \times 10^{-19} C\end{cases}\]
最早富兰克林(Franklin)将正电荷运动的方向定义为电流方向,后来汤姆逊(Thomson)纠正了这一观点,认为负电荷(自由电子)运动的方向才是电流的方向,但是无论哪种方向,对于电路的分析计算结果都不会产生实质性影响。
电路两点之间存在电压才能够形成电流,导体两端的电压提供了推动导体当中自由电子运动的电动势(EMF,Electro-MotiveForce),电压有时候也被称为电势差或者电位,但是后者更偏向于相对位能的概念。
实质上,电压表示的是单位电荷在两点之间的位能差,是衡量电场力做功能力的物理量。如果两点之间的电压为1V
伏特,相当于将 1C
库仑的电荷从一点移动到另外一点所需要做的功为 1J
焦耳:
\[电压 V = \frac{功率 U}{电荷量 q}\implies1 V 伏特 = \frac{1 J 焦耳}{1 C 库仑}\]
电子学当中,通常会使用功率 \(P\)(每秒钟为电路提供的能量,单位为瓦特W
)来定义电压的单位伏特:
\[功率 P = 电压 V \times 电流 I \implies 1 V 伏特 = \frac{1 W 瓦特}{1 A安培}\]
欧姆定律是指物体两端的电阻 \(R\) 等于两端电压 \(V\) 与通过电流 \(I\) 之比,单位为欧姆Ω
,
\[电阻 R = \frac{电压 V}{电流 I} \implies 1 Ω 欧姆 = \frac{1 V 伏特}{1 A安培}\]
欧姆定律只适用于欧姆材料,即在所能承受的电压范围之内,该材料的电阻为一个常数。由于非欧姆材料的电阻不是常数,所以并不会遵循欧姆定律。
通常情况下,欧姆定律被写作 \(V = I \timesR\)的形式,即使用电阻与电流来定义电压。欧姆材料的电阻\(R\)与欧姆定律当中的电压 \(V\)无关。换而言之,就是不能使用电阻和电流来定义电压,而只能使用电压与电流来定义电阻。
电阻率 \(\rho\)反映了物体阻碍电流的能力,属于材料的固有特性,其单位为欧姆 \(\cdot\) 米(\(Ω \cdot m\))
\[电阻率 \rho = 电阻 R \frac{横截面积 A}{长度 L}\]
电导率 \(\sigma\)反映了物体通过电流的能力,同样也是材料的固有特性,其值等于电阻率的倒数,单位为西门子\(S = (Ω \cdot m)^{-1}\)
\[电导率 \sigma = \frac{1}{电阻率 \rho}\]
下面的表格里,分别列举出了一些常见材料的电阻率与电导率:
注意:大部分金属的电导率会随着温度的升高而增大,这是由于温度升高会导致材料晶格当中原子的振动,从而阻碍导体内部电子的漂移运动。
理想电阻的情况下,可以认为其全部功率都被转化为热能,将欧姆定律\(I = \frac{V}{R}\) 或者 \(V = IR\) 代入功率的表达式\(P = VI\)当中,就可以得到功率 \(P\)所消耗的热能,即欧姆热或者焦耳热:
\[\begin{aligned}功率 P = 电压 V \times 电流 I &= 电压 V \times \frac{电压 V}{电阻 R}= \frac{V^2}{R} \\功率 P = 电压 V \times 电流 I &= (电流 I \times 电阻 R) \times 电流I = I^2 \times R\end{aligned}\]
导线的尺寸可以使用导线规格来进行表示,国际上经常采用美国导线规格(AWG,AmericanWireGauge)作为通用标准,该标准下较小的规格数目对应着较大直径的导线:
下面的表格列举了铜导线的常见 AWG 规格,其中单位\(1 mil 密尔 = 0.0254mm 毫米\):
注意:圆密尔
CM
是一个面积单位,表示的是直径为1 mil
的圆面积。
通常会将电路当中的一点定义为 0V
参考点,并以此作为测量电路上其它各点电压的基准,该点通常被称为接地点或者电流返回端,采用下图符号进行表示:
注意:物理上的接地,是指将导体埋入大地\(8 英尺 = 2.4384 米\) 以上。
除此之外,为避免发生混淆,可以采用含义更为明确的大地、框架底座接地(功率接地)、模拟数字接地、电压参考点符号:
注意:除了作为零电压参考点使用之外,接地系统的另外一个重要作用是为无线电设备产生的杂散射频电流提供一条流入大地的低阻通路,称为射频接地。
较为复杂的 PCB设计当中,信号噪声产生的最普遍原因是由于没有良好的接地,如果将PCB线路当中的某些点作为接地点,那么接地线的内阻会导致这些接地点之间存在着电位差,从而形成糟糕的接地回路,导致电压读数产生误差。
下图给出了这个问题的说明,图中两个分离的底座接地,\(V_G\)表示信号接地端与负载接地端之间的电压,\(V_S\)为负载接地端与信号输出端之间的电压,此时会得到一个错误的电压 \(V_S + V_G\):
解决该问题的方法是采用下图所示的单点接地,即为了避免在电路当中产生接地回路,而将所有电路的接地端都连接至一个点:
理论上这是一个很棒的方法,但是由于 PCB电路的接地端数量通常会比较多,实际布线操作很难将其全部连接至一个点,替代的方法是采用接地母线,也就是采用较宽的铜制导线,以便承受回流至电源的全部负载电流。由于接地母线可以按需进行延长,所以布线时进行接地操作会较为方便:
PCB电路板通常会划分为模拟电路和数字电路两个部分,通常情况下会将两者分别进行接地处理,最后再将其接地点连接起来进行单点接地,作用是防止电路当中的接地回路产生电流噪声。
上述两种情况下,如果电流发生改变,则根据欧姆定律,接地回路上的阻抗电压也将会随之改变,从而导致系统参考点(通常选择在电源引出端)相对于接地面的电压也发生变化。接地回路上的阻抗由电阻
、容抗
、感抗
共同组成,其中电阻
与感抗
起到主要作用。
电阻
起到主要作用,并且产生一个直流偏置电压;电阻
、感抗
、容抗
,进而产生一个高频交流电压;上述两种情况下,局部电路的电压变化都会导致噪声的出现,而减少噪声的最好办法就是先将模拟接地和数字接地分开,最后再进行单接地点。
电路主要存在串联与并联两种基本连结方式,其中串联的负载具有分压的作用,而并联的负载具有分流的作用:
电阻可以限制电路当中电流的流动,或者是在电路两端形成电压,主要分为固定电阻与可变电阻两大类型,其电路表示符号如下所示:
如果在一个电阻的两端添加直流电压,那么运用欧姆定律就可以计算出经过这个电阻的电流:
\[电压 V = 电流 I \times 电阻 R\]
如果要计算出该电阻欧姆热所消耗的功率,可以将欧姆定律代入功率的计算公式:
\[功率损耗 P = 电流 I \times 电压 V = \frac{电压 V^2}{电阻 R} = I^2 R\]
注意:设计电路的时候,电阻的实际功率不能超过其最大额定功率,否则会损坏电阻。典型的电阻器额定功率值有
1/8W
、1/4W
、1/2W
、1W
。生产环境下,电阻的额定功率应当至少大于期望值的两倍以上。
假设下图当中的电阻可以调节阻值,并且电源电压恒定为5V
。此时,增大电阻就会导致电流与功率的减小;而当减小电阻时,电流与功率又会增加,所以选用阻值较小的电阻器时,必须适当提高电阻器的额定功率参数标准。
当多个电阻器进行并联时,每一个并电阻器上的电压相同,但是通过的电流会跟随阻值进行变化。并联电路的总电阻,小于各个并联电阻的阻值,并联电阻器的总电阻计算公式如下面所示:
\[R_{total} = \frac{1}{\frac{1}{R_1} + \frac{1}{R_2} + \frac{1}{R_3} +\frac{1}{R_4} + \frac{1}{R_5} + ...}\]
如果仅仅只有两个电阻并联在一起,则其总电阻的计算公式可以被简化为下面的形式:
\[R_{total} = \frac{R_1 \times R_2}{R_1 + R_2}\]
当多个电阻器进行串联时,总电阻等于各个串联电阻之和,流经每一个串联电阻器的电流相同,而电压则跟随阻值进行变化,串联电阻器的总电阻\(R_{total}\) 计算公式如下所示:
\[R_{total} = R_1 + R_2 + R_3 + R_4 + R_5 ... + R_n\]
注意:电阻上标记的最大額定功率不非电阻器实际消耗的功率。流过每一个串联电阻上经过的电流都相同,但是每一个串联电阻器上的电压会随阻值的不同而变化。
下图是一个串联电阻分压电路,其中 \(V_{in}\) 为输入电压,而 \(V_2\) 为输出电压 \(V_{out}\):
可以看到,每一个串联电阻上的电压与其电阻值的大小成正比,上述电路对应的分压公式如下所示:
\[\begin{aligned}V_1 = \frac{R_1}{R_1 + R_2} \times V_{in} \\V_2 = \frac{R_2}{R_1 + R_2} \times V_{in} \\\end{aligned}\]
10%规则是设计分压电路的时候,选择电阻 \(R_1\) 与 \(R_2\)的一种标准方法,该方法综合考虑了负载的影响与负载损耗功率最小的问题。
10%
,此时就称 \(R_2\)为泄漏电阻 \(R_{bleed}\),而 \(R_2\) 上的电流称为泄漏电流\(I_{bleed}\);▶【例题】下图是一个 10V
的电压源,如果要将一个额定电压为3V
,额定电流为 9.1mA
的设备连接到电源上,请为该电路的负载设计一个分压器?
◉【解】根据题设条件,可以分别计算得到泄露电流 \(I_{bleed}\) 与泄露电阻\(R_{bleed}\):
\[\begin{cases}I_{bleed} = I_2 = 9.1 mA \times 10\% = 0.91mA \\R_{bleed} = R_2 = 3V \times 0.0091A = 3197Ω\end{cases}\]
◉【解】考虑到真实电阻器的阻值带有误差,\(R_2\) 需要选择一个阻值接近于上述计算值的\(3300Ω\) 电阻器。接下来,确定电阻\(R_1\),使其输出电压维持在3V
。首先计算出通过电阻器 \(I_1\) 的总电流,然后根据欧姆定律计算出\(R_1\):
\[I_1 = I_2 + I_{load} = 0.91 mA + 9.1mA = 10.0mA = 0.01 A\impliesR_1 = \frac{10V - 3V}{0.01 A} = 700Ω\]
◉【解】最后,再来着手确定两个电阻器所需的额定功率:
\[\begin{cases}P_1 = \frac{V_1^2}{R_1} = \frac{(7V)^2}{700Ω} = 0.07W = 70mW \\P_{R2} = \frac{V_2^2}{R_2} = \frac{(3V)^2}{3300Ω} = 0.003W = 3mW\end{cases}\]
◉【解】根据上述推导过程就可以知道,选择额定功率小于1/4W
的电阻器就可以满足需求。
▶【例题】已知负载1(75V
,30mA
)、负载2(50V
,10mA
)、负载3(25V
,10mA
),请采用10%
规则设计一个可以分别为三个负载提供功率的多项分压器?
◉【解】运用 10%
规则确定分压电阻的关键是计算泄漏电流 \(I_{R4}\),其值等于总电流的10%
,也就是总电流的 0.1
倍,具体计算步骤如下所示:
\[I_{R4} = 0.1 \times (10mA + 10mA + 30mA) = 5mA\]
◉【解】接下来,再根据欧姆定律获得泄露电阻\(R_4\) 的阻值:
\[R_4 = \frac{(25V - 0V)}{0.005A } = 5000Ω\]
◉【解】此时,流过电阻 \(R_3\) 的电流,等于经过电阻\(R_4\) 的电流与经过负载3 的电流之和:
\[I_{R3} = I_{R4} + I_{load3} = 5mA + 10mA = 15mA\]
◉【解】然后,应用欧姆定律和负载 2 与负载3 之间的电位差来求解电阻 \(R_3\):
\[R_3 = \frac{(50V - 25V)}{0.015A} \approx 1667Ω\]
◉【解】类似的,根据经过电阻 \(R_2\)上的电流,运用欧姆定律,就可以求解得到电阻 \(R_2\):
\[I_{R2} = I_{R3} + I_{load2} = 15mA + 10mA = 25mA\impliesR_2 = \frac{(75V - 50V)}{0.025A} = 1000Ω\]
◉【解】同样根据经过电阻 \(R_1\)上的电流,根据欧姆定律,还可以求解得到电阻 \(R_1\):
\[I_{R1} = I_{R2} + I_{load1} = 25mA + 30mA = 55mA\impliesR_2 = \frac{(100V - 75V)}{0.055A} = 455Ω\]
注意:虽然分压器结构简单,但是不能随意调节参数。如果一个负载的
电阻
或者电源电压
发生改变,那么所有负载的电压都会发生变化。相比较而言,采用基于运算放大器的电压调整器是更佳选择。
理想电压源是一个双端元件,其两个端子之间的电压保持着一个固定值。如果将一个可变的负载连接到一个理想电压源,那么无论负载的电阻值如何进行变化,理想电压源的电压始终保持不变,而根据\(I = \frac{V}{R}\),当电压 \(V\) 固定时,电流 \(I\) 随着电阻 \(R\)的变化而变化。当电阻的阻值变为零时,理想电压源的电流就会变为无穷大。
现实世界并不存在能够提供无穷大电流的电源设备,如果直接用导线将理想电压源的两端连接起来,那么电路当中产生的电流将会致使导线熔化,为了避免出现类似的理论难题,必须定义一个由理想电压源
与电阻
串联组成的实际电压源,其提供的最大电流为一个有限值。其中的电阻作为电源内阻
,表示电压源并非一个理想的导体,可以降低电压源两端的电压,具体降低的数值取决于电压源两端的电压与经过的电流(或者负载电阻的大小)。
上图的电路当中,将一个理想电压源的两端开路,此时由于电路没有形成回路,电源内阻上面没有电流经过,因而不会产生电压,电压源的端电压\(V_T\) 等于理想电压源的电压 \(V_S\)。当将一个负载电阻 \(R_{load}\) 与电压源连接之后,此时电阻 \(R\)与电源内阻串联。根据分压公式,电压源的端电压为 \(V_T = V_S \frac{R_{load}}{R_{load} +r_s}\),表明当负载电阻 \(R_{load}\) 远远大于电源内阻时(约1000
倍以上),电源内阻 \(r_s\) 的影响较小可以忽略。但是当负载电阻\(R_{load}\)小于或者接近电源内阻时,就必须考虑到电源内阻的影响。
下面给出了电子学当中直流电流源的符号,它能够在任意时刻为负载提供一个恒定不变的电流\(I_S\),而不论负载电阻如何进行变化。这意味着为了保持电流源的电流恒定,理想电流源的端电压将会随着负载电阻的变化而变化。
通常情况下,实际电流源都具有一个非常大的并联内阻,这个内阻可以使得电流源的端电流减小,减小量取决于电流源的电流值与端电压(或负载电阻的大小)。当电流源的两端开路时,电流源的电流\(I_T\)显然应该为零,但是如果在电流源两端接上负载电阻 \(R_{load}\),与电流源的内阻 \(r_s\)组成并联电阻电路,运用并联电阻分流公式,就可以得到其端电流\(I_T = I_S \frac{r_s}{R_{load} +r_s}\):
上式表明当负载电阻 \(R_{load}\)小于电流源的内阻 \(r_s\)时,流过内阻的电流将会非常小,通常可以忽略不计。但是当负载电阻 \(R_{load}\) 大于或者接近电流源内阻 \(r_s\) 的时候,计算时就必须考虑内阻 \(r_s\)。
一个电源既可以采用电流源表示,也可以采用电压源表示,本质上它们是相互等价的。两者之间进行相互转换时,首先保持电源内阻不变,然后应用欧姆定律将电压源的电压
转换成电流源的电流
:
由于理想电流源的内阻是无穷大的,所以理想电流源的两端可以承受任意大小的电压(或者任意的负载电阻变化)。因而理想电流源可以采用一个具有极高电压\(V\)的电压源与一个较大的电阻 \(R\)的串联组合,来近似的进行表示。如果负载电阻远远小于电阻 \(R\),那么这个近似模型提供给任意负载的电流为\(\frac{V}{R}\)。
例如上图当中的电路由一个 1kV
的电压源与一个1MΩ
的内阻串联组成,当负载电压保持在 \(0V \sim 10V\) 之间时(\(0<R_{load}<10kΩ\)),电路当中的电流将会维持在1mA
,而精度在 1%
以内。实际上,即使负载电阻发生了变化,由于电压源的内阻远远大于负载电阻,电流也会保持不变\(I = \frac{1000V}{1\ 000\ 000Ω + 100\000Ω}\)。由于 \(1\ 000\ 000Ω\)的阻值较大,因而可以忽略负载电阻 \(R_{load}\)。
电池串联之后会增大电压,输出电压等于每一节电池上的电压之和,输出电流等于每一节电池上经过的电流,输出总功率为\(P = \frac{(n \timesV_{battery})^2}{R_{load}}\):
电池并联之后会增大电流,输出电压等于每一节电池两端的电压,输出电流等于每一节电池上经过的电流之和,输出总功率为\(P =\frac{V_{battery}^2}{R_{load}}\):
基尔霍夫定律给出了分析电路的最普遍的方法,该定律不仅适用于线性电路(含有电阻、电感、电容元件),同样也适用于非线性电路(含有二极管、三极管等元件),基尔霍夫定律主要包括有如下两个子定律:
叠加原理适用于分析含有多个电源的线性电路,其内容是指线性电路任意一个支路上的电流,等于电路当中每一个电源单独作用时(其余电源置零,电压源短路,电流源开路)在该支路产生的电流之和。
例如下图左侧电路包含有两个电阻
、一个电压源
、一个电流源
,应用叠加原理可以将其转换为后面两种形式:
首先,把电流源置零,将电流源从电路里移除掉,也就是将电流源\(I_B\) 的两个端子断开:
此时,上图当中流过电阻的电流,仅会由电压源 \(V_A\) 产生,其值等于电压 \(V_A\) 除以等效电阻:
\[I_{21} = \frac{V_A}{R_1 + R_2}\]
然后,将电压源置零,直接通过导线让电压源两端短路,使得电路成为一个分流器:
此时,电流源在电阻 \(R_2\) 两端产生的电流 \(I_{22}\) 等于:
\[I_{22} = \frac{I_B R_1}{R_1 + R_2}\]
最后,运用叠加原理,将电流 \(I_{21}\) 与 \(I_{22}\) 相加,就可以得到支路 2上所经过电流 \(I_2\) 的值:
\[I_2 = I_{21} + I_{22} = \frac{V_A - I_B R_1}{R_1 + R_2}\]
注意:叠加原理是分析线性电路的一种重要方法,也是戴维南定理和诺顿定理成立的基础,这两者在电路分析当中相比叠加原理更为实用,实际电路分析当中较少直接应用到叠加原理。
如果只关注电路当中两个端子之间所连接支路的参数,那么可以将这条支路从复杂电路当中断开,并且把剩余部分电路视为拥有两个端子的线性二端网络,然后采用一个电压源与一个电阻的串联支路来代替,这种电路分析方法就称为戴维南定理。
串联支路上的电压源称为戴维南等效电压 \(V_{THEV}\),电阻称为戴维南等效电阻\(R_{THEV}\),而整个串联支路称为戴维南等效电路。运用这个简单的等效电路,再结合欧姆定律,就可以计算出其所连接电路上的负载电流\(I = \frac{V_{THEV}}{R_{THEV} +R_{LOAD}}\)。
接下来,运用戴维南定理来求解下图左上角的分压电路:
A
与B
两端的开路电压;A
与 B
两端的戴维南等效电阻 \(R_{THEV}\),把直流电源\(V_{BAT}\) 短路,计算或者测量A
与 B
两端的等效电阻 \(R_{THEV}\),即电阻 \(R_1\) 与电阻 \(R_2\) 的并联等效电阻;\[\begin{cases}V_3 = \frac{R_3}{R_3 + R_{THEV}} \times V_{THEV} = \frac{2000Ω}{2800Ω}\times 8V = 5.7V \\I_3 = \frac{V_{THEV}}{R_3 + R_{THEV})} = \frac{8V}{2800Ω} = 0.003A\end{cases}\]
类似于戴维南定理,诺顿定理也是通过一个等效电路来代替复杂的二端网络,而不同之处在于诺顿等效电路是由一个电流源与一个电阻的并联所组成。其中,由于诺顿等效电阻的值与戴维南等效电阻恰好相等,因而只需要计算出电流源的诺顿等效电流\(I_{NORTON}\) 即可。
接下来,对于前面采用戴维南定理分析的分压电路,这里改用诺顿定理来进行分析,其中诺顿电流\(I_{NORTON}\) 就是节点 A
与 B
之间的短路电流:
A
与 B
的两端短路,此时电阻 \(R_2\)被短路没有电流经过,根据欧姆定律可以得到诺顿等效电流:\[I_{NORTON} = \frac{V_{BAT}}{R_1} = \frac{10V}{1000Ω} = 0.01A\]\[I_3 = \frac{R_{THEV}}{R_{THEV} + R_3} \times I_{NORTON} =\frac{800Ω}{2800Ω} \times 0.01A = 0.003A\]
注意:诺顿定理对应的是电流源,戴维南定理对应的是电压源,两者在本质上依然是叠加原理。诺顿等效电路与戴维南等效电路可以相互转换,它们转换之后的等效电阻都相同;戴维南等效电路中的等效电阻与等效电压源串联;而诺顿等效电路中的等效电阻与等效电流源并联;戴维南等效电路的电压等于诺顿等效电路空载时等效电阻上的电压。而诺顿等效电源的电流等于戴维南等效电源的短路电流。
直流(DC):电流
或者电压
的大小、方向都不会发生变化;
交流(AC):电流
或者电压
的大小、方向均呈周期性变化;
脉动直流(PulseDC):电流
或者电压
的大小变化,而方向不发生改变,可以将其视为交流与直流的叠加;
交流发电机利用电磁感应原理可以产生正弦交流信号,下面示意图展示了一个由磁体和线圈构成的简单交流发电机,线圈放置在磁体的N
极与 S
极之间,可以围绕轴心进行旋转。伴随线圈在磁场当中的旋转,通过线圈的磁通量不断发生变化,线圈当中的电荷由于受到磁场力而发生运动,从而在线圈两端形成感应电压。
通过线圈的磁通量 \(\varPhi\)是线圈与磁场方向夹角 \(\theta\) 的函数,而感应电压是以 \(\omega\)作为角频率(rad/s
,弧度每秒)的正弦量。
下图是两个幅值相同,而且频率相近的交流信号,以及将它们串联之后得到的合成波形;注意两个交流信号的正向峰值点在合成之后,将会得到更高的峰值点,这就是所谓的拍现象,拍频率等于\(f_2 - f_1 = 500Hz\):
下图是两个频率与幅值相差较大的交流信号,以及使它们串联之后得到的合成波形,可以发现一个波驮载在另外一个波上面:
注意:把两个幅值与相位不同,但是频率相同的正弦波合成之后,得到的仍然是正弦波,这个特点在交流电路分析当中尤为重要。
利用傅里叶变换,通过一系列正弦波的叠加,就可以获得任意的周期性波形:
一个理想的正弦电压源,无论其负载如何,总是可以提供所需的电流并且维持两端的电压。而一个理想的正弦电流源,无论负载如何,都能够提供所需的电压并维持其输出电流。除此之外,还可以建立用于产生方波信号的时钟源。下图从左至右,分别展示了交流电压源、交流电流源、时钟源的符号:
交流电压
或者电流
信号的完整描述,需要使用幅值、频率、相位三要素。
下图展示了一个正弦电压
或者电流
的幅值,与一个逆时针旋转圆周的对应关系。电压
、电流
的幅值随着圆周上与\(0°\)线之间的夹角进行正弦变化,例如 \(\sin 90°\) 为1
,对应正半波的最大值;而 \(\sin 270°\) 为-1
,对应负半波的最大值;而 \(\sin 45°\) 为0.707
,对应着最大值的 0.707
倍:
持续转动的发电机可以产生正弦变化的电压
或者电流
,随着时间的不断推移,正弦波形也会不断的循环。在循环的波形上任意选取一点(例如正峰值位置)作为标记点,则每秒钟电流
或者电压
到达该标记点的次数,就称为交流电的频率。换而言之,频率表示的是电信号循环的速率,其单位为赫兹Hz
。而每次循环所持续的时间称为周期,周期在数值上等于频率的倒数:
\[\begin{cases}频率f(Hz) = \frac{1}{周期T(s)} \implies f = \frac{1}{T} \\周期T(s) = \frac{1}{频率f(Hz)} \implies T = \frac{1}{f}\end{cases}\]
例如 60Hz
交变电流信号的周期为 \(T = \frac{1}{60Hz} = 0.0167S\),而2ns
周期交变电压信号的频率为 \(f = \frac{1}{2 \times 10^{-9}(s)} =500MHz\)。
绘制下图所示的电压
、电流
正弦曲线时,通常以0°
作为计时起点,即信号正半周的起始点,而正向峰值则出现在90°
位置。换而言之,相对于 0°
起始点,交流峰值所处的相位为 90°
:
注意:一个交流信号的周期被划分为
360°
,并以此作为时间与相位的计量单位。
相位可以用于比较频率相同的交流信号,例如下图所示的正弦波A 先经过 0°
点,而正弦波B 后经过 0°
点,两个波形之间存在着相位差。图中 B滞后于 A 有 45°
,或者说 A超前于 B 有 45°
。如果正弦波A 和 B出现在相同的电路当中,两者叠加之后合成的波形相位将会介于A 与 B的相位之间。而对于同频率的正弦波而言,叠加之后产生的合成波形频率相同,而幅值与相位将会发生改变:
注意:两个同频率正弦波起始点不同,它们之间的相位差可以采用弧度或角度进行度量,上图当中B 的起始点比 A 滞后
1/8
周期,即 B 滞后于 A 有45°
。
下图所示的是一种相位差的特殊情况,其中B 滞后于 A 有 90°
,也就是B 恰好落后于 A 有 1/4
周期,即波形经过 0°
点时,另一个波形恰好到达峰值的位置:
下图所示的是另外一种相位差的特殊情况,其中A 与 B 相位差为180°
,因而当 A波形为负的时候,B波形为正,反之亦然。当在同一个电路当中,添加这样两个幅值相同的电压
、电流
信号时,将会导致它们相互抵消:
如果向电阻的两端添加交流电压,则通过电阻的电流
将会与交变电压
的相位一致,根据交变电压
与电阻
的值,就可以基于欧姆定律计算出交变电流
。例如信号发生器所产生正弦波的计算表达式为:
\[V(t) = V_P \sin(2\pi \times f \times t)\]
上面等式当中的 \(V_P\)是正弦电压峰值、\(f\)为频率、\(t\)为时间,利用欧姆定理与功率定理可以得到如下表达式:
\[I(t) = \frac{V(t)}{R} = \frac{V_P}{R} \sin (2\pi \times f \times t)\]
将上述的 \(V(t)\) 与 \(I(t)\)的波形,绘制在相同的坐标系当中。此时电流
与电压
的相位一致,即电流
伴随着电压
同时增大:
可以看到,当交流电源两端接入纯电阻负载时,电压与电流处于相同的相位。如果负载不是纯电阻负载(例如电容、电感),那么情况就将会完全不同(后续章节会进行介绍)。求解正弦信号下电阻所消耗的功率,可以将正弦电压的表达式直接代入欧姆定律,从而得到瞬时功率的表达式:
\[P(t) = \frac{V(t)^2}{R} = \frac{V_P^2}{R} \sin(2 \pi \times f \times t)\]
从数学角度来看,电压
、电流
与功率
的瞬时表达式并不复杂,只需要将具体时间\(t = 1.3S\)代入即可求解出实际值。但是仅获得某一具体时刻的电流
、电压
、功率
意义不大,还必须知道计时的起点。实际应用当中,这些瞬时值很难获取。最有效的方法是采用平均值代替瞬时值,而且运用平均值计算有功功率损耗可以不涉及正弦函数。然而正弦波在一个周期当中的正、负波形会相互抵消,导致电压
、电流
的平均值为零。所以对于功率而言,正半波与负半波都在进行能量的传递。因而必须找到一个能够代替平均值的参数,而这个参数正是均方根值(RMS,RootMeanSquare),这个值可以通过对交变电压
、交变电流
的瞬时值进行平方,然后获取其在一个周期当中的平均值,再对这个值进行开平方根来获得。
均方根值 RMS也称为有效值,其实质是交流电压/电流
与直流电压/电流
所消耗热能的等效,即交流电的均方根值等于相同电阻元件消耗交/直流功率,产生同等热量时刻的值。根据上述原理,电阻在交流峰值时消耗的功率是直流时消耗功率的两倍,也就是说,平均交流功率是交流峰值功率的\(\frac{1}{2}\)。
\[平均功率 P_{ave} = \frac{峰值功率 P_{peak}}{2}\]
假设正弦电压 \(V(t) = V_P\sin(2 \pi \times f \times t)\)、正弦电流 \(I(t) = I_P \sin(2 \pi \times f \timest)\),则它们的 RMS有效值表达式如下方程所示:
\[\begin{cases}V_{RMS} = \sqrt{\frac{1}{T} \int_0^T V(t)^2 dt} = \frac{1}{\sqrt{2}}\times V_P = 0.707 \times V_P \\I_{RMS} = \sqrt{\frac{1}{T} \int_0^T I(t)^2 dt} = \frac{1}{\sqrt{2}}\times I_P = 0.707 \times I_P\end{cases}\]
上述的推导过程表明,电压
与电流
的RMS值只与电压
或者电流
的峰值有关,而与时间和频率无关,通过简单的计算可以得到如下换算关系:
\[\begin{cases}V_{RMS} = \frac{V_P}{\sqrt{2}} \approx \frac{V_P}{1.414} \approx 0.707\times V_P \implies V_P \approx V_{RMS} \times 1.414 \\I_{RMS} = \frac{I_P}{\sqrt{2}} \approx \frac{I_P}{1.414} \approx 0.707\times I_P \implies I_P \approx I_{RMS} \times 1.414\end{cases}\]
注意:美国家庭用电标准为
60Hz,1VAC
,欧洲国家则普遍采用50Hz,2VAC
,单位 VAC 表示该电压值属于RMS 均方根有效值。
把电压
与电流
的 RMS有效值代人欧姆定律,就可以得到交流欧姆定律:
\[V_{RMS} = I_{RMS} \times R\]
同样的,把电压
与电流
的 RMS有效值代入功率定理,就可以得到交流功率定理(此处的功率是指有功功率):
\[P = I_{RMS} \times V_{RMS} = \frac{V_{RMS}^2}{R} = I_{RMS}^2 R\]
注意:上述公式只能应用于不包含
电容
与电感
的纯电阻电路当中。
下面的表格,展示了上图电压与电流的均方根有效值
、峰值
、峰峰值
、半波平均值
之间的关系,掌握它们之间的换算关系尤为重要:
待转换类型 | 结果类型 | 换算因数 |
---|---|---|
峰值 | 峰峰值 | \(2\) |
峰值 | 平均值 ★ | \(\frac{2}{2\pi}\) 或者 0.6366 |
峰值 | 有效值 | \(\frac{1}{\sqrt{2}}\) 或者 0.7071 |
峰峰值 | 峰值 | \(0.5\) |
峰峰值 | 有效值 | \(\frac{1}{2\sqrt{2}}\) 或者 0.35355 |
平均值 ★ | 峰值 | \(\frac{\pi}{2}\) 或者 1.5708 |
平均值 ★ | 有效值 | \(\frac{\pi}{2\times \sqrt{2}}\) 或者 1.1107 |
有效值 | 峰值 | \(\sqrt{2}\) 或者 1.4142 |
有效值 | 平均值 ★ | \(\frac{2\times \sqrt{2}}{\pi}\) 或者 0.9003 |
有效值 | 峰峰值 | \(2 \times\sqrt{2}\) 或者 2.828 |
注意:上面表格当中标注有 ★符号的,表示的是半个周期内的平均值。
下面的表格,展示了上图所示正弦波、方波、三角波/锯齿波的半波平均值
、峰值
、峰峰值
、有效值
之间的换算关系:
波形 | 半波平均值 | 有效值 | 峰值 | 峰峰值 |
---|---|---|---|---|
正弦波 | 1.00 | 1.11 | 1.567 | 3.14 |
... ... | 0.90 | 1.00 | 1.414 | 2.828 |
... ... | 0.637 | 0.707 | 1.00 | 2.00 |
... ... | 0.318 | 0.354 | 0.50 | 1.00 |
方波 | 1.00 | 1.00 | 1.00 | 2.00 |
三角波或锯齿波 | 1.00 | 1.15 | 2.00 | 4.00 |
... ... | 0.87 | 1.00 | 1.73 | 3.46 |
... ... | 0.50 | 0.578 | 1.00 | 2.00 |
... ... | 0.25 | 0.289 | 0.50 | 1.00 |
在两块带有相反极性电荷的平行板之间,填充上绝缘介质,就可以制作成为一个平行板电容器:
电容器是一种专门用于保存电荷,从而通过电场储存电能的元器件。如果移出电容器两极的电源,那么电容器自身的漏电流将会导致完全放电。或者采用一根导线连接电容器的两极,也可以中和两个极板上的异种电荷,从而达到快速放电的目的。
电容器当中存储的电荷量,与其两极之间电压的比值就称为电容,采用符号\(C\) 进行表示:
\[电容 C = \frac{电荷 Q}{电压 V}\]
上述公式当中电容 \(C\)的值总是取正值,单位为法拉,简写为\(F\),1
法拉等于一库仑每伏 \(1F =\frac{1C}{1V}\)。固定电容器
、有极性电容器
、可变电容器
、微调电容器
的符号(左侧),以及实际电容器的等效模型(右侧)分别如下图所示:
注意:电容器的取值范围比较宽泛,即可以在给定的电压之下存储不同的电荷量,也可以在给定电荷量的情况下维持不同的电压。因而选取合适的电容器,就能够控制电荷量或者电压。
电容器的容值与极板面积 \(A\)(单位为 \(m^2\))、极板间距 \(d\)(单位为 \(m\))、电介质的介电常数\(\varepsilon\)(真空介电常数 \(\varepsilon_0 = 8.85 \times 10^{-12}\ C^2 /N \cdotm^2\))有关。如果极板上的电压为 \(V\),极板之间的电场强度\(E =\frac{V}{d}\),此时极板上必然携带有等量的异种电荷\(Q\):
\[电荷 Q = 介电常数 \varepsilon \times 极板面积 A \times 极板间电场强度 E= \frac{介电常数 \varepsilon \times 极板面积 A \times 两极电压V}{极板间距 d}\]
上述方程当中的 \(\frac{\varepsilonA}{d}\) 部分,就是电容器 \(C\)的容值计算公式:
\[电容值 C = \frac{介电常数\varepsilon \times 极板面积 A}{极板间距 d}\]
某一种介质的介电常数与真空的介电常数的比值,就称为该介质材料的相对介电常数\(k\):
\[相对介电常数 k = \frac{某物质介电常数 \varepsilon}{真空介电常数\varepsilon_0}\]
将相对介电常数 \(k\)的表达式,代入至上述的电容值 \(C\) 的表达式里,就可以得到下面的方程:
\[电容值 C = \frac{相对介电常数 k \times 真空介电常数 \varepsilon_0 \times极板面积 A}{极板间距 d} = \frac{(8.85 \times 10^{-12}) \times相对介电常数 k \times 极板面积 A}{极板间距 d}\]
相对介电常数的变化范围为 \(1.00059\)(一个标准大气压下的空气)到 \(10^5\)(某一些陶瓷材料),下面的表格展示了一些常见介质的相对介电常数:
通常情况下,电容器的极板数量不止两个,通过极板的交替层叠,就可以在较小空间内获得较大的容值,由\(n\)层极板构成的电容器容值表达式如下所示:
\[电容值 C = \frac{相对介电常数 k \times 真空介电常数 \varepsilon_0 \times极板面积 A}{极板间距 d} \times (极板层数 n - 1)\]
注意:电容器的极板通常使用金属薄片制作而成,极板之间填充固态或者液态电介质(如
云母
、纸
、聚丙烯
、陶瓷
)。其中,电解电容器的极板采用铝箔制成,极板之间填充的电介质为半液体状的化合物,电解电容器的容值通常较大,使用时需要区分其正负极性。极性的限制意味着电解电容不能直接应用于交流电路,但是可以应用于交流与直流叠加的电路当中,只要交流峰值电压不超过其最大直流工作电压(DCWV,Direct-CurrentWorkingVolts)即可,否则就会造成电介质击穿,在两个极板之间形成一道低阻的电流路径,导致电容器完全损坏。
理想电容器容值的微分形式可以记为 \(dQ = C \timesdV\),其中电容值 \(C\) 是一个不会随着电荷\(Q\) 或者电压 \(V\) 变化的常量,而此时电流\(I =\frac{dQ}{dt}\),将其与电容的微分表达式联立之后,就可以得到经过电容器的电流\(I_C\):
\[I_C = \frac{d 电荷量 Q}{d 时间 t} = \frac{d(电容值 C \times 电容电压V_C)}{d 时间 t} = 电容值 C \times \frac{d 电容电压 V_C}{d 时间 t}\]
上面的方程表示在 \(dt\)时间内,有大小为 \(C \times dVc\)的微量电荷 \(dQ\)流入右侧极板,同时在左侧极板上出现数量相同的电荷\(dQ\),即量值为 \(\frac{dQ}{dt} = \frac{C \times dV_C}{dt}\)的电流进入了左侧极板。根据上述电容器经过电流 \(I_C\)的微分方程,可以求解得到电容器上电压 \(V_C\) 的表达式:
\[V_C = \frac{1}{C} \int I_C dt\]
上述方程针对的都是理想电容器,其所反映的各种特性,并不能直接应用于实际电容器,使用时应当加以鉴别和区分:
首先,如果在理想电容器两端施加直流电压,由于电压的变化率为 \(\frac{dV}{dt} = 0\),则电容器的电流为 \(0\),因而直流电路当中的电容器相当于开路。如果此时突然改变电压值,那么\(\frac{dV}{dt} = \frac{9V}{0V} =\infty\),此时电容器上的电流为无穷大 \(\infty\),但是实际电路当中的电流不可能为无穷大。
其次,电容器在直流状态下并没有电流经过,只有当其两端电压发生改变时,电容器才能够存储或者释放来自于电流的电荷。例如闭合上面电路当中的充电开关时,9V
电源会连接到电容器的两端,电容器中的电荷量立刻上升至最大值。然而对于实际电容器,由于其内电阻的存在,积累电荷需要耗费一定时间,使得位移电流不会为无穷大。而在电容器充电过程当中,电流会先突变至\(\frac{V_{battery}}{R_{internal}}\)而后迅速呈指数规律下降,与此同时电压会呈指数规律上升至与电源电压相等,下图是实际电容器在充电过程当中,电压
与电流
的变化曲线:
最后,当闭合放电开关之后,电容器的正负极板之间会形成一条导电路径,从而释放出与充电方向相反的电流,伴随着电荷的逐渐中和,电流从初始峰值\(\frac{V_{battery}}{R_{internal}}\)衰减,而电压则按照指数规律下降:
注意:由于实际电路当中经常存在电阻器元件,其电阻值远大于电容器的内阻,因而后者通常可以忽略,后续的RC阻容电路将会更加详细的讨论这一点。
虽然理想电容器不会消耗能量,但是实际电容器的内阻是会消耗能量的,不过该内阻值通常比较小,因而往往会忽略其造成的热损耗。
电容器当中的能量以电场的形式进行储存,将电容器的电流代入至功率表达式\(P = IV\) 当中,再将结果代入功率的定义\(P = \frac{dE}{dt}\) 里,对 \(E\)进行积分,就可以获得电容器上面存储的能量 \(E_{cap}\):
\[E_{cap} = \int VIdt = \int VC \frac{dV}{dt} = \int CVdV = \frac{1}{2}CV^2\]
例如在 \(1000 \mu F\)的电容器两端添加 5V
的电压,那么该电容器里面存储的能量 \(E_{cap}\) 等于:
\[E_{cap} = \frac{1}{2} CV^2 = \frac{1}{2} \times (1000 \times 10^{-6}F)\times (5V)^2 = 0.0125 J\]
首先,将电容器连接到直流电压源的两端,使其在一瞬间完成充电。然后,再把充满电的电容器两端进行短接,使其在一瞬间完成放电。基于这个过程,如果在该电路里加入一个电阻器,那么其充放电速率将会遵循下图所示的指数规律:
上图左侧 RC 充电电路当中的电阻\(R= 10kΩ\),而电容\(C = 100 \muF\),其波形图如右侧所示。此时电路当中的电阻电压\(V_R\)、电容电压\(V_C\)、电流 \(I\) 之间的关系如下面方程所示:
\[\begin{aligned}I = \frac{V_S}{R} e^{-\frac{t}{RC}} &\implies \frac{t}{RC} = - \ln\bigg(\frac{IR}{V_S} \bigg) \\V_R = IR = V_S \cdot e^{-\frac{t}{RC}} &\implies \frac{t}{RC} = -\ln \bigg(\frac{V_R}{V_S} \bigg) \\V_C = \frac{1}{C} \int Idt = V_S(1 - e^{-\frac{t}{RC}}) &\implies\frac{t}{RC} = -\ln \bigg( \frac{V_S - V_C}{V_S} \bigg)\end{aligned}\]
上述方程当中电流 \(I\)的单位为安培,电压源 \(V_S\)的单位为伏特,电阻 \(R\)的单位为欧姆,电容 \(C\)的单位为法拉,接入电压源后的时间 \(t\)单位为秒,除此以外自然常数 \(e \approx 2.718\)。
通常以小写字母 \(\tau = t = RC\)来表示电路的时间常数(单位为秒),表示的是RC 电路当中,电容器通过电阻从初始的0
电压,充电至最大电压的 63.2%
所需要的时间;或者是通过同一个电阻,将电容放电至其初始电压36.8%
所需要的时间。
1
个时间常数 \(t = RC =\tau\) 以后,电容器上的充电电压达到电源电压的63.2%
;2
个时间常数 \(t = 2RC =2\tau\) 以后,电容器上的电压达到电源电压的86.5%
;3
个时间常数 \(t = 3RC =3\tau\) 以后,电容器上的电压达到电源电压的95%
;5
个时间常数以后,电容电压为电源电压的99.24%
,可以认为已经充电完毕;下图右侧 RC 放充电电路当中的电阻\(R = 3kΩ\),而电容\(C = 0.1 \muF\),其波形图如右侧所示:
此时电路当中的电阻电压 \(V_R\)、电容电压 \(V_C\)、电流 \(I\) 之间的关系如下面方程所示:
\[\begin{aligned}I = \frac{V_S}{R} e^{-\frac{t}{RC}} &\implies \frac{t}{RC} = - \ln\bigg(\frac{IR}{V_S} \bigg) \\V_R = IR = V_S \cdot e^{-\frac{t}{RC}} &\implies \frac{t}{RC} = -\ln \bigg(\frac{V_R}{V_S} \bigg) \\V_C = \frac{1}{C} \int_0 Idt = V_S \cdote^{-\frac{t}{RC}} &\implies \frac{t}{RC} = -\ln \bigg(\frac{V_C}{V_S} \bigg)\end{aligned}\]
RC 电路当中,电容器的放电过程,正好与其充电过程完全相反:
1
个时间常数 \(t =1\tau\) 以后,电容电压下降 63.2%
,为电源电压的37.8%
;5
个时间常数 \(t =5\tau\) 以后,电容电压下降 99.24%
,为电源电压的0.76%
,可以认为此时已放电完毕;电容效应并不只存在于电容器的内部,不同电位的表面相互靠近时也会产生电场,从而也存在电容效应,称为寄生电容。这种效应会对电路造成不必要的干扰,因而必须采取措施降低其影响:
高阻抗电路当中,由于容性电抗占据电路阻抗的比例较大,因而寄生电容造成的影响也会更大。除此之外,由于寄生电容往往与电路形成并联,当信号频率较高时,就会造成正常信号被旁路的问题。
当多个电容器进行并联时,总电容 \(C_{total}\)等于各个并联电容的容值之和,其计算方式类似于串联电阻:
\[C_{total} = C_1 + C_2 + C_3 + C_4 + ... C_n\]
注意:可以将电容器的并联,直观的视为增大了电容器极板的面积。
对于下面电路的上半部分结点,运用基尔霍夫电流定理可以得到\(I_{total} = I_1 + I_2 + I_3 + ... +I_n\):
由于电容 \(C_1\) 与 \(C_2\) 两端的电压均为 \(V\),将其代入上面的基尔霍夫电流方程,化简之后结果中的括号部分,就是并联等效电容的计算公式:
\[I = C_1 \frac{dV}{dt} + C_2 \frac{dV}{dt} + C_3 \frac{dV}{dt} + ... +C_n \frac{dV}{dt}= (C_1 + C_2 + C_3 + ... + C_n) \frac{dV}{dt}\]
注意:并联电容器两端的安全电压,主要受限于额定电压最低的那一个电容。
当多个电容器串联在一起的时候,总电容 \(C_{total}\)的倒数等于每一个串联电容器容值的倒数之和,其计算方式类似于并联电阻:
\[\frac{1}{C_{total}} = \frac{1}{C_1} + \frac{1}{C_2} + \frac{1}{C_3} +... + \frac{1}{C_n}\]
串联之后的总电容将会降低,并且小于容值最小的那个电容;每一个串联电容器两端的电压,等于输入电压\(V_{IN}\) 的分数 \(V_{IN} \cdot(\frac{C_{total}}{C_2})\),许多电路就利用到了电容器的这种分压特性:
由于每一个串联电容器上的电流 \(I\)相等,根据基尔霍夫电压定理得到下面的方程,该方程最后结果的括号部分,就是串联等效电容的计算公式:
\[V = \frac{1}{C_1} \int Idt + \frac{1}{C_2} \int Idt + \frac{1}{C_3} \intIdt + ... + \frac{1}{C_n} \int Idt = \bigg ( \frac{1}{C_1} +\frac{1}{C_2} + \frac{1}{C_3} + ... + \frac{1}{C_n} \bigg ) \int Idt\]
注意:每一个串联电容器两端的电压,都不得超过其额定电压,必要时可以借助分压电阻来避免电容器损坏。
交流电路当中的电容器,可以允许或者限制特定频率的电流通过。下图所示的就是在交流信号下,电容器的电压、电流、功率关系曲线:
上图当中正弦电压的最大值为 100V
,在 0 ~ A
这段时间里,外加电压从 0V
上升至38V
,此时电容器也会被充电至 38V
;而在A ~ B
阶段,外加电压上升至71V
,电容器电压也随之提高了 33V
,由于A ~ B
阶段电容器的电压增量相比 0 ~ A
阶段要小,因而电容器的电荷增量也要比 0 ~ A
阶段更少;到了B ~ C
阶段,外加电压从 71V
上升至92V
,电容器电压随之提高了21V
,电压增量继续减小;继续到 C ~ D
阶段,外加电压只增加了 8V
,电压增量进一步减小。
如果把前 \(\frac{1}{4}\)周期分割为多个时间段,就会发现电容器的充电电流波形与外加电压一样为正弦波,周期起始点的电流为最大值,当电压达到最大值时电流变为零,表明在电压与电流之间存在着-90°
相位差。第二个 \(\frac{1}{4}\) 周期,也就是D ~ H
这段时间,外加电压降低,电容器将电荷释放回电路,并且电流方向与充电电压的方向相反;第三、四个\(\frac{1}{4}\)周期,将会分别重复第一、二个 \(\frac{1}{4}\)周期的过程,不同之处在于外加电压的极性相反,电流也会发生相应的改变。换而言之,电容器的充放电过程产生了交变电流。
注意:通过电容器的的电流超前于电压有
90°
度。
电容器上面的电荷量正比于电容与外加电压\(Q =CV\),一个交流电路当中,电荷在电路当中进行周期性的往返运动,电荷/电流
的运动速度与电压
、电容
、频率
呈正比关系。将电容与频率相乘,就可以得到一个类似于电阻
的参数容抗\(X_C\),其单位与电阻一样为欧姆Ω
:
\[容抗 X_C = \frac{1}{2 \pi \times 频率 f \times 电容 C} = \frac{1}{角频率\omega \times 电容 C}\]
上面公式当中,容抗 \(X_C\) 的单位为欧姆Ω
,频率 \(f\) 的单位为赫兹Hz
,电容 \(C\) 的单位为法拉F
,而圆周率 \(\pi\) 约等于 3.1416
,而 \(2 \pi f\) 通常使用角频率\(\omega\) 进行代替。
当频率 \(f\) 为无穷大时,容抗 \(X_C\)等于零,即高频时电容器相当于短路,可以认为电容器具有高通特性。而当频率\(f\) 等于零时,容抗 \(X_C\)趋于无穷大,电容器相当于断路,可以认为电容器具有抑制低频信号的特性。
注意:虽然容抗 \(X_C\)的单位为欧姆,但是容抗并不会消耗电能。在 \(\frac{1}{4}\)周期内存储在电容器的电能,会在下一个 \(\frac{1}{4}\)周期释放回电路,即一个周期当中的平均功率为零。
下图展示了各种理想电容器的容抗
与频率
之间的关系,可以看出两者呈现反比关系:
实际电容器需要考虑到电容内阻
以及电感效应
,其容抗
与频率
的关系如下图所示,图中曲线的最低点表示电容器的谐振点,该频率点下电容器的电容
与电感
效应相互抵消,因而只剩下内阻
,这个点的频率就被称为谐振频率:
上图当中,实际电容器的阻抗,首先会随着频率的增大而减小,然后又会随着频率的增大而增大。由于实际电路当中寄生效应的存在,电容器的曲线与上图描绘的曲线可能并不完全一致。
电容器分压电路通常只用于交流电路当中(由于电容器会隔断直流电压,所以其构成的分压电路不能工作在直流状态),电容器分压电路的交流输出电压\(V_{out}\)计算公式与电阻分压电路不同,其分子是串联电容 \(C_1\) 而非 \(C_2\):
注意:电容器分压电路的输出电压与输入电压的频率无关。
对于电容、电感等储能元件,可以通过品质因数Q 来区别其性能优劣。这类元件的 Q值等于元件存储的能量(即储能相关的参数电抗
)与其内部消耗的能量(即耗能相关的参数电阻
)之比:
\[品质因数 Q = \frac{电抗 X}{电阻 R}\]
品质因数 Q没有单位,电容器的电抗 \(X\) 就等于其容抗 \(X_C\),而电感器的电抗\(X\) 同样等于其感抗\(X_L\),电阻 \(R\)表示的是元件中与能量消耗相关的全部内阻。
注意:电容器的 Q值通常都比较高,例如陶瓷电容器和云母电容器的Q 值可以达到
1200
以上;而微型可调陶瓷电容器的 Q值比较小,某些应用场合下可以忽略;而微波电容器的Q 值在10GHz
以上工作频率不会超过10
。
电子学当中的三个基本元件分别是电阻、电容、电感。其中,电容器以电场
的形式存储电能,而电感器则是以磁场
的形式储存电能。现代物理将电场与磁场结合起来形成了场论,称为电磁学。
磁场可以使得导体内部的电子受力,并且沿着某一个方向移动形成电流,其作用效果类似于电路里的电动势(EMF,ElectromotiveForce),通常称为感应电动势,根据法拉第电磁感应定律,电路当中的感应电动势与磁通变化率成正比:
\[感应电动势 EMF = - \frac{d\ 磁通量 \varPhi_M}{d\ 时间 t}\]
上面等式当中的 \(\varPhi_M\)是穿过闭合回路的磁通量,其值等于磁场强度\(B\) 与面积 \(A\) 点积的积分:
\[磁通量 \varPhi_M = \int 磁场强度 B \cdot d\ 面积 A\]
可以看到,在电路当中产生感应电动势的途径,主要存在如下三种:
自感是指通过闭合线圈的电流发生了变化,致使线圈本身产生感应电动势的现象。电感器就是一种基于自感原理的电子元器件。其通常具有环状结构,内部可以产生较大的磁通。当电流变化较大时,也可以承受住较大的自感电压。
下图分别展示了空芯电感器、磁芯电感器、可调电感器、铁氧体磁环的电路符号:
当电感器两端电压值增大时,电路当中的电流随之增大,通过螺旋线圈的磁通量也将会增大。增大的磁通量会对自由电子产生反向的作用力,这个作用力就是与初始电压方向相反的感应电动势,称为反向感应EMF。
而当电感器两端电压值降低时,电路当中的电流随之减小,通过螺旋线圈的磁通量也将会减小。减小的磁通量会对自由电子产生同向的作用力,这个作用力就是与初始电压方向相同的感应电动势,称为同向感应EMF。
电感的充磁是指电源提供的能量传递到电感磁场的过程,例如下图所示电路当中,将开关由B 拔向 A时,电感上的电压发生改变,产生一个突然增大的电流,此时电感的磁场从零开始快速增大,这个过程就称为电感的充磁。
根据法拉第电磁感应定律,随着电感线圈磁通量的增大,线圈内的自由电子受到一个与电源电压方向相反的作用力(反向感应EMF):
反向感应电动势的作用结果是在电流增大时,电感产生的阻力也在增大。一段时间之后,电路里的电流不再上升,磁场强度也停止变化,通过线圈的磁通量也不再发生变化,此时反向感应电动势消失,电感呈现为直接导通的状态。下面示意图的上半部分是电源电压与感应电压的关系曲线,而下半部分则是经过电感的电流曲线\(I = \frac{V_s}{R}(1 -e^{-t/(L/R)})\):
电感的去磁就是将电感中的磁场能量释放回电路,从而转换为电能的过程。将开关由A 拔向 B时,电感上的电压发生改变,使得电流趋于零,此时电感的磁场强度骤然减小,这个过程就称为电感的去磁。
去磁过程当中,电感会力图阻止磁场的减小,根据法拉第电磁感应定律,通过线圈的磁通量减小,线圈内的自由电子会受到与开关拔动之前的电源电压同向的作用力(同向感应EMF)。因而电感会在电流降低的过程当中,充当电源的角色为电路提供电流,其所提供的能量来自于磁场的变化:
下面示意图的上半部分同样是电源电压与感应电压的关系曲线,而下半部分依然是经过电感的电流曲线\(I =\frac{V_s}{R}(e^{-t/(L/R)})\):
电感的感应电压 \(V_L\)(感应电动势)与电流\(I_L\)的关系可以采用下面的方程来进行表示:
\[感应电压 V_L = \frac{d\ 电流 I_L}{d\ 时间 t}\]
分别对上述方程的左右两侧进行积分,就可以求解得到电流\(I_L\) 的表达式:
\[电流 I_L = \frac{1}{电感系数 L} \int 感应电压\ V_L\ \cdot d\ 时间\ t\]
该表达式中的 \(L\)称为电感系数,其大小与电感的物理特性相关,例如线圈的形状与匝数、磁芯的材料与结构等。
注意:理想电感两端的电压是感应电压\(V_L\),当稳态直流通过电感时 \(V_L =0\),此时电感相当于短路。
电感系数的单位为亨利 H
,1H
等于当电流变化率为 1A/s
时 1V
的感应电压,即\(1 H = \frac{1V}{1A/s}\)。电子元件厂商生产的电感器,其典型电感系数范围在 \(0.1nH \sim 50H\) 之间,除了亨利H
这个单位之外,电感系数的常用单位还有纳亨nH
、微亨μH
、毫亨 mH
:
\[1 H = 10^3 mH = 10^6 μH = 10^9 nH\]
电感系数也可以根据其物理原理来进行定义,即任意时刻的电感系数等于磁通链\(N \varPhi_M\) 与电流\(I\) 的比值:
\[电感 L = \frac{磁通链 N \varPhi_M}{电流 I}\]
对于下图所示的空心螺线管,当流过线圈的电流为 \(I\),应用安培定律就可以计算出其磁通量\(\varPhi_M\):
\[\varPhi_M = B \cdot A = \bigg( \frac{\mu_0 NI}{l} \bigg) \cdot A = \mu_0A n_{unit} I\]
上述计算过程当中,\(n_{unit}\)为线圈单位长度的匝数 \(n_{unit} = \frac{N}{l}\),其中 \(N\) 为总匝数,\(l\) 为线圈长度,\(A\) 为横截面积,\(\mu\)为线圈内芯的磁导率。除金属铁以及铁氧体之外,大多数材料的磁导率都近似为空气的磁导率\(\mu_0 = 4 \pi \times 10^{-7}\ T\cdotm/A^2\)。
根据法拉第电磁感应定律,每匝线圈上面都存在着感应电压,因而总感应电压\(V_L\) 为磁通量 \(\varPhi_M\) 变化率的 n
倍,这里的 n
表示的是线圈匝数:
\[V_L = N \times \frac{d \varPhi_M}{dt} = \frac{\mu N^2 A}{l} \times\frac{dI}{dt}\]
上式当中的 \(\frac{\mu N^2 A}{l}\)部分就是电感线圈的电感系数 \(L_{sol} = \frac{\mu N^2A}{l}\),其值伴随着线圈总匝数 \(N\) 的平方进行变化,如果匝数增加1
倍,那么电感系数将会增加 4
倍;如果让线圈的电感系数增加 1
倍,则匝数应为线圈原有匝数的\(\sqrt{2}\) 或者1.414
倍。
类似于之前介绍的理想电容器,理想电感器同样不消耗能量,而是将能量存储在磁场当中,当磁场减小的时候,又会将能量释放回电路。利用功率定理\(P = IV\),结合功率的定义 \(P = \frac{dW}{dt}\) 和电感方程 \(V =\frac{LdI}{dt}\),并使用电感的储能 \(E_L\) 代替功 \(W\) 就可以获得如下的推导过程:
\[储能 E_L = \int P dt = \int IV dt = \int IL \frac{dI}{dt} dt = \int LIdt = \frac{1}{2} LI^2\]
上面等式当中,能量 \(E_L\) 的单位为焦耳J
,电流 I
的单位为安培 A
,电感L
的单位为亨利H
。
注意:实际电感器只会有少部分的能量被其内电阻以热量的形式损耗。
电感线圈通常绕制在磁性材料上面,例如叠片式铁芯
、铁氧体混合材料
,磁芯可以增大线圈的磁通密度,进而提高电感系数。
注意:磁芯线圈产生
磁通密度
与空芯线圈产生磁通密度
的比值,称为磁芯材料的相对磁导率\(\mu_R = \frac{\mu}{\mu_0}\)。
如果磁芯材料是导体(相比于钢制材料,铁氧体材料电阻率更大),那么在磁场发生变化时,磁芯材料内部就会产生下图所示的涡流效应:
当流过线圈的电流增大时,通过磁芯的磁通量就会发生变化,磁芯材料当中就会感应到环路电流,出现类似于电阻的热损耗,这种现象就称为涡流效应(低阻抗率材料的涡流损耗较大)。为了避免这种情况的发生,可以将涂有绝缘漆的导体薄片,层叠在一起构成磁芯,从而降低磁通变化所引起的涡流效应。
除了涡流效应之外,使用钢制材料的另一个问题在于其磁导率会随着磁场强度
、电流
、温度
的变化而发生变化。当磁场强度足够大时,钢制磁芯将会发生饱和,其相对磁导率会降低至约等于1
的水平。钢制磁芯的磁场与线圈当中电流的变化过程有关,这种剩磁特性在电感器当中,会造成额外的损耗,这种损耗被称为磁滞损耗。为了避免这种情况的出现,必须让磁芯式电感器工作于非饱和状态。通过降低工作电流
、使用较大磁芯
、改变线圈匝数
、使用低磁导率的磁芯
或者带有空气间隙的磁芯
,都可以完成这个目标。
注意:当涡流与磁滞造成的损耗较大时,电感的特性更加类似于一个电阻器。除此之外,由于电感线圈存在着匝间电容,因而在某些情况下,还会呈现出类似于电容器的特性。
下面公式当中的 \(\frac{d I_L}{dt}\)表示的是通过电感的电流相对于时间的变化率,如果通过电感的电流不变,那么电感两端就不会存在着电压。如果一段时间内,流过电感的电流是直流,那么\(\frac{d I_L}{dt} = V_L =0\),因而直流条件下电感相当于短路。
\[V_L = L \times \frac{d I_L}{dt}\]
如果经过电感的电流 \(I_L\) 随着时间 \(t\) 发生变化,那么 \(\frac{d I_L}{dt} \neq0\),此时电感两端就会出现感应电压。
0 ~ 1 秒
这段时间内,电流的变化率为\(\frac{d I_L}{dt} = 1A/s\),如果电感系数 \(L =0.1H\),那么这段时间产生的感应电压 \(V = 0.1 H \times 1 A/s = 0.1V\);1 ~ 2 秒
这段时间内,电流保持恒定\(\frac{d I_L}{dt} = 0A/s\),因而这段时间产生的感应电压为 \(V = 0.1 H \times 0 A/s = 0\);2 ~ 3 秒
这段时间内,电流变化率为\(\frac{d I_L}{dt} = -1A/s\),则这段时间产生的感应电压 \(V = 0.1 H \times -1 A/s = -0.1V\);假设一个理想电感 \(L\) 与 10V
的电源 \(V_s\)通过一个开关进行连接:
当开关闭合的一瞬间,根据电感方程 \(V_L = L \times \frac{dI_L}{dt}\),可以推断出 \(\frac{dI}{dt}\)将会趋于无穷大,这就意味着感应电压的上升情况正比于电源电压,电路当中没有电流通过,反向电压为无穷大(下图上半部分)。同样的,如果把开关打开,则会产生一个无穷大的同向电压(下图下半部分)。
但是在现实世界当中,不可能出现无穷大的电压值,因为实际电感器上总是存在着内阻以及内部电容,所以下面的实际电感模型模型当中,就包含进了内阻
与电容
的参数。
电感方程之所以没有直接包含一个内阻项的原因,在于电感系数\(L\)是一个独立的参数,其大小只会与磁场能量的变化相关,而不会与线圈的电阻
与电容
损耗相关。分析诸如RL 和 RLC这类更为复杂的电路时,在电路当中使用分散的电阻,就可以防止电感方程出现奇异解。
当需要进行精确的分析时,如果必须考虑到电感的内阻,那么可以使用理想电感和电阻\(R_{DC}\)的串联来作为实际电感模型,这个串联的\(R_{DC}\)称为电感的直流电阻。如果需要进行更为精确的分析(例如高频电路场景),那就必须同时考虑到内阻和电容效应,此时可以再在理想电感上面并联一个电阻\(R_P\) 和一个电容\(C_P\),正如上面的示意图所展示的那样。
下面左图所示的 RL电路由电阻与电感串联组成,电阻会控制输入电感磁场的能量变化速率,而在磁场减小的时候,电阻也会控制能量释放回电路的速率。假设下图左侧电路的电阻\(R = 100Ω\),而电感\(L = 20mH\),开关闭合的瞬间 \(t =0\),则其电压
与电流
的响应曲线如下面右图所示:
上述 RL 充电电路的电流与电压方程如下所示,其中 \(\tau = \frac{L}{R}\)为时间常数,而常数e = 2.718
。除此之外,电流的单位为安培、电源电压\(V_S\) 与电阻电压\(V_R\) 以及电感电压\(V_L\)的单位都为伏特、电阻 \(R\)的单位为欧姆、电感系数 \(L\) 的单位为亨利、而 \(t\)表示接入电源之后的时间,其单位为秒。
\[\begin{aligned}I = \frac{V_S}{R}(1 - e^{-t/(L/R)}),\ &\frac{t}{(L/R)} = -\ln \big(\frac{1 - V_S/R}{V_S} \big) \\V_R = IR = V_S(1 - e^{-t/(L/R)}),\ &\frac{t}{(L/R)} = -\ln \big(\frac{V_R - V_S}{V_S} \big) \\V_L = L \frac{dI}{dt} = V_S \cdot e^{-t/(L/R)},\ &\frac{t}{(L/R)} =-\ln \big( \frac{V_L}{V_S} \big)\end{aligned}\]
运用基尔霍夫电压定律,对于闭合回路当中的电压
进行求和,就可以得到RL 电路的充电响应表达式:
\[V_S = IR + L \frac{dI}{dt} \implies \frac{dI}{dt} + \frac{R}{L} \times I= \frac{V}{L}\]
求解上述的非齐次微分方程,初始条件为开关闭合之前的电流\(I(0) = 0\),由此就可以求解得到电流\(I\) 的表达式:
\[I = \frac{V_S}{R}(1 - e^{-t/(L/R)})\]
将上面的 \(I\)代入欧姆定律和电感电压的表达式,分别就可以得到电阻电压\(V_R\) 与电感电压\(V_L\):
\[\begin{aligned}& V_R = I \cdot R = V_S(1 - e^{-t/(L/R)}) \\& V_L = L \cdot \frac{dI}{dt} = V_S \cdot e^{-t/(L/R)}\end{aligned}\]
这里假设电阻值为零,在没有电阻的情况下闭合开关,根据欧姆定律电流
将会持续增大,最终使得自感电压与电源电压相等。如果电路当中存在电阻,那么欧姆定律就会限制电流的大小,此时电感 \(L\)上产生的反向感应电压,必须等于电源电压与电阻电压之差;当电流接近欧姆定律所限制大小的时候,这个感应电压将会变得非常小;由于反向电压在理论上不可能完全消失,电流也不会完全达到欧姆定律所限制的大小。所以在实际情况下,该差值较短时间内就能够降低到可以被忽略的水平。
当电流达到最大值的 63.2%
时,所花费的时间就称为时间常数,其值 \(\tau\) 等于 \(\frac{L}{R}\),单位为秒。每经过1
个时间常数,电路都将会再传输 63.2%
的剩余电流,大约经过 5
个时间常数之后,就可以认为电流已经达到了最大值。
如果一个 RL 电路的电感为10mH
,串联电阻值为10Ω
,当该电路通电之后,电流达到最大值约需要经过5
个时间常数,所以 \(t = 5 \tau =5(L/R) = 5(10 \times 10^{-3}H) / 10Ω = 5.0 \times 10^{-3} 秒 = 50毫秒\)。当电感系数增加到 1.0H
的时候,所需要的时间则会增加到 0.5
秒。由于电路里的电阻值不变,所以两种情况下电流的最大值都相同。但是增大电感系数之后,电流达到最大值所需要的时间将会变长。下图给出了电路在拥有相同电阻不同电感的情况下,电流
的响应曲线:
断开开关之后,电感的磁场会随着电流的消失而消失,储存在磁场当中的能量将会被释放回电路。在开关断开的瞬间,由于感应电压与磁场的变化率呈正比,磁场骤降引发的感应电压通常比电源电压要大上许多倍,进而导致开关触点位置产生火花或者电弧。
当电路里的电感系数以及电流很大的时候,就会在短时间之内释放较大的能量,导致开关触点烧蚀熔化。如果在开关触点两端串联上电容
和电阻
,就可以抑制火花或者电弧,这样用途的RC电路被称为缓冲电路。下图左侧的电路可以在不断开电路的情况下移除电源激励,此时电流将会遵循下图右侧的波形,以及接下来的方程进行衰减:
对于上述的 RL放电电路,运用基尔霍夫定律,对闭合回路当中的电压进行求和,就可以得到如下的推导过程:
\[V_S = IR + L \times \frac{dI}{dt}\implies\frac{dI}{dt} + \frac{R}{L} \times I = \frac{V}{L}\]
对于上述的非齐次微分方程进行求解,并且假设初始条件为开关闭合之前的电流\(I(0)\),就可以求解得到电流 \(I\):
\[I(0) = \frac{V_R}{R} \implies I = \frac{V_S}{R} \cdot e^{-t(L/R)}\]
同样将上面的电流 \(I\)代入欧姆定律和电感电压表达式,就可以得到电阻电压 \(V_R\) 与电感电压 \(V_L\):
\[\begin{aligned}& V_R = I \cdot R = V_S \cdot e^{-t/(L/R)} \\& V_L = L \cdot \frac{dI}{dt} = - V_S \cdot e^{-t/(L/R)}\end{aligned}\]
类似于之前介绍过的 RL 充电电路,RL放电电路的电流响应也可以采用时间常数来进行表示。在5
个时间常数以后,就可以认为电感放电结束。
本小节第 1个电路里的开关断开,电流被切断,导致感性负载的磁场骤降,进而产生一个较大的同向感应电压。当该电压增大至一定程度时,开关触点之间的电压也将会变得很大,进而导致电火花的出现,此时的电流
与电压
响应曲线会比较复杂。而本小节第2 个电路中的开关从位置 A 移动至位置B,导致电源激励从电路当中断开,此时电流\(I\) 与电阻电压 \(V_R\)、电感电压 \(V_L\) 表达式分别为:
\[\begin{aligned}I = \frac{V_S}{R}e^{-t/(L/R)},\ &\frac{t}{(L/R)} = -\ln \big(\frac{I \times R}{V_S} \big) \\V_R = IR = V_S \cdot e^{-t/(L/R)},\ &\frac{t}{(L/R)} = -\ln \big(\frac{V_R}{V_S} \big) \\V_L = L \frac{dI}{dt} = - V_S \cdot e^{-t/(L/R)},\ &\frac{t}{(L/R)}= -\ln \big( \frac{V_L}{V_S} \big)\end{aligned}\]
该电路的电阻 \(R =100Ω\) 电感 \(L =20mH\),而上面方程当中的 \(L/R =\tau\) 为时间常数,常数e = 2.718
。电流的单位为安培,电源电压\(V_S\) 与电阻电压\(V_R\) 以及电感电压\(V_L\)的单位都为伏特,电阻 \(R\)的单位为欧姆,电感系数 \(L\) 的单位为亨利,而 \(t\)表示接入电源之后的时间,单位为秒。
无论 RL电路里的电感系数大小为多少,都会对输出信号造成影响。例如下图所示的RL电路当中,电感
与电阻
两端的输出信号,会随着电感系数的增大(放电时间延长),进而导致波形失真逐渐加剧:
接下来,把频率为1.0kHz
,周期为 \(T = \frac{1}{f} = \frac{1}{1000 Hz} =1ms\),电压为 0 ~ 5V
的方波电压源连接至电阻为 10Ω
的 RL电路,然后增大电感系数,观察波形的变化过程:
电感系数 \(L = 0.1mH\),时间常数\(\tau = \frac{0.0001H}{10Ω} =0.01ms\),此时 RL 电路的时间常数为周期的1%
,因而在方波由高到低和由低到高的变化过程当中,感应电压表现为窄尖峰波形。假设电感的充放电在5
个时间常数(即0.05ms
)以后完成,即在半个周期(0.5ms
)之内完成充放电,因而电阻电压的波形边缘会略带弧度:
电感系数 \(L = 1mH\),时间常数\(\tau = \frac{0.001H}{10Ω} =0.1ms\),此时 RL 电路的时间常数为周期的10%
,因而在电源电压的变化过程当中,感应电压呈指数规律进行升降的效果较为明显。其完全充放电所需的5
个时间常数为0.5ms
,正好是周期的一半。所以在每半个周期里,电感都可以完全吸收、释放其磁场能量:
电感系数 \(L = 10mH\),时间常数\(\tau = \frac{0.01H}{10Ω} =1ms\),此时 RL电路的时间常数与方波周期相等,但由于需要 5
个时间常数(即5ms
)来完成充放电过程,所以感应电压近似为线性变化,其波形按照指数函数进行小幅度升降。在半个周期之内,电感的磁场并不能完全吸收、释放其磁场能量:
电感系数 \(L = 1H\),时间常数\(\tau = \frac{1H}{10Ω} = 0.1s\),此时RL 电路的时间常数为周期的 100
倍,电感完全充放电所需的 5
个时间常数等于周期的500
倍。换而言之,电感没有足够的时间来完成充放电。虽然波形仍然呈指数规律升降,但是实际只占据初始值的\(\frac{1}{500}\),其波形可以近似为一条直线:
携带有诸如继电器
、螺线管
、电动机
等较大感性负载的电路当中,机械或者晶体管的开关操作经常会引发尖峰状的感应电压。即使电源电压较小的时候,所形成的尖峰电压也可以高达数百伏。尖峰电压会引发电弧,造成开关触点性能下降或者晶体管损坏。下图所示的电路,将一个可以让电流单向流动的二极管,并联至继电器
的线圈两端,从而在需要断开电路时,为尖峰电压提供缓冲路径:
通电的直线导体(非线圈)周围都会存在磁场,因而也就存在着自感系数,一段非磁性材料制成的直导线电感值为:
\[电感 L = 0.00508 \times 导线长度 b \bigg[ \ln \bigg(\frac{2 \times导线长度 b}{导线半径 a} \bigg) - 0.75 \bigg]\]
上面公式里的电感单位为毫亨 \(\mu H\),导线半径 \(a\) 与导线长度 \(b\)的单位为英尺(1 inch = 30.48 cm
),而 \(\ln\) 为自然对数。
直导线的电感值较小,通常被称为寄生电感。低频时寄生电感的电抗为零,例如10MHz
的时候,\(0.106 \muH\) 电感的电抗仅为 6.6Ω
;但是当频率上升至300MHz
时,其电抗就会上升至不容忽视的200Ω
。因而在高频电路当中,应当尽可能的缩短元件的引脚端。由于导线总是与元件相互串联,一个元件的寄生电感可以通过在该元件上串联一枚数值相近的电感器来模拟。
注意:超高频率(
30MHz ~ 300MHz
)电路当中,由于集肤效应的存在,上面的公式会有一些微小的改变。当频率接近于无穷大时,上述公式中的常数0.75
可以近似为1
。
如果两个电感线圈沿着相同的轴线进行放置,那么流过线圈1 的电流所形成的磁通将会通过线圈2。当线圈 1 的磁场强度发生改变时,线圈2上将会产生感应电压。这个感应电压类似于自感电压,由于属于外部线圈1的作用结果,因而被称为互感电压,而这种现象就被称作互感。
上述两个线圈的关系称为感应耦合,它们靠得越近,互感就会越强。如果两个线圈间隔较远,或者并不处于相同的轴线上面,那么互感就会相对较弱,此时两个线圈称为松耦合。
互感系数的实际值与其最大值的比值,称为耦合系数,通常采用分数来进行表示。如果将一个空芯线圈缠绕在另一个空芯线圈的上面,那么两个线圈的耦合系数将会达到0.6 ~ 0.7
。如果将它们分开进行放置,那么耦合系数就会相对较小。当线圈绕制在闭合磁芯上面的时候,其耦合系数甚至可以达到100%
。
注意:互感原理主要应用于变压器当中,而在设计电路的时候,互感现象会产生一些不良后果。例如元件位置靠得太近的时候,或者感性负载、大电流交流电缆造成外部磁场波动的时候,电路当中就会出现错误的互感电压信号干扰。
当两个或者两个以上的电感器串联时(电感之间需要保持一定距离,避免相互之间的磁场干扰):
总电感量 \(L_{total}\)等于每一个串联电感器上面的电感量之和:
\[L_{total} = L_1 + L_2 + L_3 + ... + L_n\]
上述串联电感的计算公式,也可应用基尔霍夫电压定律推导得出,将电感\(L_1\) 的电压记为 \(L_1 \frac{dI}{dt}\),电感\(L_2\) 的电压记为 \(L_2 \frac{dI}{dt}\),电感\(L_3\) 的电压记为 \(L_3 \frac{dI}{dt}\),那么下面公式当中的\((L_1 + L_2 + L_3)\)部分就是串联等效电感:
\[V = L_1 \frac{dI}{dt} + L_2 \frac{dI}{dt} + L_3 \frac{dI}{dt} = (L_1 +L_2 + L_3) \frac{dI}{dt}\]
当两个或者两个以上的电感器进行并联时(电感之间同样保持一定距离,避免相互之间的磁场干扰):
总电感量 \(L_{total}\)的倒数就等于每一个并联电感器上面电感量的倒数之和:
\[\frac{1}{L_{total}} = \frac{1}{L_1} + \frac{1}{L_2} + \frac{1}{L_3} +... + \frac{1}{L_n}\]
如果当前只存在两个电感器进行并联,那么上述的计算公式就可以简化为如下形式:
\[L_{total} = \frac{L_1 \times L_2}{L_1 + L_2}\]
该并联电感的计算公式,可以采用基尔霍夫电流定律推导获得。由于并联电流\(I = I_1 + I_2 + I_3\),并且电感 \(L_1\)、\(L_2\)、\(L_3\)之间的端电压相等,各个并联电感器上的电流可以分别表示为 \(I_1 = \frac{1}{L_1} \int Vdt\)、\(I_2 = \frac{1}{L_2} \int Vdt\)、\(I_3 = \frac{1}{L_3} \int Vdt\),那么电流\(I\) 就可以表示为如下形式,其中的\((\frac{1}{L_1} + \frac{1}{L_2} +\frac{1}{L_3})\) 部分就是并联等效电感:
\[I = I_1 + I_2 + I_3 = \frac{1}{L_1} \int Vdt + \frac{1}{L_2} \int Vdt +\frac{1}{L_3} \int Vdt= \bigg( \frac{1}{L_1} + \frac{1}{L_2} + \frac{1}{L_3} \bigg) \int Vdt\]
▶【例题】下图所示电路的等效总电感值为 70mH
,求解电感\(L_2\) 的值 ?
◉【解】根据上面电路图里的参数与题设条件,经过如下的一系列推导步骤,就可以计算出\(L_2\) 的电感值等于30mH
:
\[L_{total} = L_1 + \frac{L_2 \times L_3}{L_2 + L_3}\implies70mH = 50mH + \frac{60mH \times L_2}{60mH + L_2}\impliesL_2 = 30mH\]
当在理想电感器两端接入交流电压的时候,经过电感器的电流会滞后于电压,这与交流信号下电容器的特性正好相反。下图为理想电感电路当中的交流信号的电流、电压、功率曲线:
造成滞后的根本原因在于电感器产生了反向电压,由于反向电压的大小与电流的变化率呈正比:
0 ~ A
时间段,电源电压为正向最大值,反向电压(感应电压)也为最大值,此时经过的电流最小,但是电流的变化率达到了38%
的最大值;A ~ B
时间段,电流变化了33%
,感应电压与电源电压同步减小。该过程会在B ~ C
与 C ~ D
时间段持续进行,随着电源电压以及感应电压趋于零,电流仅仅只增加了8%
;D ~ E
时间段,电源电压改变了方向,感应电压也会相应的改变方向。伴随着磁场的减小,电流开始返回电路,此时电流的方向与电源电压方向相反,但是仍然处于正向。随着电源电压在反方向继续增大,正向的电流值开始减小,当电源电压为反相最大值时电流为零;90°
;类似于容抗,感抗是电感
与交流信号频率
的综合效应,其单位也采用欧姆Ω
,具体的计算公式如下面所示:
\[感抗 X_L = 2 \pi \times 频率 f \times 电感 L\]
上述公式当中的 \(\pi =3.1416\),频率 \(f\) 的单位为赫兹Hz
,电感 \(L\) 的单位为亨利H
。除此之外,感抗还可以采用角频率来进行描述:
\[感抗 X_L = 角频率 \omega \times 电感 L\]
为了使得计算更加简便,可以采用余弦函数代替正弦函数,例如电源电压的表达式为\(V_0 \cos (\omegat)\),则电感元件上面经过的电流 \(I\) 等于:
\[I = \frac{1}{L} \int Vdt = \frac{1}{L} \int V_0 \cos(\omega t) dt= \frac{V_0}{\omega L} \sin(\omega t)\]
当上面等式当中的 \(\sin(\omega t) =1\) 的时候,电感上经过的电流将会达到最大值 \(I_0 = \frac{V_0}{\omegaL}\)。峰值电压与峰值电流的比值具有欧姆Ω
的量纲,其体现了反向感应电压抵抗正向电压的效应,这种效应就称之为感抗:
\[X_L = \frac{V_0}{I_0} = \frac{V_0}{\frac{V_0}{\omega L}} = \omega L\]
当角频率 \(\omega\)趋向于无穷大时,感抗 \(X_L\)也将会趋于无穷大,此时电感相当于开路,说明电感会阻碍高频信号的通过。但当角频率 \(\omega\)趋于零的时候,感抗 \(X_L\)也将会趋于零,说明低频信号可以轻松的通过。
注意:在理想电感通过直流信号的情况下,就不需要考虑到阻抗的概念。
下图分别为 \(1\mu H\)、\(10\mu H\)、\(100\mu H\)电感器的感抗
,伴随着频率
进行变化的对数坐标图。可以看到其响应曲线呈线性。当频率
增大的时候,对应的感抗
也会随之呈正比增大:
由于实际电感器的内部存在着寄生电阻与寄生电容,因而真实的感抗响应曲线将会比较复杂,下图为实际电感器的阻抗
伴随着频率
进行变化的曲线:
注意:当频率接近电路的振荡频率时,阻抗曲线就不会再呈现为线性,而是达到峰值之后就开始下降,后续振荡电路部分的内容将会对其进行更为详细的介绍。
实际电感模型可以通过串联电感 \(L\)、串联电阻 \(R_{DC}\)、并联电容 \(C_P\)、并联电阻 \(R_P\) 四个无源理想元件来进行模拟:
0
(即阻抗表现为纯电阻)求解得到,或者也可以通过品质因数Q 进行求解;线圈
与引脚
之间的分布电容;当电感通过交流信号的时候,电感两端的电压将会发生变化,其作用等效于多个电容与电感线圈的并联。下图展示了分布电容与电感发生谐振时的曲线,低于谐振频率时阻抗呈感性,其值随着频率的增大而减小;而高于谐振频率时阻抗呈容性,其值会随着频率的增大而增大:
注意:实际电感器往往存在着多种形式的损耗,例如
导线电阻损耗
、磁芯损耗
、集肤效应损耗
。除此之外,当交流信号的频率增大时,电流将会集中到导体的表面,这种特性称为集肤效应,因而电感线圈还存在着集肤效应引发的损耗。
电容与电感这类储能元件的性质,都可以采用品质因数Q来进行描述,其值等于储能元件存储的能量(感抗)与消耗能量(电阻)的比值:
\[品质因数 Q = \frac{电抗 X}{电阻 R}\]
注意:上述方程当中的品质因数 Q没有量纲,而 \(X\)为电抗(
感抗
或者容抗
),电阻\(R\)表征电感元件实际损耗的全部能量。
电容器通常具备较高的 Q 值,例如陶瓷电容器的Q 值可以达到 1200
以上。而电感的品质因数为\(Q = \frac{2 \pi fL}{R_{DC}}\),当电路当中同时包含有电感
和电容
时,电感的Q 值并不会等于电容的 Q 值。
注意:多数情况下,电路都会要求使用更高品质因数的电感,然而有些电路则会要求使用比较特殊的Q 值参数。
感性分压器经常被应用在输入交流信号的电路当中,根据电阻分压的原理,交流输入电压将会按照两个电感的电阻关系进行分配,具体请参考下面的电路图与公式:
注意:上述电路的输出电压与输入频率无关,但是如果电感器的感抗在指定工作频率上不够高(即电感值不够大),那么并联元件\(L_2\)将会如同短路,从而产生非常大的电流。
电子学当中,电感器的基本功能是以磁场的形式存储电量,电感器与电容器等其它元件组合起来,就可以形成用于滤除特殊频率信号的滤波器。除此之外,两个或者两个以上的耦合线圈,还可以构成用于对交流电压进行升压与降压的变压器。而在开关电源当中,电感器可以控制稳压器在开关频率的特定部分进行充电,而在剩余的周期内进行放电,充放电比例决定了输出与输入电压的比值。
下图所示的电路当中包含有电阻
、电容
、电感
,以及正弦电压源
:
应用基尔霍夫电压定律就可以得到下面的推导过程:
\[V_0 \cos (\omega t) = IR + L \frac{dI}{dt} + \frac{1}{C} \int I dt\impliesL\frac{d^2 I}{dt^2} + R \frac{dI}{dt} + \frac{1}{C} I = - \omega V_0\sin(\omega t)\]
上述等式是一个二阶线性非齐次常微分方程,通过参数变换
或者待定系数法
求解方程,并将求解得到的电流代入电阻、电容、电感的电压
与电流
关系方程,通过繁杂的数学运算就可以求解得到各个元件上的电压。上面这个电路相对较为简单,而对于下图这种较为复杂的电路,如果继续运用基尔霍夫定律对回路与节点列写微分方程,那么涉及的运算将会变得极为复杂:
注意:通过复阻抗的概念以及相应的复数运算,就可以完全规避复杂的微分方程求解过程。
一个采用正弦电源作为激励的电路,所有的电压
与电流
都是正弦量,它们会与正弦电压源的输出同频率变化。如果电路当中存在电容器和电感器,那么电压
与电流
的幅值与电压源
的幅值成正比,而电压
与电流
的波形相对于电压源
的波形存在着相位差。利用正弦电路的电压
与电流
都属于同频率正弦量的特点,就可以避免以求解微分方程的方式来分析动态电路。
叠加原理指出在具有多个正弦电源的线性电路当中,任意一个支路上的电流
等于各个电源单独作用时产生的电流之和。利用基尔霍夫定律可以证明这个结论,将基尔霍夫定律应用于线性电路,从而得到一组线性方程,将它们简化为只包含有1个未知数的单一方程,如果未知量是支路电流,那么可以将其表达为具有适当系数的各个电源的叠加。换而言之,就是无需再计算时间相关的未知量,由于这些未知量的形式总是\(\cos(\omega t +\varPhi)\),因而只需要计算其峰值(或者RMS均方根值)以及相位角,再运用叠加原理进行求解即可。
具有相同频率、不同相位的两个正弦波叠加,得到的将会是一个具有相同频率的新正弦波:
而对于频率不同的正弦波,叠加之后得到的将不再是一个正弦波:
频率相同、相位不同的两个方波,叠加之后所获得的并不一定就是一个方波:
本文在《数学预备知识》章节,介绍过采用复数表示正弦量的相关概念。例如,当\(\theta\) 在 \(0° \sim 360°\) 范围变化时,复数的三角形式\(z = r \cdot \cos \theta + j \times r \cdot\sin \theta\)在复平面上的轨迹是一个圆周。如果取\(z\) 相对于 \(\theta\)的实部来绘制曲线,就可以得到一个正弦波;而通过改变\(r\)的值,就可以改变正弦波的幅值;让 \(\theta\)乘以一个系数,就可以改变正弦波的频率;让 \(\theta\)加上一个数值(度
或者弧度
),就能够与同频率的正弦波产生相位差。
注意:如果将 \(\theta\) 替换为 \(\omega t\)(其中 \(\omega = 2 \pi f\)),把 \(r\) 替换为 \(V_0\),同时为 \(\omega t\)添加相位差,就可以得到以复数形式表示的电压源,采用类似的办法也可以表示电流源。
相比于正弦函数,复数的优势在于可以采用多种形式(直角坐标系
、三角
、指数
、极坐标
)进行表示,从而简化叠加过程当中的数学运算。例如,将复数转化成直角坐标形式
之后,就可以容易的进行加减运算,而转化为指数形式与极坐标形式,则可以很容易的进行乘除运算。
电流
与电压
的值事实上都属于实数,并不存在虚数的电压
与电流
。之所以存在虚部是因为需要引入相位的概念,所以采用复数形式进行叠加之后,所得到的最终结果必须转换为实数,即必须将复数结果转换为三角形式
、指数形式
、极坐标形式
,并且移除虚部。例如下面等式当中的电压采用RMS 均方根值,将等式左侧的复数,转换为右侧的指数和极坐标形式:
\[V(t) = 5V + j10V \implies\sqrt{(5.0V)^2 + (10.0V)^2} e^{j 63.4°}\approx (11.2V) e^{j 63.5°}= 11.2V \angle 63.5°\]
经过上述推导过程,就可以得到电压 \(V(t)\) 的 RMS 值为11.2V
,由于相位 \(\angle 63.5°\)往往无关紧要,所以这里直接将其忽略。
假设正弦电压为 \(V_0 \cos (\omegat)\),其中 \(\omega = 2 \pif\),将其转换为 \(V_0 \cos (\omega t) +j V_0 \sin(\omega t)\),这个等式当中的 \(j V_0 \sin(\omega t)\)是没有任何物理意义的虚数,虽然不会影响到实际的电压表达式,但是在叠加计算过程当中会使用到它。接下来为了便于计算,需要使用欧拉公式\(e^{j \theta} = r \cos(\theta) + jr\sin(\theta)\)将三角形式转换为指数形式 \(V_0 \cdot e^{j(\omegat)}\),或者极坐标形式 \(V_0 \angle (\omega t)\)。
上述的电压可以在复平面当中,采用一个角频率为 \(\omega\),并且沿着逆时针方向旋转的矢量来进行表示。其中,矢量长度表示电压\(V_0\)的最大值,而该矢量在实轴的投影表示 \(V\)的实部
或者瞬时值
,在虚轴上的投影表示的则是\(V\) 的虚部
:
得到电压的复数表达式之后,分别将其代入电阻(\(I =\frac{V}{R}\))、电容(\(I = C\frac{dV}{dt}\))、电感(\(I = \frac{1}{L} \intVdt\))的表达式,进而分别得到电流的复数表达式,比较每种元件的电流
以及电压
的相位差,就能够得到下面的示意图:
电压
与电流
同相,相位差\(\varPhi =0°\),该特性也可以在复平面上表示,其中电压
与电流
的矢量都具有相同的辐角,两者都以角频率\(\omega = 2 \pi f\)沿逆时针方向进行旋转;电流
的相位大于电压
有+90°
,即电流
超前于电压
有90°
,通常规定相位差 \(\varPhi\)为从电流矢量
指向电压矢量
的角度,当 \(\varPhi\)为正时电流超前,当 \(\varPhi\)为负时电流滞后;电流
的相位大于电压
有-90°
,即电流
滞后于电压
有90°
;这种在复平面上采用电压
与电流
的幅值与相位角表示的图形称为相量图,相量与依赖于时间的数学函数不同,它只是提供了某一个瞬间或时刻的相位
与幅值
。接下来,再介绍一种重要的交流电路分析方法,如果分别将电阻
、容抗
、感抗
元件上的电压
除以电流
,就可以得到下图所示的结果:
注意:上图当中的 \(V_0\cdot e^{j(\omega t)}\)项被消去,得到
电阻
、容抗
、感抗
的复数形式。这些表达式只是频率
的函数,而与时间
无关,从而避免求解微分方程。
正弦激励电路当中,把容抗
与感抗
表示为复数,就可以将电容
和电感
视为频率敏感的电阻,采用这些电阻替代直流电路当中的电阻,再将直流电源切换为正弦电源,并将所有的电压
、电流
、电阻
、阻抗
转换为复数形式,分别代入欧姆定律
、基尔霍夫定律
、戴维南定理
等电路定理建立方程,通过简单的复数运算就能够进行求解。例如交流欧姆定律可以表示为\(V(\omega) = I(\omega) \timesZ(\omega)\),其中的 \(Z\)就是复阻抗,一种以复数形式描述元件对于电流阻碍作用的方法。复阻抗可以只是电阻
、容抗
、感抗
,也可以是电阻
与电抗
元件的组合:
\[\begin{cases}电阻 &V_R = I_R \times R \\电容 &V_C = I_C \times X_C = I_C \big( - j \frac{1}{\omega C} \big)= - j \frac{I_C}{\omega C} = \frac{I_C}{\omega C} \angle -90° \\电感 &V_L = I_L \times X_L = I_L (j \omega L) = j I_L \omega L = I_L\omega L \angle + 90° \\复阻抗 &V_Z = I_Z \times Z\end{cases}\]
下图展示了之前讨论过的正弦电压源的相量表示,以及电阻
、电容
、电感
的复阻抗:
将复阻抗视为频率敏感的电阻,通过串联电阻的等效公式,就可以求解得到复阻抗串联之后的等效复阻抗\(Z_{total}\):
\[Z_{total} = Z_1 + Z_2 + Z_3 + ... + Z_N\]
换而言之,之前的直流分压电路,可以转变成一个交流分压电路:
相应的,将 \(N\)个复阻抗进行并联,其等效阻抗 \(Z_{total}\) 的表达式如下所示:
\[Z_{total} = \frac{1}{\frac{1}{Z_1} + \frac{1}{Z_2} + \frac{1}{Z_3} + ...+ \frac{1}{Z_N}}\]
特别的,如果当前只有两个复阻抗进行并联,那么上述公式可以简化为下面的形式:
\[Z_{total} = \frac{Z_1 Z_2}{Z_1 + Z_2}\]
同样的,之前的直流分流电路,也可以转变为一个交流分流电路:
更为重要的是,可以将复阻抗代入基尔霍夫电压定律,通过建立回路方程来求解拥有多个节点的复杂电路:
▶【例题】下图的 RL 串联电路由一个输出电压为 12VAC
(RMS均方根值),频率为 60Hz
的电源激励,已知电路当中的电感\(L = 265mH\),电阻 \(R = 50Ω\),求解 \(I_S\)、\(I_R\)、\(I_L\)、\(V_R\)、\(V_L\),以及视在功率
、有功功率
、无功功率
、功率因数
?
◉【解】首先,计算出感抗 \(X_L\):
\[X_L = j \omega L = j(2 \pi \times 60Hz \times 265 \times 10^{-3} H) = j100Ω\]
◉【解】因为该电路当中的电阻与电感串联,所以采用直角坐标形式的复数相加,进而得到等效阻抗\(Z\):
\[Z = R + X_L = 50 Ω + j100 Ω\]
◉【解】接下来,再将上面求解得到的等效阻抗 \(Z\) 转换为极坐标形式:
\[Z = \sqrt{50^2 + 100^2} \angle \arctan \big( \frac{100}{50} \big) = 112Ω\angle 63.4°\]
◉【解】利用交流欧姆定律,就可以求解得到电流 \(I_S\):
\[I_S = \frac{V_S}{Z_{total}} = \frac{12 VAC \angle 0°}{112Ω \angle 63.4°}= 0.107A \angle -63.4°\]
◉【解】上面等式当中的 -63.4°
表示电流滞后于电源电压,由于串联电路当中 \(I =I_R =I_L\),利用交流欧姆定律和分压公式就可以求解出电阻\(R\) 与电感 \(L\) 两端的电压:
\[\begin{cases}V_R = I \times R = (0.107A \angle -63.4°)(50Ω \angle 0°) = 5.35 VAC\angle -63.4° \\V_L = I \times X_L = (0.107A \angle -63.4°)(100Ω \angle 90°) = 10.7 VAC\angle 26.6°\end{cases}\]
◉【解】以上步骤计算的是当 \(t = 0\)时刻,电源电压 \(V_S = 12 VAC\angle 0°\) 情况下的值。如果需要绘制精确的波形,那么就需要将\(\omega t\)代入电源电压的表达式,并且将有效值乘以 1.414
得到 \(V_S = 17.0V \angle(\omegat)\),该结果描述了电压随着时间的连续变化过程。接着再将这个结果转换为三角形式,去掉虚部就可以得到\(V_S = 17.0 V \cos (\omegat)\)。参照电源电压 \(V_S\)的推导过程,将其它电压
与电流
的波形全部列写为三角形式,再代入相应的峰值与相位角,就可以获得如下的波形与计算结果:
注意:峰值电压与电流等于其有效值乘以
1.414
,例如 \(V_P = 1.414 \timesV_{RMS}\)。
◉【解】根据上述推导结果,还可以获得该电路上面总阻抗的视在功率\(VA\)、电阻消耗的有功功率\(P_R\)、电感上的无功功率\(VAR\)、功率因数\(PF\),接下来的章节将会逐一介绍这些内容:
\[\begin{cases}总阻抗的视在功率 VA &= I_{RMS} \times V_{RMS} = (0.107A) \times (12VAC) = 1.284 VA \\电阻消耗的有功功率 P_R &= I_{RMS}^2 R = (0.107A)^2 \times (50Ω) =0.572 W \\电感上的无功功率 VAR &= I_{RMS}^2 X_L = (0.107A)^2 \times (100Ω) =1.145 VAR \\功率因数 PF &= \frac{P_R}{VA} = \cos(\phi) = \cos(-63.4°) = 0.45\end{cases}\]
注意:上述方程当中的 \(\phi\) 表示的是 \(V_S\) 与 \(I_S\) 之间的相位差。
上述示例当中,电阻电压 \(V_R\)与电感电压 \(V_L\) 的代数和等于 \(5.35VAC + 10.70VAC = 16.05VAC\),该结果要大于电源电压 \(V_S =12VAC\),似乎并不满足基尔霍夫电压定律。这是由于没有考虑到相位角的因素造成的,纳入相位角之后的正确计算结果如下所示:
\[\begin{aligned}V_{total} &= V_R + V_L = (5.35 VAC \angle - 63.4°) + (10.70 VAC\angle 26.6°) \\&= 2.4 VAC - j 4.8 VAC + 9.6 VAC + j 4.8 VAC \\&= 12 VAC\end{aligned}\]
下图当中的电压信号波形,非常直观的展示了波形的幅度与相位之间的对应关系:
对于含有电阻
、电感
、电容
元件的复杂电路,将之前介绍过的功率定理\(P = I_{RMS} \times V_{RMS}\) 当中的\(P\) 更换为 \(VA\),就可以得到视在功率的计算公式:
\[视在功率 VA = I_{RMS} \times V_{RMS}\]
可以看到视在功率 VA
的计算公式与普通交流功率的计算公式相同,之所以使用 VA
而不使用P
,是由于计算出的功率值并不只是消耗了有功功率,因而不能使用以瓦特
作为单位的有功功率来进行表示,而应当使用伏安VA
作为其单位。
视在功率同时包含了电阻消耗的有功功率和无功功率。其中,有功功率是电流经过电阻时所产生的热损耗,其单位为瓦特W
,可以由交流欧姆定律代入功率定理之后得到的方程进行定义:
\[有功功率 P_R = I^2_{RMS} R\]
而无功功率不表示功率的消耗,其与电感器当中储存的磁场能量,以及电容器当中储存的电场能量存在着联系。当电感器的磁场减弱或者电容器进行放电时,它们当中储存的能量又会释放回电路当中。无功功率采用乏VAR
来作为其单位,把上述欧姆功率定理当中的电阻
或阻抗
部分更换为电抗\(X\),就可以得到无功功率的定义:
\[无功功率 VAR = I^2_{RMS} X\]
为了简化计算过程,下面直接给出无功功率、有功功率、视在功率之间相互进行转换的关系式:
\[视在功率 VA = \sqrt{有功功率 P_R^2 + 无功功率 VAR^2}\]
功率因数也是一种用于描述视在功率
和无功功率
的术语,电路的功率因数\(PF\)等于电路消耗的功率与视在功率的比值,通常以百分数 \(\%\) 格式来进行表示:
\[功率因数 PF = \frac{电路消耗功率 P_{consumed}}{视在功率 P_{apparent}} =\frac{P_R}{VA}\]
纯电阻电路的功率因数等于 \(100\% =1\),而纯电抗电路的功率因数则等于 \(0\)。由于功率因数总是为正数,所以必须明确的标识当前电压
与电流
之间的相位关系是超前还是滞后。除此之外,功率因数还可以表示为电压
与电流
之间相位差\(\phi\) 的形式:
\[功率因数 PF = \cos \phi\]
除了功率因数之外,还有另外一个用于描述电抗当中无功功率
所占百分比的术语,称为无功因数:
\[RF = \frac{P_{reactive}}{P_{apparent}} = \frac{无功功率 VAR}{视在功率VA} = \sin(\phi)\]
戴维南定理同样可以应用于交流线性电路的分析,对于任意包含有电阻
、电容
、电感
元件的复杂网络,都可以等效为一个正弦电压源与复阻抗的串联。例如求解复杂正弦电路当中两点之间的电压,或者某个元件上的电流
与电压
,只需要移除该元件,并求解出戴维南等效电压\(V_{THEV}(t)\),再将原来的正弦电源直接采用导线进行短路,进而求解出戴维南等效复阻抗\(Z_{THEV}(t)\)及其对应的戴维南等效电路。下图左侧是一个包含有电阻
、电容
、电感
元件的复杂电路,而右侧是该电路所对应的戴维南等效电路:
▶【例题】求解下图所示电路当中流过电阻的电流 \(I_R\) ?
◉【解】首先,移除电阻,使得电路成为拥有两个外接端子的黑盒子:
◉【解】然后,再分别计算其容抗 \(X_C\) 与感抗 \(X_L\) :
\[\begin{aligned}&X_L = j \omega L = j(2\pi \times 1000Hz \times 200 \times 10^{-3})= j 1257Ω \\&X_C = - j \frac{1}{\omega C} = -j \frac{1}{2\pi \times 1000Hz\times 20 \times 10^{-9}F} = -j 7958Ω\end{aligned}\]
◉【解】接下来,运用交流分压公式计算出开路电压,也就是戴维南等效电压\(V_{THEV}\):
\[\begin{aligned}V_{THEV} = V_C &= \bigg( \frac{X_C}{X_C + X_L} \bigg) \times V_S =\bigg( \frac{-j 7958 Ω}{-j 7958 Ω + j 1257 Ω} \bigg) \times 10 VAC \\&= \bigg( \frac{7958 \angle -90°}{6701 \angle -90°} \bigg) \times 10VAC= 11.88 VAC \angle 0°\end{aligned}\]
◉【解】再将正弦电源短路,得到其等效阻抗\(Z_{THEV}\)为电容
与电感
的并联:
\[\begin{aligned}Z_{THEV} &= \frac{X_C \times X_L}{X_C + X_L} = \frac{-j7958Ω \timesj1257Ω}{-j7958Ω + j1257Ω} \\&= \frac{(7958Ω \angle -90°) \times (1257Ω \angle -90°)}{(6701Ω\angle -90°)}= \frac{10003206Ω^2 \angle 0°}{6702Ω \angle -90°} \\& = 1493 Ω \angle 90° = j(1493)Ω\end{aligned}\]
◉【解】最后,把负载电阻与戴维南等效电路进行连接,得到如下的等效电路:
◉【解】根据戴维南等效电压 \(V_{THEV}\) 与电阻 \(R\)的串联关系,就可以求解出总阻抗 \(Z_{total}\):
\[Z_{total} = R + Z_{THEV} = 3300Ω + j 1493 Ω = 3622 Ω \angle 24.3°\]
◉【解】基于交流欧姆定律,就可以求解得到经过电阻的电流\(I_R\) 等于:
\[I_R = \frac{V_{THEV}}{Z_{total}} = \frac{11.88 VAC \angle 0°}{3622Ω\angle 24.3°} = 3.28mA \angle -24.3°\]
◉【解】上述的计算结果表明,电阻上的电流 \(I_R\) 等于3.28mA
,并且滞后于电源电压24.3°
。如果需要将瞬时值转换为时间相关的实数函数,那么就要把\(\omega t\)添加到每一个相位角表达式,并且将 RMS值转换为真实值:
◉【解】根据上述的计算结果,还可以求解得到该电路对应的视在功率、有功功率、无功功率、功率因数:
\[\begin{cases}视在功率 VA &= I_S^2 \times Z_{total} = (0.00328 A)^2 \times 3622 Ω= 0.039 VA \\有功功率 P_R &= I_R^2 \times R = (0.00328 A)^2 \times 3300 Ω = 0.035W \\无功功率 VAR &= I_R^2 × Z_{THEV} = (0.00328 A)^2 \times 1493 Ω =0.016 VAR \\功率因数 PF &= \frac{P_R}{VA} = \cos(\phi) = \cos(-24.3)° =0.91(滞后)\end{cases}\]
如果在 LC电路的两端电路添加正弦电压源,那么当电源的频率等于谐振频率时,就会发生一些有趣的现象。
下图所示的 LC 串联电路的谐振角频率 \(\omega_0 = 1 \sqrt{LC}\)或者等效谐振频率 \(f_0 =\frac{1}{2\pi/LC}\) 的时候,该 LC电路的等效阻抗将会趋于零,即相当于短路,此时流过电源的电流达到最大值。理想状况下,这个电流将会趋于无穷大,但是实际上电路内电阻会将其限制在一定的范围。
这里先求解出上述电路的等效阻抗,由于其频率未知,因而等效阻抗\(Z_{total}\) 必须被视为一个变量:
\[等效阻抗 Z_{total} = 感抗 X_L + 容抗 X_C = j \omega L - j\frac{1}{\omega C} = j \bigg(\omega L - \frac{1}{\omega C} \bigg)\]
这个等效阻抗 \(Z_{total}\)对应的极坐标形式如下面所示(任意数除以 0
的反正切为 90°
,所以下面的阻抗相位角也等于90°
):
\[Z_{total} = \bigg( \omega L - \frac{1}{\omega C} \bigg) \angle 90°\]
此时,经过并联等效阻抗 \(Z_{total}\)的电流 \(I\) 为:
\[I = \frac{V_S}{Z_{total}} = \frac{10 VAC \angle 0°}{\omega L -\frac{1}{\omega C}} \angle -90°= \bigg[ \frac{10 VAC}{\omega L - \frac{1}{\omega C}} \bigg] \angle -90°\]
如果代入电感 \(L = 100 \muH\)、电容 \(C =62.5nF\)、角频率 \(\omega = 2 \pif\),并且不考虑相位角的因素,那么总阻抗\(|Z_{total}|\) 与电流\(|I|\) 分别等于:
\[\begin{cases}|Z_{total}| = 6.28 \times 10^{-4} f - \frac{2546479}{f} Ω \\|I| = 10 VAC \div \big[ 6.28 \times 10^{-4} f - \frac{2546479}{f} \big]Ω\end{cases}\]
可以看到,阻抗与电流都属于频率的函数,其波形如下图所示:
值得注意的是,当上述方程当中的频率等于谐振频率\(f_0 = \frac{1}{2\pi \sqrt{LC}} =\frac{1}{2\pi \sqrt{(100 \times 10^{-6}H)(62.5 \times 10^{-9}F)}} =63663 Hz\)的时候,其阻抗等于零,同时电流趋于无穷大(实际情况下,电路内阻会限制电流大小)。电路发生谐振时,感抗与容抗的大小相等相位相反,具体请参见如下方程:
注意:LC串联电路在发生谐振时,电容与电感两端的电压大小相等相位相反,意味着它们串联之后的有效电压降等于零,两端的阻抗也就一定等于零。
下图所示并联 LC 电路的谐振角频率 \(\omega_0 =\frac{1}{\sqrt{LC}}\),等效谐振频率 \(f_0 = \frac{1}{2\pi / \sqrt{LC}}\),与 LC串联电路谐振频率的表达式相同,但是作用的效果却完全相反,发生谐振时不再是阻抗趋于零,电流趋于无穷大。而是电阻趋于无穷大,电流趋于零,即相当于开路。实际情况下,由于电路当中内电阻
、寄生电容
、寄生电感
的存在,这种开路现象并不会真实发生。
\[等效阻抗 Z_{total} = \frac{感抗 X_L \times 容抗 X_C}{感抗 X_L + 容抗X_C}= \frac{(j \omega L)(-j \frac{1}{\omega C})}{j \omega L - j\frac{1}{\omega C}}= \frac{\frac{L}{C}}{j(\omega L - \frac{1}{\omega C})}= -j \frac{\frac{L}{C}}{(\omega L - \frac{1}{\omega C})}\]
将上述结果改写为极坐标形式(任意负数除以0
的反正切为-90°
,所以下面的阻抗相位角也等于 -90°
):
\[Z_{total} = \frac{\frac{L}{C}}{(\omega L - \frac{1}{\omega C})} \angle-90°\]
此时,流入并联阻抗的电流等于 \(I\):
\[I = \frac{V_S}{Z_{total}} = \frac{10 VAC \angle 0°}{\frac{L/C}{\omega L- 1 / \omega C}\angle - 90°}= \bigg[ \frac{10 VAC}{\frac{L/C}{(\omega L - 1 / \omega C)}} \bigg]\angle 90°\]
同样代入电感 \(L = 100 \muH\)、电容 \(C =62.5nF\)、角频率 \(\omega = 2 \pif\),如果不考虑相位角,那么总阻抗 \(|Z_{total}|\) 和电流 \(|I|\) 分别为:
\[\begin{cases}Z_{total} = 1600 \div \big(6.28 \times 10^{-4} - \frac{1}{3.92 \times10^{-7}} \big) Ω \\I = 0.00625 \times \big(6.28 \times 10^{-4} - \frac{1}{3.92 \times10^{-7}} \big) A\end{cases}\]
可以看到,阻抗与电流也同样是频率的函数,对应的波形如下图所示:
当上述方程当中的频率等于谐振频率\(f_0 = \frac{1}{2\pi \sqrt{LC}} =\frac{1}{2\pi \sqrt{(100 \times 10^{-6}H)(62.5 \times 10^{-9}F)}} =63663 Hz\)的时候,其阻抗趋于无穷大,同时电流等于零。当频率趋近于零的时候,电感相当于短路,电流趋于无穷大;而当频率趋近于无穷大的时候,电容也相当于短路,同样会导致电流趋于无穷大(实际情况下,电路内阻
、寄生电感
、寄生电感
会限制电流的大小)。
发生谐振时,由于电容 \(C\) 和电感 \(L\) 的阻抗 \(X_C = X_L\) 与电压 \(V_C = V_L\)相等,但是相位相反。由此可知,流过电感\(L\) 与电容 \(C\)的电流同样大小相等方向相反。即流过电感的电流从电容上端流入,经过电容之后又从电感的下端流入,下一个时刻电流发生反相,能量沿着相反的方向释放。此时,电容与电感的作用类似于振荡器,来回传递相同的能量,该能量的大小取决于电感与电容的大小,这种在LC回路当中来回流动的电流被称为循环电流。此时由于电源两端的电位差较小,所以经过电源的电流也比较小。换而言之,如果希望LC电路提供一个外部电流,那么就意味着电感与电容元件必须存在电位差。但是发生谐振的时候,由于流过电感与电容的电流相等而方向相反,因而无法对外提供电流。
▶【例题】如果一个谐振电路的电感为 \(5.0 \muH\) 而电容为 \(35pF\),试求解电路的谐振频率?
◉【解】根据题设条件,该电路的谐振频率 \(f_0\) 等于:
\[f_0 = \frac{1}{2 \pi \sqrt{LC}} = \frac{1}{2 \pi \sqrt{(5.0 \times10^{-6}) \times (35 \times 10^{-12})} } = 12 \times 10^6 Hz = 12 MHz\]
▶【例题】如果一个谐振电路的电感为 \(2.0 \muH\),如果谐振频率为 \(21.1MHz\),试求解电路当中电容的值 ?
◉【解】根据题设条件,这个电路当中电容 \(C\) 的值等于:
\[f_0 = \frac{1}{2 \pi \sqrt{LC}} \implies C = \frac{1}{L} \big(\frac{1}{2 \pi f_0} \big)^2 = \frac{1}{2.0 \times 10^{-6}H} \big[\frac{1}{2 \pi (21.1 \times 10^6 Hz)} \big]^2 = 2.85 \times 10^{-11} F =28.5F\]
注意:上述公式可以在元件允许的误差范围之内,计算出相应的频率与元件参数。除了
谐振频率
之外,谐振电路还具有阻抗
、带宽
、串联谐振电路当中元件之间的压降
、并联谐振电路中的循环电流
等重要特性。
前面讨论的 LC 串联谐振电路、LC并联谐振电路都属于理想电路,由于电路元件实际上都存在着内电阻
或者内阻抗
,所以理想电路的谐振与真实发生谐振存在着一定偏差。实际的LC谐振电路当中,电容的高频损耗电阻较小,可以忽略;而电感的高频损耗电阻较大,不可以忽视,分析电路时需要将其纳入考量。接下来通过下图所示的电路,说明RLC 串联电路的工作原理:
首先,求解出上述 RLC串联电路的总阻抗 \(Z_{total}\):
\[Z_{total} = R + X_L + X_C = R + j \omega L - j \frac{1}{\omega C} = R +j \bigg( \omega L - \frac{1}{\omega C} \bigg)\]
这里依然把上述结果转换为极坐标形式:
\[Z_{total} = \sqrt{R^2 + (\omega L - \frac{1}{\omega C})^2} \angle\tan^{-1} \bigg( \frac{\omega L - \frac{1}{\omega C}}{R} \bigg)\]
如果不考虑相位,那么流过总阻抗的电流\(I\) 等于:
\[I = \frac{V_S}{Z_{total}} = \frac{10 VAC}{\sqrt{R^2 + \big( \omega L -\frac{1}{\omega C} \big)^2}}\]
将电感 \(L = 100 \muH\)、电容 \(C = 62.5nF\)、角频率 \(\omega= 2 \pi f\) 代入,既可以求解得到一个关于电流的频率函数:
\[I = \frac{10 VAC}{\sqrt{25 + (6.28 \times 10^{-4} f -\frac{2546479}{f})^2}} Ω\]
当上述方程里的频率 \(f\) 等于谐振频率 \(f_0 = \frac{1}{2\pi \sqrt{LC}} = \frac{1}{2\pi\sqrt{(100 \times 10^{-6}H)(62.5 \times 10^{-9}F)}} = 63663 Hz\)的时候,该 LCR 串联谐振电路的总电流\(I = \frac{V_S}{R} = \frac{10 VAC}{5Ω} =2A\)并不会趋于无穷大,而是在发生谐振时感抗
与容抗
相互抵消,其中电阻
可以防止出现阻抗为零的情况。
空载品质因数 \(Q_u\)就是指电路发生谐振时的电抗
除以电阻
:
\[Q_u = \frac{1}{R} \times \sqrt{\frac{L}{C}} \times \frac{X_{L, 0}}{R} =\frac{\omega_0 L}{R} = \frac{2 \pi f_0 L}{R} = \frac{40Ω}{5Ω} = 8\]
当电路发生谐振的时候,感抗
与容抗
相互抵消,整个电路的阻抗仅由电阻
来决定。由此可以推断,发生谐振时的电流
与电压
同相,类似于只存在一个电阻的正弦电路。如果当前没有发生谐振,由于感抗
或者容抗
的增加,总阻抗
将会增大。如果当前电路的频率低于谐振频率,那么容抗占据主导地位(电容对于电流的阻碍作用增强)。如果当前电路的频率高于谐振频率,则感抗占据主导地位(电感对于电流的阻碍作用增强)。当电路没有发生谐振的时候,电阻对于电流幅值的影响微不足道。
上图当中的电流曲线存在着一个尖锋,当感抗
或者容抗
与电阻
的大小相当时,如果远离谐振频率,那么电流就会缓慢下降,此时电流曲线的尖峰较宽。相反的,当感抗
或者容抗
比电阻
更大时,无论朝哪个方向远离谐振频率,电流都会迅速的下降,此时的电流曲线尖峰较窄。窄带谐振电路对于谐振频率的响应,要比接近谐振频率位置附近的频率响应更大,而宽带谐振电路对于谐振频率附近的频率响应基本都相同。
因此,窄带谐振电路具有更好的选择性,可以表现出对于指定频率信号较强的响应能力(幅值),并且能够抑制其它频率的信号。而宽带谐振电路可以应用于需要对频带内所有信号进行相同响应的场景(而并非只对单一频率有较强响应)。
注意:接下来所要讨论的品质因数与带宽,是体现RLC 谐振电路频率选择性的两个重要参数。
之前内容当中有介绍过,品质因数 Q是电抗
(储能)与电阻
(耗能)的比值,在RLC 串联电路(其中的 R
是元件内阻)当中,电感器 L
的内阻损耗在高频情况下占据主导地位,这意味着电感的 Q值在很大程度上决定了谐振电路的 Q 值。因为Q 值与接收功率的外部负载无关,所以这里更改了谐振电路的Q 值,称其为电路的无负载 \(Q\) 值,并且记作 \(Q_u\)。
使用上面 RLC串联谐振电路当中的电阻
,除以感抗
或者容抗
(谐振时的感抗
与容抗
相等)就可以确定该电路的无负载Q 值:
\[Q_u = \frac{X_{L,0}}{R} = \frac{40Ω}{5Ω} = 8 \ 或者\ Q_u =\frac{X_{C,0}}{R} = \frac{40Ω}{5Ω} = 8\]
上述等式表明,如果增大电阻 R
,那么无负载 Q值 \(Q_u\)就会降低,谐振电路的响应曲线就会变宽。例如当电阻分别为10 Ω
、20 Ω
、50 Ω
时,\(Q_u\) 分别会降低至4
、2
、0.8
。相反的,如果减小电阻R
,那么无负载 Q 值 \(Q_u\)就会增大,谐振电路的响应曲线就会变窄。例如当电阻减小至 2Ω
的时候,\(Q_u\) 就会增大到20
。
除了品质因数 Q之外,带宽是另外一个用于表征 RLC谐振电路频率选择特性的物理量。把上面的品质因数曲线图转换为下面的带宽曲线图,即将竖轴的电流
更换为相对电流
,并将用于表示变化Q值的曲线簇向上移动,使得所有曲线都具有相同的峰值电流。通过假设每一条曲线的峰值电流相等,可以非常容易的比较出不同Q值时,电流的变化率以及相关的电抗
与电阻
之比。
从上面的曲线可以看出,与 Q值较高的电路相比,Q值较低的电路可以通过更大带宽的频率。带宽被定义为两个频率之间的差值,此时两个频率点上的电流幅值为最大值的0.707
倍或者 \(\frac{1}{\sqrt{2}}\)倍。由于电阻消耗的功率与电流的平方成正比,假设这里 R
为常数,则电路在这两个频率点位置的功率,是发生谐振时最大功率的一半。在上面的曲线图当中,已经标识出了这个半功率点,或者称为-3dB
点。
由于 Q 值大于 10
的曲线近乎完全对称,因而可以很容易的得出带宽(\(WB\))的计算公式(带宽
与频率
的单位都是赫兹Hz
):
\[带宽\ BW = \frac{谐振频率\ f_0}{无负载品质因数\ Q_u}\]
例如对于本小节开头的 RLC 串联谐振电路,其在100KHz
频率时的带宽为 \(BW_1 = \frac{f_0}{Q_u} = \frac{100000 Hz}{8} =12500Hz\),而在 1MHz
频率时的带宽为\(BW_1 = \frac{f_0}{Q_u} = \frac{1000000Hz}{8} = 125000Hz\):
RLC谐振电路当中,电感
与电容
两端的电压可以根据交流欧姆定律求解得到:
\[\begin{cases}电容电压\ V_C = X_C \times I = \frac{1}{2 \pi f C} \times I \\电感电压\ V_L = X_L \times I = 2 \pi f L \times I\end{cases}\]
因为电感器与电容器会将其储存的能量返还给电路,所以电感器与电容器两端的电压可能会大于电源电压,特别是对于具备高Q 值的电路,更是尤为如此。
例如在发生谐振时,本小节开头所示 RLC串联电路里的电容
与电感
两端电压 \(V_C\) 与 \(V_L\) 分别为:
\[\begin{cases}V_C = X_C \times I = (40Ω \angle -90°) \times (2A \angle 0°) = 80° VAC\angle -90° \\V_L = X_L \times I = (40Ω \angle +90°) \times (2A \angle 0°) = 80° VAC\angle +90°\end{cases}\]
将 RMS 值乘以 1.414
就可以将其转换为峰值,即约等于113V
。这样高 Q值的电路经常出现在天线耦合器当中,由于其功率较大,因而可以承受较高无功电压
造成的电弧(无功电压是由电抗元件在线路上产生的变化电压)。即使电源电压处于元件的额定电压范围以内,但是在考虑Q 值大于 10
的情况时,RLC串联电路发生谐振时的无功电压 \(V_X\) 可以采用下面公式获得:
\[无功电压 V_X = 无负载品质因数 \ Q_u \times 电源电压\ V_S\]
对于频率低于 30 MHz
的串联谐振电路,电容的能量损耗比电感更小。但是在30 MHz ~ 300 MHz
范围以内,电容的损耗可能会影响到电路的Q值。电容损耗主要来自于电容器极板之间电介质的泄漏电阻,其与电感器的内阻损耗存在着区别:电感器的导线损耗电阻
与感抗形成串联关系,而电容器的泄漏电阻
与容抗形成并联关系。如果电容器的泄漏电阻影响到串联谐振电路的Q值,则必须将这个并联的泄漏电阻,转换为串联的等效电阻,其计算公式如下所示:
\[串联等效电阻\ R_S = \frac{容抗\ X_C^2}{泄露电阻\ R_P} = \frac{1}{R_P\times (2 \pi f C)^2}\]
注意:把该
串联等效电阻
与电感的导线损耗电阻
相加,就可以得到RLC 谐振电路当中电阻 \(R\) 的取值(该书将 RLC 电路中的电阻R
视为电感L
与电容C
的内阻之和)。
▶【例题】10.0pF
的电容器在 40.0 MHz
频率时的泄漏电阻为9000 Ω
,求解其等效串联电阻 \(R_S\) ?
◉【解】根据题设条件,该电路的等效串联电阻 \(R_S\) 等于:
\[R_S = \frac{1}{R_P \times (2 \pi f C)^2} = \frac{1}{9000Ω \times (6.283\times 40.0 \times 10^6 \times 10.0 \times 10^{-12})^2} = 17.6 Ω\]
注意:计算串联谐振电路的
阻抗
、电流
、带宽
时,需要把串联泄漏电阻
与电感线圈内电阻
相加,但是由于集肤效应的存在,电感的内阻会随着频率的提高而增大,从而导致电容与电感的全部损耗,严重降低了电路的Q 值。
▶【例题】假设一个串联谐振电路的损耗电阻为4Ω
,求解感抗与容抗都为200Ω
时电路的无负载 Q 值?以及感抗与容抗为 20Ω
时候的无负载 Q 值 ?
◉【解】感抗与容抗都为200Ω
时电路的无负载 Q 值 \(Q_{u1}\) 等于:
\[Q_{u1} = \frac{X_1}{R} = \frac{200Ω}{4Ω} = 50\]
◉【解】感抗与容抗都为20Ω
时电路的无负载 Q 值 \(Q_{u2}\) 等于:
\[Q_{u2} = \frac{X_2}{R} = \frac{20Ω}{4Ω} = 5\]
▶【例题】如果一个串联谐振电路的工作频率为7.75 MHz
,工作带宽为775 kHz
,求解该电路的无负载 Q 值 ?
◉【解】根据题设条件,这个电路的无负载 Q 值 \(Q_u\) 等于:
\[Q_u = \frac{f}{BW} = \frac{7.75MHz}{0.775 MHz} = 10\]
下图是一个典型的RLC 并联谐振电路,类似于 RLC串联谐振电路,电感线圈的内阻
是主要的功率损耗源,因而在电感支路侧添加了一个串联电阻。RLC串联谐振电路的阻抗会在谐振时趋于最小值,而 RLC并联谐振电路的阻抗则会在谐振时趋于最大值,所以通常称 RLC并联谐振电路为反谐振电路或者带阻电路(而RLC 串联谐振电路被称为带通电路)。
LRC 并联电路的总阻抗 \(Z_{total}\) 等于感抗 \(X_L\) 与电阻 \(R\) 串联,再与容抗 \(X_C\) 进行并联:
\[Z_{total} = \frac{(R + X_L) \times X_C}{(R + X_L) + X_C}= \frac{(R + j \omega L) \times (- j \frac{1}{\omega C})}{(R + j \omegaL) + (- j \frac{1}{\omega C})}= \frac{\frac{L}{C} - j \frac{R}{\omega C}}{R + j (\omega L -\frac{1}{\omega C})}\]
按照惯例,同样将总阻抗 \(Z_{total}\) 转换为极坐标形式:
\[Z_{total} = \frac{\sqrt{(\frac{L}{C})^2 + (\frac{R}{\omega C})^2} \angle \tan^{-1}\big[\frac{R/(\omega C)}{L/C} \big] }{\sqrt{R^2 + (\omega L - \frac{1}{\omega C})^2} \angle \tan^{-1} \big[\frac{\omega L - \frac{1}{\omega C}}{R} \big]}\]
将电感 \(L =5.0µH\)、电容 \(C =50pF\)、电阻 \(R =10.5Ω\)、角频率 \(ω =2 \pi f\) 分别代入,就可以得到忽略相位的总阻抗\(Z_{total}\):
\[Z_{total} = \frac{\sqrt{1.0 \times 10^{10} + \big(\frac{3.34 \times 10^{10}}{f} \big)^2}}{\sqrt{110.3 + \big( 3.14 \times 10^{-5} \times f - \frac{3.18 \times10^9}{f} \big)^2}}\ Ω\]
进一步的就可以得到一个不考虑相位角的总电流 \(I\):
\[I_{total} = \frac{V_S}{Z_{total}} = \frac{10 V}{\frac{\sqrt{1.0 \times 10^{10} + \big(\frac{3.34 \times 10^{10}}{f} \big)^2}}{\sqrt{110.3 + \big( 3.14 \times 10^{-5} \times f - \frac{3.18 \times10^9}{f} \big)^2}}\ Ω}\]
将上面的等式输入电路仿真工具,就可以得到如下的谐振频率特性曲线:
观察上图可以发现,在特定的频率
之下,阻抗
趋于最大值,总电流
趋于最小值。但是这个频率并非位于\(X_L = X_C\) 的位置,不属于 LC并联电路或者 RLC串联电路的谐振频率点。RLC并联电路的谐振频率表达式较为复杂,总共存在着三种表达方式,在这里我们采用LC 并联电路来近似的进行表示:
\[f_0 = \frac{1}{2 \pi \sqrt{LC}} = 10,070,000 Hz = 10.07 MHz\]
利用电感 \(L\)的感抗,就可以得到无负载 Q 值 \(Q_u\):
\[Q_u = \frac{X_{L,0}}{R} = \frac{\omega_0 L}{R} = \frac{2 \pi f_0 L}{R} =\frac{316.4Ω}{10.5Ω} = 30\]
下图所示的曲线展示了电感支路里的串联电阻大小,对于品质因数Q 值的影响:
RLC 并联谐振电路里的电阻 \(R\)改变了电路的谐振条件,例如当感抗 \(X_L\) 与容抗 \(X_C\)相等时,电感
与电容
支路的阻抗不为零。由于电阻的存在,使得电感支路的阻抗
比电容支路的容抗
更大,并且与\(X_C\) 的相位角不为180°
,因而电路的总电流并非最小值,且电流
与电压
的相位也不相同,如下图当中的直线A 所示。
如果稍微调整电感的取值,并且保持 Q值为常数,就会得到一个可以使得电流达到最小值的频率。我们把电流达到最小值作为RLC并联电路发生谐振的标志,电流最小值(或者阻抗最大值)所在的频率点称为反谐振点。注意不要把反谐振点与条件\(X_L = X_C\)混淆。电感被微调以后,电流
与电压
的相位会稍有不同,如下图中的直线B 所示。
当电路的 Q 值达到 10
以上时,谐振点之间的差异很小,几乎都集中在同一个频率,这种情况下可以采取近似计算,认为最小电流与电压之间的相位几乎相同,从而避免复杂的计算过程。如果假设电路的Q 值大于10
,那么可以去掉电感支路上的串联电阻,改为采用一个并联电阻来等效电感的内阻:
上图左侧的串联电阻 \(R_S\)被右侧等效电路当中的并联电阻 \(R_P\)替代,反之亦然。通常称这个并联等效电阻为并联谐振电路的动态电阻,其取值与电感支路的串联电阻成反比。换而言之,并联等效电阻会随着电路Q 值的增加而变大,并联等效电阻 \(R_P\) 的近似计算公式如下面所示:
\[R_P = \frac{X_L^2}{R_S} = \frac{(2 \pi f L)^2}{R_S} = Q_u X_L\]
▶【例题】假设上图左侧电路发生谐振时的感抗为316Ω
,串联电阻为10.5Ω
,求解电感的并联等效电阻,以及无负载Q 值 ?
◉【解】根据题设条件,可以得到电感的并联等效电阻\(R_P\) 为:
\[R_P = \frac{X_L^2}{R_S} = \frac{(316Ω)^2}{10.5Ω} = 9510Ω\]
◉【解】电感线圈的无负载 Q 值 \(Q_u\) 等于电感的感抗 \(X_L\) 除以其串联电阻 \(R_S\)(内阻):
\[Q_u = \frac{X_L}{R_S} = \frac{316Ω}{10.5Ω} = 30\]
注意:让 \(Q_u\)乘以电抗,也可以得到与电感器串联电阻近似的并联等效电阻\(R_P\)。
发生谐振的时候,假设并联等效电路满足关系式 \(X_L = X_C\),则 \(R_P\)为该并联谐振电路的等效阻抗。由于感抗
与容抗
相等,则电压
与电流
保持同相。换而言之,发生谐振时电路只呈现并联电阻的特性,因此前述的并联等效电阻\(R_P\)近似计算公式,可以重新改写为下面的形式:
\[Z = \frac{X_L^2}{R_S} = \frac{(2 \pi f L)^2}{R_S} = Q_u X_L\]
当电路的频率小于谐振频率时,感抗
小于容抗
,此时经过电感
的电流比经过电容
的电流更大,相互之间仅有一部分被抵消掉,因而总电流大于电阻的电流。当频率大于谐振频率时,则情况正好相反,经过电容
的电流比经过电感
的电流更大,总电流仍然大于电阻的电流。而在发生谐振时,电流完全由并联等效电阻\(R_P\) 决定,如果 \(R_P\) 增大电流
就会减小,如果\(R_P\)减小电流
就会增大。
随着总电流在谐振之后增大,并联谐振电路的阻抗下降,电压
与电流
之间的相位差增大,阻抗下降的速率是\(Q_u\)的函数。本节内容开始位置的曲线簇,就展示了电路的 Q 值在\(10 \sim 100\)范围内,阻抗由于发生谐振而下降的情况。并联电路阻抗的曲线簇本质上与串联电路电流的曲线簇相同。
如果应用半功率(-3dB
)点来比较和测试电路性能,那么就可以将串联谐振电路的带宽公式\(BW = \frac{f}{Q_u}\)应用到并联谐振电路当中。接下来的表格,对于并联谐振电路的性能特点进行了归纳总结:
高 Q 值与低 Q值的并联谐振电路比较:
高 Q 值 | 低 Q 值 | |
---|---|---|
选择性 | 高 | 低 |
带宽 | 窄 | 宽 |
阻抗 | 高 | 低 |
线路电流 | 小 | 大 |
环流 | 大 | 小 |
当电感 L
和电容C
分别为常数时,电路远离谐振点之后的特性:
高于谐振频率 | 低于谐振频率 | |
---|---|---|
感抗 | 增大 | 减小 |
容抗 | 减小 | 增大 |
电路电阻 | 不变 | 不变 |
电路阻抗 | 减小 | 减小 |
线路电流 | 增大 | 增大 |
环流 | 减小 | 减小 |
电路特性 | 容性 | 感性 |
已知理想 LC并联谐振电路发生谐振时,电容
与电感
之间会存在比较大的循环电流,而电源端输出的电流为零。对于实际的RLC并联谐振电路,发生谐振时同样会存在循环电流,这个电流会比电源输出的电流更大(电源由于负载的存在电流较小,但是不会为零)。这是由于尽管谐振时电路的阻抗较大,但并非是无穷大,循环电流在通过电感
与电容
时产生损耗,而大部分损耗是由电感
的内阻所造成。实际的RLC并联谐振电路(下图左)及其等效电路(下图右)如下图所示:
根据上图右侧的并联等效电路,可以分别求解得到电感、电容、电阻上面的电流值\(I_L\)、\(I_C\)、\(I_R\):
\[\begin{aligned}I_R &= \frac{V_S}{R_P} = \frac{10 VAC}{9510Ω} = 1 mA \\I_L &= \frac{V_S}{X_L} = \frac{V_S}{2 \pi f L} = \frac{10 VAC}{2 \pi\times (10.07 \times 10^6 s^{-1})\times(5.0 \times 10^{-6}H)} = \frac{10VAC}{316Ω} = 32mA \\I_C &= \frac{V_S}{X_C} = \frac{V_S}{\frac{1}{2 \pi f C}} = \frac{10VAC}{\frac{1}{(2 \pi) \times (10.07 \times 10^6 s^{-1}) \times (50.0\times 10^{-12}F)}} = \frac{10 VAC}{316Ω} = 32 mA\end{aligned}\]
当电路工作于谐振频率时,循环电流\(I_{circuiting} = I_C =I_L\),如果并联谐振电路的无负载 Q 值大于10
,那么循环电流可以近似的等于 \(I_{circuiting} = Q_u \timesI_{total}\)。在上面的例子当中,总电流 \(I_R = 1 mA\),电路的 Q值等于 30
,则循环电流 \(I_{circuiting} \approx 30 \times 1mA =30mA\)。
▶【例题】假设并联谐振电路的总电流为50mA
,Q 值等于 100
,求解经过元件的循环电流?
◉【解】根据题设条件,可以求解得到该电路当中的循环电流\(I_C\):
\[I_C = Q_u \times I_T = 100 \times 0.05 A = 5 A\]
在许多谐振电路的应用当中,实际的功率损耗主要消耗在谐振电路的内阻上面,当频率低于30MHz
时,这个内阻主要体现为电感器的内电阻。增加电感器的线圈匝数,会让感抗
比线圈的内阻
增加得更快。高Q 值电路当中的电感器,通常会具有较大的电感值。
当能量通过谐振电路传递到负载的时候,谐振电路消耗的能量通常会比负载消耗的能量更小。如果负载消耗的能量是电感与电容消耗能量的10
倍以上,那么相比于负载电阻
,谐振电路的并联阻抗
将会更大,整个电路的实际阻抗
等于负载阻抗
。在这种情况下计算Q值时,可以使用负载电阻
代替电路阻抗
,此时并联谐振电路的Q 值计算公式为:
\[带负载电路的 Q 值\ Q_{LOAD} = \frac{并联负载电阻\ R_{LOAD}}{电抗\ X}\]
▶【例题】将一个 4000Ω
电阻负载连接至谐振电路,当电路发生谐振时,感抗
和容抗
都为316Ω
,试计算该电路的带负载 Q 值 ?
◉【解】根据题设条件,就可以求解得到该电路的带负载 Q值 \(Q_{LOAD}\):
\[Q_{LOAD} = \frac{R_{LOAD}}{X} = \frac{4000Ω}{316Ω} = 13\]
注意:当电路的电抗下降时,电路的带负载Q值就会增加,因而当一个带负载电路的电阻较小(几千欧姆)时,必须使用低电抗值的元件(大电容和小电感),使得发生谐振时的Q 值更大。
电子学当中,经常需要比较两个信号的幅值以及功率。例如一个放大器的输出电压
为输入电压
的10
倍,此时的比值 \(\frac{V_{out}}{V_{in}} = \frac{10 VAC}{1 VAC} =10\)被称为增益;而一个放大器的输出电压
小于输入电压
有10
倍,则比值 \(\frac{V_{out}}{V_{in}} = \frac{1 VAC}{10 VAC} =0.1\) 被称为衰减。
当两个信号的幅值
或者功率
比值差距较大的时候,绘制曲线将会变成一件非常困难的事情。在电子学当中,就通过贝尔这个单位引入特殊的对数坐标解决这个问题,贝尔\(bel\) 是指比较功率\(P_1\) 与参考功率\(P_0\) 的比值:
\[贝尔\ bel = \log \bigg(\frac{比较功率\ P_1}{参考功率\ P_0}\bigg)\]
电子学当中,贝尔 \(bel\)经常用于比较功率的大小,但是应用更为普遍的单位是分贝dB
:
\[1 分贝dB = \frac{1}{10} 贝尔bel \implies 1 贝尔bel = 10 分贝dB\]
因而在这里,可以改用分贝
来度量功率的大小,前面的公式需要改写为下面的形式:
\[分贝\ dB = 10 \times \log \bigg(\frac{比较功率\ P_1}{参考功率\P_0}\bigg)\]
▶【例题】如果一个放大器的输入信号功率为1W
,而输出信号功率达到50W
,试求解该放大器的增益 ?
◉【解】根据题设条件,可以求解出该放大器的增益为 \(17dB\):
\[dB = 10 \times \log \bigg( \frac{50W}{1W} \bigg) = 10 \times \log (50) =17 dB\]
比较电路当中的信号大小时,通常已知的是信号的电压
或者电流
,而并不是功率
。虽然可以通过电路的阻抗计算出功率,但是更为简单的办法是将交流欧姆定律代入分贝表达式中的功率,此处调用\(P = \frac{V^2}{Z} =\frac{I^2}{Z}\)(只有当电路的阻抗不随电压
或电流
的变化而波动时,这种情况才会成立),即只要阻抗保持不变,就可以用分贝来比较电压
与电流
信号。
\[\begin{cases}dB = 10 \log \bigg( \frac{V_1^2}{V_0^2} \bigg) = 20 \log \bigg(\frac{V_1}{V_0} \bigg) \\dB = 10 \log \bigg( \frac{I_1^2}{I_0^2} \bigg) = 20 \log \bigg(\frac{I_1}{I_0} \bigg)\end{cases}\]
如果输出功率是输入功率的两倍,那么就是增益3.01 dB
:
\[dB = 10 \log(2) = 3.01 dB\]
如果输出功率是输入功率的一半,那么就是衰减-3.01 dB
:
\[dB = 10 \log(0.5) = -3.01 dB\]
注意:通常会省略小数点后面的
0.01
,即认为功率翻倍时的增益为\(3dB\),而在功率减半时的衰减为\(-3dB\)。
下面的表格展示了常见的分贝值,和对应的功率变化情况,以及电压与电流的变化情况:
注意:只有当对应的阻抗相等时,上面表格当中所列出的关系才会成立。
我们将以分贝作为单位的值,与 1mW
功率的比值称为分贝毫瓦dBm
。这是一个用于指代功率的绝对值(分贝是一个表示功率的相对值)。例如从天线传递到接收设备的信号功率为\(2 \times 10^{-13}mW\),此时接收设备的信号输入强度则可以表示为:
\[dB_m = 10 \times \log \bigg( \frac{2 \times 10^{-13} mW}{1mW} \bigg) =-127 dBm\]
除此之外,还可以将使用分贝作为单位的值,与1W
功率的比值称为分贝瓦dBW
,而与 1V
电压幅值的比值称为分贝伏dBV
,它们各自都拥有着相应的物理意义与用途。
电子工程实验当中,必不可少的涉及到大量测量仪器的使用,本文主要记录笔者工作室当中所使用的数字万用表(Multimeter)、数字电桥(LCRMeter)、数字存储示波器(DSO)、逻辑分析仪(LogicAnalyzer)、可编程直流电源(DCSupply)、信号发生器(SignalGenerator)等仪器的性能指标术语,包括三极管测量
、电源纹波
、晶振频率
、谐波输出
等常规的测量方法与技巧,以及相关的注意事项。
数字万用表(Multimeter)是一种多用途的电子测量仪器,可以用于测量电路当中的电压
、电流
、电阻
、电感
、晶体管
等数据。手持式数字万用表的的显示规格通常为三位半或者四位半,其中三位半是指有三位数字可以显示0 ~ 9
,而最高位只能显示数字1
,而四位半同理。
数字万用表判断三极管属于 NPN 还是 PNP类型,需要使用到二极管档位,此时红表笔
相当于电池正极,黑表笔
相当于是电池负极。由于三极管的B、C、E极之间都存在着 PN 结,当表笔向 PN结施加正向电压时就能够导通(导通电压约0.7V
左右),本测量方法正是基于这个原理。
指针万用表主要分为内磁式(表针游丝安装在环形磁铁内部,受外磁场干扰较小,磁路短。由于用磁材料较少,导致难以形成较强磁场,灵敏度相对较低)和外磁式(表针游丝安装在环形磁铁外部,由于用磁材料较多,灵敏度高,线性好,但是也存在着易受干扰的问题)。
虽然相比于数字万用表而言,指针万用表读数不便,且精度相对较差。但是由于指针万用表电阻档的测量输出电压较高,因而可以用于判断IGBT 等大功率器件引脚的通断状态。笔者当前使用的是一台由 南京天宇电子仪表厂生产的 T-88N型外磁式指针式万用表(可以直接测量频率和电容),下面分别展示了其表盘和档位旋转开关的示意图:
该款外磁式指针式万用表的具体测量技术指标,如下面的表格所示:
电流
或者电压
刻度的零点,如果不在则需要通过【指针归零】旋钮将指针归零;500mA
)时,禁止在测量过程当中拨动量程开关,以免产生电弧烧坏开关触点;注意:不要在测量较高电压的时候,拨动量程切换开关,从而避免产生电弧烧坏开关触点。
使用指针式万用表测量电阻的操作步骤如下所示:
注意:指针万用表在电阻档状态下,电流是从红色表笔流出,黑色表笔流入。
指针式万用表测量二极管,是根据二极管在正向导通时阻值较小,而反向截止时阻值较大的原理。
数字电桥(LCRMeter)是一种用于测量电感
、电容
、电阻
元件参数的仪器,其主参数不仅能显示出元件值,副参数还能够反映Q
、D
、Z
、Lp
、Ls
、Cp
、Cs
、Kp
、Ks
等参数。
注意:通常情况下,低阻抗元件使用串联等效模型,高阻抗元件使用并联等效模型。
数字存储示波器(DSO,Digital Storage Oscilloscope[əˈsɪləskoʊp])是一种将电信号数字化之后再重建波形,并且具有记忆、存储波形信号功能的电子仪器。
奈奎斯特(Nyquist)采样原理认为,对于最大频率\(f_{MAX}\)的带宽有限制信号而言,等距采样频率 \(f_S\) 必须超过最大频率\(f_{MAX}\)两倍以上,才能够产生出不会发生混叠的信号。
\[最大频率 f_{MAX} = \frac{等距采样频率 f_S}{2} = 奈奎斯特频率 f_N =折叠频率\]
数字示波器的实际采样率由当前的水平时基档位决定,采样率不足会引起波形出现失真
、混叠
、漏失
等问题,从而造成波形无法正常进行显示:
波形失真:由于采样率低造成某些波形细节缺失,使示波器采样显示的波形与实际信号存在较大差异;
波形混叠:由于采样率低于实际信号频率的2倍,对采样数据进行重建时的波形频率小于实际信号的频率;
波形漏失:由于采样率过低,对采样数据进行重建时的波形没有反映全部实际信号;
示波器的带宽是指按照 3dB
衰减输入信号幅值的最低频率,对于没有超过示波器最大频率 \(f_{MAX}\) 的频率分量而言,所需要的采样率\(f_S\) 为示波器带宽 \(f_{BW}\) 的两倍。
由于数字方波信号由基本频率位置的正弦波
和多个奇次谐波
组成,具有超出其基本频率的分量,所以正常显示波形的采样率\(f_S\) 应当高于带宽 \(f_{BW}\) 的 4 倍以上。
存储深度是指示波器在每一次触发采集当中,所能够存储的波形点数。
存储深度 \(MDepth\)(单位为pts
)、采样率 \(SRate\)(单位为Sa/s
)、水平时基档位 \(TScale\)(单位为s/div
)、屏幕水平方向格数 \(HDivs\)(单位为 div
)三者的关系满足如下方程式:
\[存储深度 MDepth = 采样率 SRate \times 水平时基档位 TScale \times屏幕水平方向格数 HDivs\]
注意:在相同的水平时基档位下,高存储深度可以保证高采样率。
通常情况下,示波器获取的采样点难以直观进行观察,为了提高信号的可视性,示波器通常会采用插值法进行显示。这里的插值法是一种连接各个采样点,并利用采样点推算出整个波形面貌的处理方法,主要分为线性插值x 和正弦插值 sinx/x 两种方式:
方波
;3 ~ 5
倍时,建议采用该方法;波形的获取方式用于控制如何从采样点当中产生出波形点,通常需要使用到示波器面板上的【Acquire】按钮。
显示屏幕的垂直方向上,每一个刻度代表的是电压幅值,通常表示为V/div
,目前国产数字示波器的垂直档位调节范围在500μV/div - 10V/div
之间。
设置耦合方式可以滤除不需要的信号,例如:被测信号是一个含有直流偏置的方波信号。
直流分量
和交流分量
都可以通过;直流分量
被阻隔;直流分量
和交流分量
都被阻隔;带宽限制可以减少显示波形中的噪声,例如:被测信号是一个含有高频振荡的脉冲信号。
20MHz
:被测信号当中大于 20MHz
的高频分量将会被衰减;衰减比是指被测信号的显示幅度
与被测信号实际幅度
之间的比值。
1 | 0.1X 0.1 : 1 |
关闭波形反相时,波形正常显示;打开波形反相时,波形电压值被反相:
使用示波器进行实际测量时,探头电缆的传输延迟可能带来较大的误差(零点偏移,波形与触发电平线的交点相对于触发位置的偏移量)。此时通过设定一个延迟时间,可以校正对应通道的零点偏移。
显示屏幕的水平方向上,每一个刻度代表的是时间基准,通常表示为S/div
,目前国产数字示波器的水平档位调节范围在1.0ns/div ~ 100s/div
之间。
Y
轴表示电压量,X
轴表示时间量;电压-时间
转化为电压-电压
,然后使用李沙育法测量相同频率的两个信号之间的相位差,下面是相位差的测量原理图:根据 \(\sin \theta = \frac{A}{B} =\frac{C}{D}\),其中A
、B
、C
、D
的定义见上图,而 \(\theta\)表示两个通道之间的相差角,从而可以推导得到:
\[\theta = \pm \arcsin (\frac{A}{B}) = \pm \arcsin (\frac{C}{D})\]
0 ~ π/2
或者 3π/2 ~ 2π
范围内。π/2 ~ π
或者 π ~ 3π/2
范围内。注意:该功能可以用于测量信号经过一个电路网络之后,所产生的相位变化。
滚动 Roll模式下,波形自右向左滚动刷新显示,波形水平位移和触发控制不起作用。
慢扫描模式是指在 YT模式下,当水平时基设定为 50ms/div
甚至更慢时,示波器会首先采集触发点左侧的数据,然后等待触发,在触发之后继续绘制触发点右侧的波形。应用慢扫描模式观察低频信号时,建议将通道耦合方式设置为直流。
数字示波器的触发信源可以是 CH1 ~ CH4
模拟信号通道,也可以选择 AC Line
交流市电输入。
用于控制波形的触发位置,从而决定波形如何显示:
触发耦合决定信号的哪种分量被传送到触发模块。注意与“通道耦合”进行区别。
8Hz
的信号;当信号具有较大的直流偏移时,使用交流耦合可以获得稳定的边沿触发;2MHz
的低频分量,当信号当中含有低频分量时,使用 LFR可以获得稳定的边沿触发;1.2MHz
以上的高频成份;注意:触发耦合与通道耦合是完全独立的两个概念,使用时不能进行混淆。
触发释抑可以稳定的触发复杂波形(例如脉冲序列、调制波),释抑时间是指示波器发生正确触发之后到重新启用触发电路之前等待的时间,在释抑时间内,即使满足触发条件,示波器也不会触发,直至释抑时间结束,示波器才会重新启用触发电路。
正确的触发释抑时间通常会略小于一次波形的重复时间,这样可以让重复的波形生成唯一的触发点,通常释抑时间的可调范围为80ns ~ 1.5s
。
噪声抑制可以抑制信号中的高频噪声,降低示波器被误触发的概率,但是这样同时也会降低触发的灵敏度,需要根据实际酌情使用。
边沿触发:在输入信号指定边沿的触发阈 [yù] 值
上触发;
斜率触发:让示波器在指定时间的正斜率
和负斜率
上触发,适用于观测锯齿波或三角波;
脉宽触发:在指定宽度的正脉冲
或者负脉冲
上触发,即当输入信号的脉冲宽度满足条件时,示波器就会触发;
超时触发:从输入信号的上升下降沿
跨过触发电平开始,到相邻的上升下降沿
跨过触发电平结束的间隔时间\(\Delta T\)大于指定的超时时间就会触发;
欠幅触发:用于触发那些跨越过了一个触发电平,但是未能跨越过另外一个触发电平的脉冲;
码型触发:查找指定码型作为触发条件,码型是任意两个通道的逻辑关系(与
、或
、与非
、或非
)组合,每个通道都可以设定为无效
、低
、高
三种类型;
使用快速傅立叶变换(FFT,FastFourier TransformAlgorithm)可以将时域信号转换为频域分量(频谱,水平档位从时间S
变换为频率Hz
,垂直档位从伏特 V
变换为分贝dB
),从而实现同时观测信号的时域波形
和频谱图
。通过使用FFT运算可以方便的测量谐波分量与失真
、直流电源中的噪声特性
、分析振动
等;
10X
档;正常情况下都建议使用 1X
档,避免不必要的噪声衰减影响纹波质量;除此之外,建议探头上使用接地弹簧进行接地,从而避免接地线过长带来的不必要干扰;20MHz
的带宽限制,滤除不必要的高频噪声;10X
,防止探头带宽过低;注意:无源晶振通常输出的是
正弦波
,而有源晶振输出的信号可能是正弦波
或者方波
。
逻辑分析仪是专门针对数字信号的调试工具,可长时间采集信号,并且无波形死区,支持复杂触发定位以及全面的协议内容解析。相比于数字存储示波器,由于逻辑分析仪只采集高低电平,因而更加擅长于分析数字通讯过程和复杂的协议解析。
采集时长和采样率是逻辑分析仪的两个主要性能指标,目前市场上的逻辑分析仪都支持高采样率
的Buffer 模式,以及较长采集时间
的Stream 模式:
由于 Stream 模式实时将采集到的数据通过 USB传输到电脑内存,最大可以达到 16G深度,从而可以大大提高波形的记录时长:
注意:Stream 模式的实时传输会受到 USB接口的带宽限制(USB2.0 传输速率上限仅为
480Mbps
,但是USB3.0 传输速率上限可以达到5Gbps
)。
采样率越高,对于逻辑信号的还原精度就会越高,通常推荐采样率为被测数字信号频率的10 ~ 100
倍。
可编程直流电源(Programmable DC Power Supply)用于将220V
交流电转变成低压直流电,之所以称为可编程是由于内部并未采用电位器,而是通过微控制器来控制输出的电压与电流。
可编程直流电源通常提供有恒压(CV,Constant Voltage)和恒流(CC,ConstantCurrent)两种输出模式:
电压设置值
,输出电流由负载
决定;电流设置值
,输出电压由负载
决定;串联两个或多个隔离通道可以提供更高的电压;并联两个或多个隔离通道可以提供更高的电流,这种工作模式通常用于单个通道输出的电压、电流上限无法满足实验需求的时候。
可编程直流电源的串联工作模式可以提供更高的输出电压,其输出电压是所有通道的输出电压之和
,此时内部接线方式如下图所示:
可编程直流电源的并联工作模式可以提供更高的输出电流,其输出电流是单个通道的输出电流之和
,此时内部接线方式如下图所示:
电源纹波(Ripple[ˈrɪpl])是由于直流稳压电源内部电压波动
而造成的一种现象,由于直流稳压电源通常由交流电源经整流、稳压等环节而形成,从而不可避免的在直流稳压量当中携带了一些交流成份,这种叠加在直流稳定量上的交流分量就称之为纹波。
信号发生器(SignalGenerator)是一种能够根据需要,产生各种模拟和数字激励信号的电子仪器。
50Ω
的固定串联输出阻抗,如果实际负载与指定值不同,则显示的电压电平将与被测电路的电压电平不匹配。要确保正确的电压电平,必须保证负载阻抗设置与实际负载相匹配。修改阻抗设置后,信号发生器将自动调整输出振幅和偏移电压;\(V_{pp}\)是表示信号峰峰值的单位,\(V_{rms}\)是表示信号有效值的单位,信号发生器默认使用 \(V_{pp}\)作为信号幅值的单位。对于不同的波形,\(V_{pp}\) 与 \(V_{rms}\)之间的关系不同。以正弦波为例,二者之间的关系如下图所示:
根据上图,可以推导出 \(V_{pp}\) 与\(V_{rms}\)之间换算关系满足如下关系式:
\[V_{pp} = 2 \cdot \sqrt{2} \cdot V_{rms}\]
\(dBm\)是表示信号功率绝对值的单位,\(dBm\) 与 \(V_{rms}\) 之间满足如下关系:
\[dBm = 10 \cdot \lg(\frac{V_{rms}^2}{R} \times \frac{1}{0.001W})\]
由于上面方程当中的 R
表示的是通道的输出阻抗,必须为确定的数值,所以当信号发生器的输出阻抗被设置为高阻
时,就不能使用\(dBm\) 作为单位。
信号发生器可以输出包括正弦波、方波、锯齿波、脉冲、噪声在内的 5 种基本波形,
占空比是方波波形高电平持续的时间所占周期的百分比,该参数仅在输出方波
或者脉冲波
时有效。
对称性是指锯齿波波形的上升阶段占据周期的百分比,该参数仅针对锯齿波
有效。
10%
位置上升至 90%
位置所持续的时间;90%
位置下降至 10%
位置所持续的时间;50%
位置之间的时间间隔;信号发生器通常附带有谐波发生功能,可以输出具有指定次数
、幅度
、相位
的谐波,通常应用于谐波检测设备或者谐波滤波设备的测试当中。
傅立叶变换理论指出时域波形
是由一系列正弦波叠加而成的,可以采用如下方程进行表示:
\[f(t) = A_1 \sin(2 \pi f_1 t + \varphi_1) + A_2 \sin(2 \pi f_2 t +\varphi_2) + A_3 \sin(2 \pi f_3 t + \varphi_3) + ...\]
\(f_1\)为基波频率,频率为 \(f_1\)的分量就称为基波,\(A_1\) 为基波幅度,\(\varphi_1\)为基波相位。上述方程当中其它各个分量的频率通常为基波频率的整数倍,称为谐波。频率为基波频率奇数倍
的分量称为奇次谐波,频率为基波频率偶数倍
的分量称为偶次谐波。
信号发生器工作在扫频模式下时,会在指定的扫描时间内从起始频率到终止频率变化的进行输出,正弦波
、方波
、锯齿波
、任意波
都可以进行扫频输出。
信号发生器可以输出经过调制波形,支持的调制类型包括AM
、FM
、PM
、ASK
、FSK
、PSK
、PWM
等。所谓调制就是按照调制信号
的变化改变载波信号
某些参数(幅度、频率、相位等)的过程,这里的载波可以是正弦波
、方波
、锯齿波
、任意波
、脉冲波
,而调制波则是来自内部或者外部的调制源。
调制类型 | 英文缩写 | 英文全称 | 调制方式描述 |
---|---|---|---|
幅度调制 | AM | Amplitude Modulation | 载波的幅度 随着调制波形瞬时电压 的变化而变化; |
频率调制 | FM | Frequency Modulation | 载波的频率 随着调制波形瞬时电压 的变化而变化; |
相位调制 | PM | Phase Modulation | 载波的相位 随着调制波形瞬时电压 的变化而变化; |
幅移键控 | ASK | Amplitude Shift Keying | 配置信号发生器在两个预设的幅度(载波幅度 和调制幅度 )之间移动 其输出幅度; |
频移键控 | FSK | Frequency Shift Keying | 配置信号发生器在两个预设的频率(载波频率 和跳跃频率 )之间移动 其输出频率; |
相移键控 | PSK | Phase Shift Keying | 配置信号发生器在两个预置相位(载波相位 和调制相位 )之间移动 其输出相位; |
脉宽调制 | PWM | Pulse Width Modulation | 载波的脉宽 随着调制波形瞬时电压的变化而变化; |
]]>注意:载波(CarrierWave)和载波频率属于相同的物理概念,是一种在
频率
、幅度
、相位
方面被调制以传输信号的电磁波。
标签
或卡片
,其集成电路当中包含有8
位或者 32
位的微控制单元MCU、只读存储器 ROM、电可擦只读存储器EEPROM(按字节操作)或者闪速存储器Flash(按扇区操作)、随机访问存储器RAM,以及固化在只读存储器 ROM当中的片内操作系统(COS,Chip OperatingSystem),并且通常内置有DES
、RSA
、国密 SMx
、SSF
等加解密算法。目前市场上主流的 IC 卡芯片有恩智浦 NXP 的Mifare 系列、英飞凌Infineon 的 SL 系列、、复旦微电子的 FM 系列,华大半导体的SHC 和 CIU 系列除此之外,还有 华虹集成电路的 SHC 系列,以及大唐微电子的 DMT 系列,紫光国微的THD 系列。这些芯片主要遵循 《ISO/IEC7816》 和《ISO/IEC 14443TypeA》两部协议规范,本文主要介绍了笔者在日常工作当中,经常接触到的各类智能卡相关的技术与规范。
接照用途和构成,可以将 IC 卡划分为存储卡(MemoryCard)和带有 CPU 的智能卡(Smart Card)。
接触式
与非接触式
接口为一体的单芯片智能卡,两种接口共享着相同的微控制器、操作系统、EEPROM;注意:许多 IC卡芯片的数据手册当中,
读写卡设备
通常被称为邻近耦合装置(PCD,ProximityCouplingDevice),而IC 卡片
本身则通常被称为感应卡(PICC,ProximityCard)。
ISO/IEC 7816是一种标准化的接触式智能卡通信协议,主要用于读写接触式的集成电路卡,该协议由如下14 个部分组成:
其中,ISO/IEC 7816-4里面定义了应用协议数据单元(APDU,Application ProtocolData Unit)相关的内容,包括接口上交换的 命令-响应
对的内容、检索 IC卡里数据元素和数据对象的方法、通过历史字节的结构与内容来描述 IC卡的工作特性、IC 卡当中程序和数据的结构、访问 IC卡里文件和数据的方法、定义 IC卡内文件与数据访问权限的安全体系结构、用于识别与定位 IC卡当中应用的方法与机制、安全消息传递的方式、访问 IC卡内置的处理算法;
注意:国际标准化组织并未提供标号为《ISO7816-14》的技术规范;
ISO/IEC 14443 定义了 Type A 和Type B 两种 IC 卡类型,它们均工作在13.56MHz
无线频率,两者的主要区别在于调制方式、编码方案(协议第 2部分)、协议初始化过程(协议第 3 部分)三个方面,但是都共同采用了协议第4 部分定义的传输协议,该协议主要由如下 4 个部分组成:
读写卡装置
与 IC 卡之间的无线通信频率为13.56MHz
,当读写卡装置
对 IC卡进行读写操作时,所发出的信号主要由 2 部分叠加组成:
读写卡装置
向 IC卡发送的固定频率电磁波,卡片内置 LC 串联谐振电路的频率与读写卡装置
发射的频率相同,在电磁波的激励下这个 LC电路产生共振,让卡片内置的电容充满电荷,同时另一端连接的单向导通电子泵会将这些电荷传送至另一个电容进行存储,当累积电荷达到2V
时,该电容就可以作为电源为卡片进行供电;读写卡装置
指挥 IC芯片完成数据的读取、修改、储存等操作,并且返回响应信号给读写卡装置
,从而完成一次读写操作过程;ISO/IEC 14443 可以具体划分为由恩智浦(NXP)等公司提出的 TypeA,以及由意法半导体(ST)等公司提出的 Type B两种标准,两者的区别主要体现在 IC卡与读写卡装置
之间的通讯调制方式:
1
时,信号会出现0.2 ~ 0.3
微秒的间隔;而当表示数据 0
时,信号可能有间隙也可能没有,这与前后的信息相关;这种方式优点在于信息区别明显,受干扰的机会少,反应速度快,不容易误操作;缺点在于当需要为IC 卡提供更高的工作电压时,传输的电量有可能会出现波动;1
的信号幅度更大,而数据 0
的信号幅度更小,该方式的优点在于可以持续不断的传递信号,不会出现能量波动的情况;缺点在于数据区别不够明显,相对更容易受到外界干扰;恩智浦半导体于 1994 年 推出的 MifareClassic 系列 也被称为 Mifare 1,即俗称的 M1卡。其工作频率为 13.56MHZ
,符合 ISO 14443Type A 非接触式射频卡规范,虽然其采用的私有算法CRYPTO1已经遭到破解,但是由于目前国内市场上存在着大量与其相兼容的国产芯片(例如复旦微电子的FM11RF08芯片),所以并不妨碍其被广泛使用在安全等级要求较低的场合。
0
扇区不可以进行修改,其它扇区则可以反复进行擦写;0
区块只能够被写入一次,然后变为 M1 卡,在 CUID复无效的情况下,或许可以绕开反克隆设备;标准 Mifare 1 卡的 EEPROM 被划分为 16个扇区(Sectors),其中每个扇区由 4个数据块(Blocks)组成,每个数据块拥有16 个字节(Bytes):
请求 REQA
或唤醒 WUPA
的指令;当IC 卡
与读写卡装置
完成上述认证过程之后,就可以执行如下操作步骤:
内部传输缓冲区
;内部传输缓冲区
的内容写入到一个数据块;应用协议数据单元(APDU,Application Protocol DataUnit)是卡片和外部应用之间的通信报文协议,其格式标准被定义在ISO7816-4当中,具体可以被划分为命令和响应两种类型:
读写卡装置
发送到智能卡
,其中包含一个必选的 4字节头部 CLA + INS + P1 + P2
以及 0 ~ 255
字节的数据;智能卡
返回给读写卡装置
,其中包含有必选的 2字节状态字和 0 ~ 255
字节的数据;下面表格展示了一个 APDU命令-响应对(Command-Response Pair),即命令APDU 和响应 APDU:
命令 APDU 字段 | 功能描述 | 字节数 |
---|---|---|
命令头 | 表示 CLA 的类字节 | 1 |
- | 表示 INS 的指令字节 | 1 |
- | 表示 P1 - P2 的参数字节 | 2 |
\(L_c\)字段 | 编码 \(N_c =0\) 时缺省,而 \(N_c > 0\)时出现; | 0 、1 或者3 |
命令数据字段 | 编码 \(N_c =0\) 时缺省,而 \(N_c > 0\)时体现为一个 \(N_c\)字节的字符串; | \(N_c\) |
\(L_e\)字段 | 编码 \(N_e =0\) 时缺省,而 \(N_e > 0\)时出现; | 0 、1 、2 或者 3 |
响应 APDU 字段 | 功能描述 | 字节数 |
---|---|---|
响应数据字段 | 编码 \(N_r =0\) 时缺省,而 \(N_r > 0\)时体现为一个 \(N_r\)字节的字符串; | \(N_r\)(最多 \(N_e\)) |
响应尾 | 状态字节为 SW1-SW2 | 2 |
EMV(Europay MasterCardVisa)标准是由全球三大银行卡组织欧陆卡(Europay)、万事达卡(MasterCard)和维萨卡(Visa)共同发起制定的银行卡技术标准,是基于IC 卡的金融支付标准,目前已经成为全球公认的统一标准。其中,接触式卡片以ISO/IEC 7816作为标准,而非接触式卡片则主要以 ISO/IEC14443 作为标准。
中国人民银行(PBOC,People's Bank of China)于 2013年正式颁布《中国金融集成电路 IC 卡规范》V3.0
版本,类似上面的介绍的EMV,也属于一种金融集成电路智能卡感应端与接收端的规范标准。并且接触式卡片同样以ISO/IEC 7816作为标准,而非接触式卡片则主要以 ISO/IEC14443 作为标准。
卡片操作系统(COS,Card OperatingSystem)紧密围绕着其所服务的智能卡特点而研发,设计时会紧密结合智能卡内置存储器的分区情况,并且遵循ISO/IEC 7816 或者 ISO/IEC 14443等国际标准,主要用于控制智能卡与外界的信息交换,管理智能卡当中的存储器,并且在智能卡内部完成各种命令的处理。由于目前主要解决的是如何处理与响应外部命令的问题,并不会涉及到共享和并发的管理,所以其本质上更加接近于监控程序,而非一个完整的操作系统。
注意:JavaCard™ 目前已经成为 COS 事实上的工业标准,其以 Java虚拟机作为基础,通过更为安全的方式来执行 JavaApplet,并且支持多应用动态下载,具有平台无关、高安全性、高可靠性、一卡多用等特点。
安全元件(SE,SecureElement)也称安全芯片,主要由安全硬件和软件两部分组成,硬件部分包括安全的运行环境、存储、算法、接口等;软件部分则提供安全的交互机制,确保SE 与上位机之间命令与数据的交互安全。基于 SE对数据进行安全处理,可以实现设备的身份认证、数据传输加密、敏感信息保护等功能。
伴随近年 5G逐步组网商用,物联网在迎来较快发展的同时,安全问题日益突出,物联网的安全需求主要存在于如下四个方面:
基于嵌入式安全元件 SE提供的安全存储与运算环境,就可以为物联网设备运营者提供一个安全可信任的根,然后再由运营者发行SE 当中的设备 ID以及证书密钥等,结合云端的安全服务,从而形成一套完整的物联网安全方案。
ARMSecurCore是一系列专门为高性能、大容量智能卡与嵌入式安全产品而设计的芯片内核架构,目前主要有如下两款:
ARMTrustZone 在芯片内部提供了一种安全高效的的方法,TrustZone技术已经分别被集成到采用 Armv8-A 架构的 Cortex-A系列以及采用 Armv8-M 架构的 Cortex-M系列芯片当中,通过在微控制器系统当中创建独立的可信与非可信区域,确保数据、固件、片上外设的安全性。
ARM TrustZone 技术通常需要结合如下的软件和规范进行使用:
下面的表格展示了采用 ARM TrustZone技术的相关厂商以及对应的典型产品型号:
芯片厂商 | 型号 | 内核架构 |
---|---|---|
Microchip | SAM L11 | Cortex-M23 |
Nordic | nRF9160 与 nRF5340 | Cortex-M33 |
Nuvoton | M2351 | Cortex-M23 |
NXP | LPC5500 和 i.MX RT600 系列 | Cortex-M33 |
Silicon Labs | Gecko Series 2 | Cortex-M33 |
STMicroelectronics | STM32L5 | Cortex-M33 |
Mbed OS 是一款基于 Cortex-M微控制器的嵌入式实时操作系统,其提供了一个包含有存储、连接、设备管理、传感器驱动、输入输出设备的抽象层。
针对银行、身份认证、支付解决方案,均支持ISO7816、ISO14443 A/B 智能卡协议:
针对 NFC、eSE、eSIM 产品的移动安全交易解决方案:
同样基于 ST33 硬件架构,所提供的车规级 eSIMs解决方案,致力于汽车生态系统的安全连接:
针对物联网生态系统当中的嵌入式平台到网关和服务器:
主要基于 ARM SecurCore SC300核心架构,针对工业控制与物联网的组网与通迅用途:
英飞凌在通用微控制器方面,提供了基于 32 位 ARM Cortex 架构的PSoC(基于 Cortex M0 和 M4 架构的系列)、TRAVEOT2G(基于 Cortex M4 和 M7的高性能系列)、XMC(基于 Cortex M0 和 M4架构的工业控制系列)微控制器。
除此之外,英飞凌还拥有自行研发的 TriCore多核心微控制器架构,并基于此推出了 AURIX系列车规级微控制器(常用于装载有发动机控制程序的乘用车 ECU),包括第一代TC2XX 和第二代 TC3XX两个产品序列,最大特色在于嵌入了硬件安全模块(HSM,HardwareSecurity Module),其中包含了32 位安全计算平台
、存储密钥和身份 ID 的受保护存储区
、AES-128 硬件加速器
和随机数生成器
。总而言之,HSM提供了一个安全的平台,通过防火墙将其与微控制器的其他部分隔开,从而创建了一个可信的执行环境。
注意:除此之外,英飞凌还提供有适用于非接触式卡片的CIPURSE 安全解决方案,以及集成嵌入式安全方案OPTIGA,和带有操作系统的集成嵌入式安全解决方案SECORA。
恩智浦NXP 即提供了基于 ARM内核的通用微控制器系列产品:
也提供了基于自家 Power 架构的通用微控制器系列:
除此之外,恩智浦 NXP 还提供了安全与认证相关的解决方案:
EdgeLock SE050/SE051
物联网安全元件;SmartMX3 P71D321/P71D320
、SmartMX2 P60
;其中,值得一提的是其于 2018 年推出的 2GO安全服务平台,为物联网设备提供了一系列安全可扩展的服务:
芯片自定义服务
、标签管理
、身份验证
等功能;EdgeLock SE050
安全元件的物联网设备;瑞萨Renesas 拥有基于 ARM Cortex-M 内核的Synergy 系列微控制器,以及采用自研 RenesaseXtreme 内核的 RX系列微控制器。在安全解决方案方面,则推出了基于 Cortex-M23/M33架构,并采用了 ARM TrustZone 技术的 RA 系列:
兆易创新Gigadevice 推出了基于 ARM Cortex-M23内核的 GD32E230/231/232
系列,以及 ARMCortex-M33 内核的 GD32E5
的高性能系列。
SSLv2
、SSLv3
、TLSv1
)、大量算法实现(对称/非对称/摘要)、大数运算、非对称算法密钥、ASN.1
编解码库、证书请求(PKCS10
)编解码、数字证书编解码、CRL
编解码、OCSP
协议、数字证书验证、PKCS7
标准实现和 PKCS12
个人数字证书格式实现等功能。然而一直以来 OpenSSL 代码质量,总是受到开发人员的各种诟病,因而出现了WolfSSL 与 PolorSSL 等 OpenSSL的开源替代产品,其中 PolarSSL 被 ARM 公司收购之后,现更名为 Mbed TLS,主要由 TrustedFirmware 组织进行维护,遵循相关的 ARM 规范,并为Armv8-A、Armv9-A、Armv8-M内核架构提供了安全可信的参考实现。本文主要主要讨论了Base64 与 Hash 编码、以及 OpenSSL所涉及的相关加解密知识。
Base64 是一种基于 64个可打印字符来表示二进制数据的方法,因为 \(\log_2 64 = 6\),所以每 6 bits
为一个单元,对应某个可打印字符。例如 3 Bytes
相当于24 bits
,对应于 4
个 Base64 单元,即3
个字节可由 4
个可打印字符来表示。Base64编码常被用于表示、传输、存储一些二进制数据。
Base64 当中的可打印字符包括字母 A-Z
和a-z
,以及数字 0-9
共有 62个字符,此外还包括 2个可打印的符号,在不同的操作系统当中表现不同:
注意 1:标准 Base64 编码并不适用于在HTTP 环境下通过 URL传递较长的信息,这是由于 URL 编码器会将标准 Base64 当中的
/
和+
字符转换为形如%XX
的形式,由于标准 SQL语句当中将%
符号用作通配符,而这些%
号在存入数据库时还需要再一次进行转换。为了解决这个问题,可以采用一种用于URL 的改进 Base64 编码,其并不会在末尾填充=
号,并将标准Base64 中的+
与/
分别修改为-
和_
,从而免去了在 URL编解码和数据库存储时所需要进行的额外转换,避免了编码信息长度在此过程中的增加,并且统一了数据库、Web页面表单的标识符格式。
注意2:除此之外,还有一种用于正则表达式的改进Base64 编码变种,其将
+
和/
分别修改为!
和-
,这是由于+
,*
、[
、]
在正则表达式当中可能具有特殊含义。
散列函数(Hash)又称为散列算法或者哈希函数,可以将任意长度的输入通过散列算法转换为固定长度的散列值输出,Hash算法没有固定的公式,只要符合散列思想的算法都可以称为 Hash算法。目前常见的散列算法可以参见下面的表格:
所有的散列函数算法都具备如下 2 个基本特征:
注意:利用散列算法所计算出来散列值的不可逆性(无法逆向演算回原本的数值),可以将其用于加密存储在数据库当中的密码字符串,从而有效的保护密码。
消息摘要算法(MD5,Message-DigestAlgorithm)通过输入不定长度信息,输出四组 32位数据,最后组合成为一个固定长度的 128 bits/16 Bytes
散列值,通常用于确保数据传输的完整性。该算法是由美国密码学家罗纳德·李维斯特(RonaldLinn Rivest)设计,于 1992 年公开,但是已于 1996年在理论上被证实存在破解可能性,并最终于 2004年被证实无法防止碰撞攻击,因而不再适用于安全性认证。
1 | 输入字符串: |
注意:MD5 加密后的位数有
16 Bytes
和32 Bytes
两种,其中16 Bytes
实际上是取32 Bytes
字符串中间的第9 ~ 24
位部分。
安全散列算法(SHA,Secure HashAlgorithm)包含了一系列密码散列函数算法,可以计算出一个消息所对应的固定长度字符串(称为消息摘要),如果输入的消息不同,那么对应的消息摘要也会不同。SHA家族算法由美国国家安全局(NSA)设计,并由美国国家标准与技术研究院(NIST)发布:
SHA-224
、SHA-256
、SHA-384
、SHA-512
、SHA-512/224
、SHA-512/256
,虽然至今尚未出现对该版本算法的有效攻击,但是其算法本质上与SHA-1 基本类似;循环冗余校验(CRC,Cyclic RedundancyCheck)可以根据文件等数据,利用除法及余数的原理,产生简短的固定位数校验码,也属于一种散列函数算法,主要用于校验数据传输完成之后可能出现的错误,能够高比例的纠正数据传输过程当中的错误,并在极短的时间内完成数据校验计算,该方法由W.Wesley Peterson 于 1961 年发表。
对称加密算法(Symmetric-keyAlgorithm)又称为私钥加密、共享密钥加密,属于密码学当中的一类加密算法。这类算法在加密和解密时使用相同的密钥(或者两个可以简单相互推算的密钥),这组密钥将会多个成员之间的共同秘密,以便维持专属的通信联系。与公开密钥加密相比,要求双方获取相同的密钥是对称密钥加密的主要缺陷之一。常见的对称加密算法有AES
、ChaCha20
、3DES
、Salsa20
、DES
、Blowfish
、IDEA
、RC5
、RC6
、Camellia
等等。
非对称式加密算法(AsymmetricCryptography)也称为公钥加密算法(Public-keyCryptography),同样属于密码学当中的一种算法,其加解密过程需要公开密钥(用于加密)和私有密钥(用于解密)2个密钥,使用公钥将明文加密之后所得到的密文,只能使用对应的私钥才能解密并且得到原来的明文,最初用于加密的公钥并不能用作解密。由于加密与解密需要2 个不同的密钥,所以被称为非对称加密;
注意:相比较于加密与解密都要使用同一个密钥的对称式加密,非对称式加密的公钥可以任意向外发布,但是私钥必须自行严格秘密保管,绝不能透过任何途径向外提供。此外,对称加密的速度远远快于非对称加密。
数据加密标准(DES,Data EncryptionStandard),是一种在过去主要使用的对称加密算法,1977年被认定为联邦资料处理标准(FIPS),但是现在已经并非一种安全的加密方法。而DES算法的继任者三重数据加密(3DES,TripleDES),本质上相当于是对每个数据块运用 3 次 DES加密,它并非一种全新的块密码算法,并且在理论上也存在破解方法。
注意:DES 和 3DES标准目前已经逐渐被高级加密标准(AES)所取代。
高级加密标准(AES,Advanced EncryptionStandard),属于美国联邦政府采用的一种区块加密标准,该标准用于替换原先的DES,由美国国家标准与技术研究院(NIST)于 2001 年 11 月 26 日发布,并于2002 年 5 月 26日成为有效标准,目前已经成为对称密钥加密里最为流行的算法之一。
密文 = AES 加密函数(明文,密钥)
;明文 = AES 解密函数(密文,密钥)
;结构上 AES将明文划分为一系列长度相等的数据组,每次只加密一组数据,直至加密完整个明文。在AES 标准规范中,分组长度只能是 128 bits
位,即每个分组为16 Byte
字节,而密钥的长度可以使用128 bits
、192 bits
或者 256 bits
位,密钥的长度不同,推荐加密轮数也不同,具体请参见下面表格:
AES | 密钥长度(32 bits) | 分组长度(32 bits) | 加密轮数 |
---|---|---|---|
AES-128 | 4 | 4 | 10 |
AES-192 | 6 | 4 | 12 |
AES-256 | 8 | 4 | 14 |
RSA 是一种非对称加密算法,由 RonRivest、Adi Shamir、LeonardAdleman 三位麻省理工学院的学者于 1977 年共同提出,RSA就是由 3 位的姓氏首字母组成。对于极大整数做因数分解的难度决定了 RSA算法的可靠性(假如找到一种快速因数分解的算法,那么 RSA的可靠性就会极度下降,但找到这样算法的可能性微乎其微),RSA诞生近半个世纪后的今天,仅有较短的 RSA密钥才有可能会被暴力破解。除此之外,世界上还没有任何可以攻击 RSA算法可靠性的方式,只要其密钥的长度足够长,采用 RSA加密后的信息基本不可能被破解。
下面是一个基于 RSA算法的典型双向非对称加密握手步骤:
使用 OpenSSL签名一个文件需要使用到私钥,可以通过下面的命令创建OpenSSL 公私钥对:
1 | 生成保存私钥的文件 private.pem |
上述命令中的 <phrase>
密码短语用于加密存储在private.pem
文件里的私钥,出于安全的原因,建议使用4096 bits
位的私钥,具体原因可以参见 《RSAKey Sizes: 2048 or 4096bits?》一文。当命令执行完毕之后,私钥将会被保存在当前目录下的private.pem
文件,而公钥则会被保存在public.pem
文件。
【示例】:将 <phrase>
密码短语设置为 Hank
,然后使用 OpenSSL命令生成私钥文件:
1 | ➜ sudo openssl genrsa -aes128 -passout pass:Hank -out private.pem 4096 |
【示例】:然后,再通过上面得到的private.pem
文件,来生成对应的公钥文件public.pem
:
1 | ➜ sudo openssl rsa -in private.pem -passin pass:Hank -pubout -out public.pem |
拥有了公钥与私钥之后,接下来就可以使用OpenSSL 签名一个文件,这个过程当中将会要求提供密码短语<phrase>
。由于过去 OpenSSL签名的默认输出格式为二进制,如果希望在互联网上进行传输,则需要采用Base64
对签名文件进行编码转换:
1 | 基于私钥生成签名文件 |
上述语句中的 <private-key>
是包含私钥的文件,<target-file>
为待签名的文件,而<base64-signature>
为 Base64格式的数字签名的文件名,操作完成之后签名文件将会保存为 /opt
目录下的 signature.sha256
文件。
【示例】:使用前一步生成的私钥文件private.pem
对当前目录下的 uinika.c
文件进行签名,得到一个二进制签名文件 signature.sha256
:
1 | ➜ sudo openssl dgst -sha256 -sign private.pem -out signature.sha256 uinika.c |
【示例】:将 /opt
目录下的二进制文件signature.sha256
转换为 Base64 编码的signature.base64
文件:
1 | ➜ sudo openssl base64 -in signature.sha256 -out signature.base64 |
注意:目前新版本的 OpenSSL签名文件,已经可以正常在互联网上传输,不需要再进行额外的 Base64编码。
将签名从 Base64编码重新转换回二进制文件,并使用前面得到的公钥来验证该签名文件:
1 | 将签名文件从 Base64 编码还原为二进制格式 |
上述命令当中的 <base64-signature>
是包含 Base64签名的文件,而 <public-key>
是包含公钥的文件,<target-file>
则是待验证的二进制签名文件。验证成功之后,OpenSSL 将会提示Verified OK
,否则就会提示verification Failure
。
【示例】: 把 Base64 编码的签名文件signature.base64
还原为二进制格式的签名文件signature.sha256
:
1 | ➜ sudo openssl base64 -d -in signature.base64 -out signature.sha256 |
【示例】:通过目标文件 uinika.c
和公钥文件 public.pem
校验还原得到的signature.sha256
是否有效:
1 | ➜ sudo openssl dgst -sha256 -verify public.pem -signature signature.sha256 uinika.c |
传输层安全性协议(TLS,Transport LayerSecurity)以及其前身安全套接层(SSL,SecureSocketsLayer)都属于一种安全协议,目的是为互联网通信提供安全以及数据完整性保障。网景公司(Netscape)于1994 年推出第 1 版网页浏览器时发布了 HTTPS 协议,并以 SSL 进行加密,后来IETF 将 SSL 进行标准化,于 1999 年公布了TLS 1.0
,随后又于 2006 年公布了 TLS 1.1
,2008年公布了 TLS 1.2
,以及在 2018 年公布的TLS 1.3
,目前该协议已经成为互联网加密通信的工业标准。
TLS 协议采用主从式架构模型,用于在网络上的 2个应用程序之间创建安全的连接,防止在交换资料时受到窃听以及篡改。TLS协议与高层的 HTTP
、FTP
、Telnet
等应用层协议并不会产生耦合,这些应用层协议透明的运行在 TLS 之上,由 TLS进行创建加密通道需要的协商与认证,应用层协议传送的数据通过 TLS协议时都会被加密,从而保证通信的私密性。
TLS协议必须在客户端与服务器分别配置之后才能使用,一旦客户端和服务器都同意使用TLS协议,那么它们会通过一个握手过程,协商出一个带有状态的连接用于传输数据,如下就是握手建立的具体步骤:
服务器的名称
、受信任的证书颁发机构(CA)
、服务器的公钥
;注意:握手完毕之后的连接是安全的,直到该连接被关闭为止;如果上述任何一个步骤失败,TLS的握手过程就会失败,并且断开所有连接;
公钥数字签名也称为数字签名(DigitalSignature),其实质就是逆向使用非对称加密体系,即签名者将信息用私钥加密(非对称加密体系下,私钥通常用于解密),然后将公钥发布出去,验证者使用公钥将加密信息解密并且比对消息(非对称加密体系下,公钥通常用于加密)。
概而言之,非对称加密体系下,通常使用公钥加密,私钥解密
。而在数字签名当中,则是使用私钥加密(生成签名),公钥解密(验证签名)
。
我们可以直接对数据进行签名(即使用私钥加密,其目的是为了签名,而非保密),验证者用公钥正确解密消息,如果和原始数据保持一致,则签名验证成功。通常情况下,我们只会对数据的Hash 值进行签名(但是计算数据 Hash 值并非数字签名的必要步骤),因为 Hash值的长度远远小于原始数据的长度,从而使得签名(非对称加密)的效率大幅度提高。
注意:工程实践当中,通常会组合使用加密与签名技术,例如前面提到的TLS 协议就同时组合了加密与签名。
数字证书认证(CA,CertificateAuthority)是用于实现多方安全通信所提供电子认证,其本质上是由证书签证机构CA 签发的对于用户公钥的认证。这里的 CA即指代负责发放与管理数字证书的权威机构,也指代其所承担的位于非对称加密体系当中的公钥合法性校验任务,主要具有如下的作用与特点:
数字证书的内容包括有CA 机构的相关信息
、公钥用户信息
、公钥
、CA 机构的签名与有效期
等,目前数字证书的格式与验证方法普遍遵循 X.509公钥证书格式标准。
X.509是密码学当中公钥证书的格式标准,应用于 TLS/SSL在内的众多网络协议当中。X.509证书当中包含有公钥、身份信息(比如网络主机名,组织或个体名称等)、签名信息(即可以是证书签发机构的CA 签名,也可以是自签名)。
注意:在 X.509当中,组织机构通过发起证书签名请求(CSR,CertificateSigning Request)来获得一份签名证书。
X.509 拥有如下几种常用的扩展名:
.pem
:隐私增强型电子邮件格式,通常为 Base64 格式;.cer
、.crt
、.der
:通常为 DER二进制格式;.p7b
、.p7c
:PKCS#7格式,不包含数据,只包含证书或者 CRL;.p12
:PKCS#12格式,包含证书的同时可能还包含有私钥;.pfx
:PFX,在 PKCS#12
出现之前使用的格式;注意:PKCS#7是签名或者加密数据的格式标准,由于证书是可以进行校验的签名数据,所以采用签名数据(SignedData)结构进行表述;而PKCS#12 则是由 PFX格式发展而来,用于交换公有或者私有对象的标准格式。
国密算法主要是经由《密码管理局》和《密码行业标准化技术委员会》认定的国产密码算法,当前使用较为广泛的主要是以下5 种:
ECDSA
、ECDH
等国际标准,该标准包括总则
、数字签名算法
、密钥交换协议
、公钥加密算法
四个部分;数字签名
与验证
;该算法对输入长度小于\(2^{64}\)次方的数据,经过填充与迭代压缩,生成长度为 256 bits
位的杂凑值,该算法由填充
、迭代过程
、消息扩展
、压缩函数
四部分构成。128 bits
位,加密算法与密钥扩展算法都采用 32轮非线性迭代结构,其中加解密算法的结构相同,只是轮密钥的使用顺序相反,解密轮密钥
是加密轮密钥
的逆序;]]>注意:密码行业标准化技术委员会(CSTC,CryptographyStandardization TechnicalCommittee)是一家国内从事密码标准化工作的非法人技术组织,归属密码管理局领导和管理,主要从事密码技术、产品、系统和管理等方面的标准化工作。
本篇文章讲解了数字逻辑电路的分析与设计所涉及到的基础理论,首先讲解了数制
、码制
和逻辑代数
等基础知识,接着重点描述组合逻辑电路
和时序逻辑电路
的分析与设计方法,然后讨论了各种数字集成电路
(含门电路、可编程逻辑元件、半导体存储器)的原理以及使用方法,并且介绍了硬件描述语言
与可编程逻辑器件
的相关知识,最后一部分讲解AD/DA
转换以及脉冲波形
的产生和转换电路。
模拟信号的电压或者电流在幅值和时间上都是离散的:
数字信号的电压或者电流的幅值随着时间连续变化:
数字信号可以采用高、低电平来表示,它们统称为逻辑电平:
0
;1
;CMOS元器件电压值范围与数字逻辑电平之间的对应关系:
电压范围 | 逻辑值 | 逻辑电平 |
---|---|---|
\(3.5V \sim5V\) | 1 | 高电平 H |
\(0V \sim1.5V\) | 0 | 低电平 L |
\(1.5V \sim3.5V\) | 无定义 | 无定义 |
数字波形是信号的逻辑电平相对于时间的图形化表达方式:
实际脉冲波形在高、低电平跳变时,边沿不是陡直的,都需要经历一个过渡过程:
V
;ns
;ns
;▶【例题】假设周期性矩形脉冲波形的高电平持续时间为6ms
,低电平的持续时间为 10ms
,求解占空比q
和频率 f
?
▶【解答】根据条件可以得到脉动宽度 \(t_w =6ms\) 和周期 \(T = 6ms + 10ms =16ms\),从而可以计算出:
\[\begin{aligned} 占空比 &\implies q = \frac{6 ms}{10 ms} \times 100\% = 37.5\% \\ 频率 &\implies f = \frac{1}{T} = \frac{1}{16 \times 10^{-3}s} =62.5 Hz\end{aligned}\]
数制是一种计数规则,主要是指每一位的构成,以及从低位向高位的进位。例如:十进制是以10
为基数的计数体制,采用0
、1
、2
、3
、4
、5
、6
、7
、8
、9
十个数值,其进位的规则是逢十进一。
二进制则是以 2
为基数,采用0
和 1
两个数值,其进位规则是逢二进一,其中左侧是最高有效位(MSB),右侧为最低有效位(LSB)。
注意:二进制数中的每 1 个二进制数称为
1 bit
位,而 8 位二进制数被称为1 Byte
字节。
下面的表格对照了十(Decimal)、二(Binary)、八(Octonary)、十六(Hexadecimal)进制的特点:
下面的表格展示了常用进制数值的换算关系:
二进制数转换为十进制的方法,按照按权展开公式进行计算。即将每个位上的数值与相应位置的权相乘,最后再求和。
▶【例题】将二进制整数 \((10011101)_2\) 转换为十进制数。
▶【例题】将二进制小数 \((0.1011)_2\)转换为十进制数。
十进制整数转换为二进制数主要有加权求和法、除二取余法两种方式。
加权求和法是通过确定一组二进制权,让它们的和等于已知十进制数。
▶【例题】将十进制整数 \((9)_{10}\)转换为二进制数。
▶【例题】将十进制整数 \((82)_{10}\)转换为二进制数。
▶【例题】将十进制整数 \((125)_{10}\)转换为二进制数。
除二取余法是将十进制整数除以 2
取其余数,所得之商再除以 2
,再取其余数,如此重复直到商为0
,每次得到的余数就构成了二进制数的对应位。其中,第一个余数为二进制数的最低位,最后一个余数为二进制数的最高位。
▶【例题】将十进制数 \((45)_{10}\)转换为二进制数。
十进制小数转换为二进制数同样可以选择加权求和法、除二取余法两种方式。
加权求和法是通过确定一组二进制权,让它们的和等于已知十进制数。
▶【例题】将十进制小数 \((0.625)_{10}\) 转换为二进制数。
除二取余法是将十进制整数除以 2
取其余数,所得之商再除以2
,再取其余数,如此重复直至小数部分为 0
或者小数部分的位数满足误差要求,然后四舍五入为止,每次得到的整数就构成了二进制数的对应位。
▶【例题】将十进制小数 \((0.3125)_{10}\) 转换为二进制数。
▶【例题】将十进制小数 \((0.562)_{10}\)转换为二进制数,要求转换误差小于 \(1\%\)。
如果误差要求小于 \(1\%\),那么 \(2^{-m} \le 1\% \implies m \ge \frac{2}{\lg 2} =6.64 \implies m = 7\),即保留 7 位二进制结果即可:
接下来校对上面得到二进制结果 \((0.1000111)_{2}\) 的转换误差,
由于 \((0.562)_{10} - (0.555)_{10} \approx0.7\%\) 误差小于 \(1\%\),所以最后得到的二进制结果满足转换误差的要求。
由于 4 位二进制数恰好拥有 16 个状态,如果将这 4位二进制数看作整体,其进位输出正好是逢十六进一,所以可以采用分组转换法,即以二进制数的小数点为基准,整数部分从右至左每4 位分成一组,而小数部分从左至右每 4 位也分成一组,不足 4 位的以0
进行补足,然后将每一组数以一个十六进制数代替。
▶【例题】将二进制小数 \((1101\ 1001\ 1011\0011 . 01)_{2}\) 转换为十六进制数。
所以,最终的转换结果为 \((1101\ 1001\ 1011\0011.01)_2 = (D9B3.4)_{16}\)。
将每个十六进制数改写为等值的 4位二进制数即可,并且保持高低位的次序不变。
▶【例题】将十六进制小数 \((4E6.97C)_{16}\) 转换为二进制数。
所以,最终的转换结果为 \((4E6.97C)_{16} =(0100\ 1110\ 0110. 1001\ 0111\ 1100)_2\)。
可以根据按权展开公式进行计算,即将每个数与相应位置上的权相乘,然后再进行求和运算。
▶【例题】将十六进制小数 \((3A.C)_{16}\) 转换为十进制数。
所以,最终的转换结果为 \((3A.C)_{16} =(58.75)_{10}\)。
将十进制转换为十六进制,可以先转换为二进制数,然后再将得到的二进制数转换为等值的十六进制数。
当然,也可以采用除以十六取余法直接从十进制整数转换为十六进制。
▶【例题】将十进制整数 \((650)_{10}\)转换为十六进制数。
对于十进制小数转换为十六进制,则需要使用乘以十二取整法。
▶【例题】将十进制小数 \((0.75)_{10}\) 转换为十六进制数。
当两个二进制数表示两个数量大小时,它们之间可以进行数值运算,这种运算称为算术运算。
二进制数加法的运算规则与十进制数加法类似,只是其进位规则为逢二进一。
对于一位二进制数的相加运算,会向左侧相邻的高位产生进位:
对于多位二进制数的加法从最低位(最右侧)开始,每次取被加数和加数的一位相加,然后逐一向左侧相邻的高位进位。
二进制减法运算当中,当 0
减去 1
不够减时,需要向左边高位进行借位,借的这一位作为 10
处理(即十进制数 2
),也称为借一为二。
\[\begin{aligned} 0 - 0 &= \color{Red}0 &\implies 借位为\ \color{Green}0 \\ 1 - 0 &= \color{Red}1 &\implies 借位为\ \color{Green}0 \\ 1 - 1 &= \color{Red}0 &\implies 借位为\ \color{Green}0 \\ 0 - 1 &= \color{Red}-11 &\implies 借位为\ \color{Green}1 \\\end{aligned}\]
当两个一位二进制数相减时,如果低位向本位的借位一直为1
,那么计算的四种情况为:
当两个多位二进制数相减时,从最低位(最右边)开始,每次取被减数与减数的1位相减;同时还要考虑低位向本位的借位,如果被减数小于减数,就要将减数与被减数交换位置,用减数减去被减数,然后在差值的前面添加负号-
。
被乘数与乘数中某一位相乘的结果,称为部分积。
\[\begin{aligned} 0 \times 0 &= \color{Red}0 \\ 0 \times 1 &= \color{Red}0 \\ 1 \times 0 &= \color{Red}0 \\ 1 \times 1 &= \color{Red}1 \\\end{aligned}\]
▶【例题】计算两个四位二进制数 \(1011\) 和 \(1001\) 的积?
所以,多位二进制数 \(1011\) 乘以\(1001\) 的积为 \(1100011\)。
注意:计算机当中,乘法运算是通过左移被乘数、加法两种运算共同完成的。
从被除数的最高位开始,逐位向低位不断减去除数,够减时商为1
,不够减时商为0
,这样不断减下去就可以求得商。在二进制除法当中,每一位商的值为0
或者 1
。
\[\begin{aligned} 0 \div 1 &= \color{Red}0 \\ 1 \div 1 &= \color{Red}1 \\\end{aligned}\]
注意:类似于十进制的除法,二进制的除数不能为
0
,否则没有意义。
▶【例题】计算两个四位二进制数 \(1010\) 和 \(111\) 的商?
注意:计算机当中,除法运算是通过右移被除数、减法两种运算共同完成的。
日常生活当中,通常在一个数的前面采用 +
号表示正数,减号-
表示负数。由于数字系统只能识别和处理 0
和1
表示的二进制数据,因此通常将正号 +
用 0
表示负号用 1
表示。将数的符号和值分别用 0
和 1
进行编码,所表示出来的二进制数称为机器数,机器数真正的值(即用正负符号表示的十进制或二进制数值)称为真值。机器数可以分为有符号和无符号两种类型:
有符号数可以进一步分为原码、反码、补码形式:
原码就是将正数的符号位用 0
表示,负数的符号位用 1
表示,数值用绝对值的二进制数形式表示。
因此,真值 0
也会拥有 +0
和 -0
两种不同的表示形式:
注意:计算机当中,位
bit
是二进制数据的最小单位,一位二进制数就是1
比特(bit
),通常将8
位二进制数称为1
字节(Byte
),而4
位二进制数称为半字节(Nibble
/ˈnɪbl/)。
原码简单易懂且便于转换为真值,但是实现加、减运算较为麻烦。为了简化计算机的处理过程,通常会将减法运算转换为加法运算,于是引进了补码的概念。由于补码与反码之间存在一定的换算关系,所以这里首先对反码进行介绍。
1
,数值部分则按位取反;反码当中 0
同样拥有 +0
和 -0
两种不同的表示形式:
减法运算 10 – 5
可以用 10 + 7
的加法运算来代替,而 5
和 7
相加正好是进位的模数 12
,所以称 7
为-5
对模 12
的补数,也称为补码。
模是指一个计量系统的量程,例如时钟能够表示 \(1 \sim 12\),那么以 \(12\)作为一个计数循环就被称为模。而四位二进制数能够表示\(0000 \sim 1111\) 其模为16
,同理八位二进制数的模为 \(2^8= 256\)。
所以,在舍弃进位的条件下,减去某数的计算可以采用加上这个数补码的计算来代替,该结论同样适用于二进制数的减法运算。
例如减法 \(1011 - 0111 = 0100\)对应的十进制形式为 \(11 - 7 =4\),在舍弃进位的条件下,可以采用 \(1011 + 1001 = 0100\)形式代替,对应的十进制等式是 \(11 + 9 =4\)。这是因为四位二进制数的模数为 16
,而9
恰好就是 -7
对模 16
的补码。
1
的负数,数值部分为其绝对值按位取反,并在最低位加1
,即负数的补码等于其反码加上一;注意,补码当中,真值 0
的表示是唯一的,即:
负数补数的简便求解方法:从右侧最低位向左侧最高位扫描,保留出现第一个1
的位,后续的其它位全部按位取反,符号位保持不变。
▶【例题】使用八位二进制数,将 -90
用补码表示出来:
▶【例题】使用八位二进制数,将 -1
用补码表示出来:
求解一个补码的补码,就可以将补码转换成原码,即\([[x]_补]_补 = [x]_原\)。
▶【例题】求解 \([1010 1010]_补\)的原码和真值?
将补码当中所有等于 1
的位的权值相加(包括符号位,负数的符号位的权值被赋予负值),就可以得到其十进制数。
▶【例题】确定补数 \([0101\0110]_补\) 和 \([1010\1010]_补\) 的十进制值?
\[[0101\ 0110]_补 = 1 \times 2^6 + 1 \times 2^4 + 1 \times 2^2 + 1\times 2^1 = 64 + 16 + 4 + 2 = +86\]
\[[1010\ 1010]_补 = 1 \times (-2)^7 + 1 \times 2^5 + 1 \times 2^3 + 1\times 2^1 = -128 + 32 + 8 + 2= -86\]