8. PWM
8.1 PWM介绍
PWM(Pulse Width Modulation 脉宽调制)是利用微处理器的数字输出来对模拟电路进行控制的一种非常有效的技术。PWM 是一种对模拟信号电平进行数字编码的方法。是指在一定时间内波形的高电平(即 1 状态)所占用的时间比例。通过高分辨率计数器的使用,方波占空比被调制用来对一个具体模拟信号的电平进行编码。PWM 信号任然是数字的,因为在给定的任何时刻,满幅值的直流供电要么完全有,要么完全无。比如我们的电压输出是 5v 的,那么经过改变 PWM 的占空比,可以达到在一定时间内输出 3.3V 或者 1.3V 的效果。
举个例子
想象你有一个LED和一个开关,你以肉眼看不清的速度,快速反复地开关一次,这样LED灯就会亮一半时间,暗一半时间。如果你快速地进行这个操作,对于观察者来说,LED就像是以半亮度持续亮着。这就是PWM的基本原理。 如果你把大部分时间保持开关为关闭状态,那么LED会显得更暗;相反,如果你把开关大部分时间保持为打开状态,LED会显得更亮。这就是PWM调节占空比来控制亮度的过程。
8.2 PWM的基本参数
PWM 是脉冲宽度调制,具有两个非常重要的参数:频率和占空比。
频率
:PWM 信号的周期长度,通常使用赫兹 (Hz) 表示,表示每秒钟有多少个脉冲。PWM 的频率是整个周期的倒数。指 1 秒钟内信号从高电平到低电平再回到高电平的次数(一个周期)占空比
:占空比是指一个周期内高电平所占的比例。占空比可以表示为百分比,比如50%的占空比意味着高电平持续一半的周期,然后低电平持续另外一半。分辨率
:ESP32 支持的 PWM 信号分辨率是指设备可输出的不同占空比级别的数量。例如,8 位分辨率就表示设备可以输出 2^8 个不同占空比级别,即 0%、1/256、2/256 … 直到 100%。
8.3 ESP32S3上的PWM
在ESP32-S3中有两个硬件外设可以输出PWM信号,分别是LED PWM 控制器 (LEDC) 和 电机控制脉宽调制器 (MCPWM)。它们各有其特点和用途:
LED PWM 控制器 (LEDC)
:这个模块的主要设计目标是产生高精度的 PWM 波形,用以控制 LED 灯的亮度或者产生声音。LEDC 的分辨率可以达到 16 位,能够产生准确且平滑的变化,适用于控制 LED 灯的亮度和产生声音。并且,LEDC 支持多达 8 个通道的 PWM 输出。用户可以配置每个通道的频率和占空比。电机控制脉宽调制器 (MCPWM)
:这个模块主要用于马达控制,包括伺服马达、步进马达和普通电机。MCPWM 支持更加复杂的控制模式,如电机的向前/向后驱动、断电刹车等,并且支持闭环控制模式,能满足更复杂的电机控制需求。MCPWM 支持高达 6 个通道的独立 PWM 输出,并且支持死区控制和外部信号捕获。
总的来说,它们两者在处理 PWM 方面有所不同,并被应用于不同的场景。LEDC 更加适合控制灯光、声音等线性设备,而 MCPWM 包含更高级的功能,适合马达控制。本章我们以LED PWM 控制器作为案例输出PWM,后面简称LEDC。
8.4 PWM 的控制流程
使用 ESP32S3 的 PWM 功能在 MicroPython 中的流程如下:
- 导入相关的模块和库:
import machine
- 初始化 PWM 对象:
classmachine.PWM(dest, \*, freq, duty_u16, duty_ns)
PWM 可以通过 ESP32S3 所有 GPIO 引脚输出。所有通道都有 1 个特定的频率,从 1 到 40M 之间(单位是 Hz)。占空比的值为 0 至 1023 之间。
PWM 在 machine 的 PWM 模块中,我们也是只需要了解其构造对象函数和使用方法:
构造函数 machine.PWM(dest, freq, duty, duty_u16, duty_ns),使用以下参数构造并返回一个新的 PWM 对象:
- dest 是输出 PWM 的实体,通常是 machine.Pin 对象;
- freq 应该是一个整数,用于设置 PWM 周期的频率(以 Hz 为单位);
- duty 占空比,范围是 0 - 1023;
- duty_u16 占空比,范围是 0 - 65535,2 的 16 次方;
- duty_ns 以纳秒为单位设置脉冲宽度,范围是 0 - 50000。
示例:
pin_number = 48
pwm = machine.PWM(machine.Pin(pin_number))
2
- 配置 PWM 信号的频率和占空比:
pwm.freq(desired_frequency) #获取或设置 PWM 输出的当前频率。
pwm.duty(desired_duty_cycle)#获设置 PWM 输出的占空比。
2
desired_frequency 参数是希望设定的 PWM 信号的频率,单位为 Hz。
desired_duty_cycle 参数是 PWM 信号的占空比,范围为 0-1023,表示 0%-100% 的占空比。
在初始化PWM后,可以在任何时候通过调用 freq() 和 duty() 方法来更改 PWM 信号的频率和占空比。
- 修改 PWM参数:c
pwm.deinit() # 先关闭 PWM 输出,确保初始化状态 pwm.init()
1
2c修改 PWM 对象的设置。有关参数的详细信息,请参阅前面的构造函数.PWM。PWM.init(\*, freq, duty_u16, duty_ns)
1
在调用 init() 方法之前,最好先调用 deinit() 方法关闭 PWM,以确保处于初始化状态。
- 关闭 PWM 输出:
pwm.deinit()
这将关闭 PWM 输出,并释放相关资源。
资料参考官方MicroPython文档:
http://www.86x.org/en/latet/library/machine.PWM.html#machine-pwm
8.5 硬件连接与准备
本案例使用板载的LED进行呼吸灯测试。一般人眼睛对于 80HZ 以上刷新频率则完全没有闪烁感,由于频率很高时看不到闪烁,占空比越大 LED 越亮,占空比越小 LED 越暗。所以在频率一定时,可以用不同占空比改变 LED 灯的亮度,使其达到一个呼吸灯的效果(逐渐亮在逐渐灭,如此反复)。
板载的LED接到的引脚是GPIO48,所以我们在初始化时,需要将LEDC功能绑定到GPIO48。
8.6 PWM呼吸灯验证
import time from machine import Pin, PWM
# 创建 LED 控制对象
led = PWM(Pin(48), freq=1000)
while True:
# 渐亮
for i in range(0, 1024):
led.duty(i)
time.sleep_ms(1)
# 渐暗
for i in range(1023, 0, -1):
led.duty(i)
time.sleep_ms(1)
2
3
4
5
6
7
8
9
10
11
12
13