PWM 简介

PWM 的全称为 Pulse Width Modulation, 翻译成中文是 脉冲宽度调节, 是把模拟信号调制成脉波的技术. 数字信号只有低电平 0 和高电平 1 两种. 通过以快速切换高低电平来控制传感器引脚上的电压(和电流)的平均值.
举个 LED 灯的例子: 控制LED, 亮 1s1s 往复循环, 肉眼可见 LED 在不断闪烁. 然后把间隔时间缩短为: 亮 100ms100ms 往复循环就可以看到 LED 在快速闪烁. 把这个变换的持续缩小, 小于肉眼的视觉暂留时间, 人眼就会分辨不出来 LED 在闪烁, 而此时 LED 的亮度处在灭与亮之间,这时候 LED 就达到了正常的 1/2 亮度.

Duty_Cycle_Examples

当然亮的时间和暗的时间是可以不相等的, 这个比例是可以调节的. 通过这个比例的调节可以实现控制 LED 亮度的目的. 这个比例就是占空比(duty), 占空比的完整定义: 在一个周期内, 高电平时间占总体周期的比例. 例如假设 PWM的控制周期为 10ms, 其中 8ms 为高电平, 2ms 为低电平, 则占空比就是 8/10 = 80%

在多数单片机中, 占空比并不是百分比. ESP32 的占空比取值范围为 0 <= duty <= 1023. 其本质就是把工作电压 0-3.3v 划分为 1024 个离散值.
PWM 的第二个属性就是频率. 根据常识,频率为控制周期T的倒数. 假设 10ms 就是控制周期,那频率就是 1 / 0.1 = 10HZ. 频率的取值范围也是由由硬件决定的, ESP32PWM 频率范围为 0 < freq < 78126.

MicroPython-PWM

MicroPython 提供了专门针对 PWM 的模块.

PWM 定义

首先是使用相应的引脚创建对应的对象, 然后调用对象的 init 方法传入频率和占空比初始化对象:

1
2
3
4
5
6
from machine import Pin,PWM

pin = Pin(12, Pin.OUT)
pwm = PWM(pin)
# 初始化PWM 频率=1000, 占空比=512
pwm.init(1000, 512)

也可以在新建 PWM 对象的时候直接传入频率和占空比:

1
2
3
4
from machine import Pin,PWM

pin = Pin(12, Pin.OUT)
pwm = PWM(pin, freq=1000, duty=512)

单独设置频率和占空比

除了定义的时候申明外, PWM 类还提供了单独设置频率和占空比的方法:

1
2
led.freq(1000) # 设置频率
led.duty(512) # 设置占空比

关闭 PWM

使用完了 PWM 需要关闭对象:

1
led.deinit()

示例: PWM调节LED亮度

1
2
3
4
5
6
7
8
9
10
from machine import Pin,PWM

led = PWM(Pin(12, Pin.OUT), freq=1000)
while True:
led.duty(1023)
time.sleep(1)
led.duty(512)
time.sleep(1)
led.duty(0)
time.sleep(1)

结合 MQTT 就可以写出一个可以通过网络控制的 LED 灯节点:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
from machine import Pin,PWM
import math

led = PWM(Pin(12, Pin.OUT), freq=1000)
led.duty(1023)

def breathing():
while True:
for i in range(1024):
led.duty(i)
client.check_msg()
for i in range(1023, 0, -1):
led.duty(i)
client.check_msg()

def mqtt_callback(topic, msg):
msg = json.loads(msg)
if "mode" in msg:
if msg['mode'] == "breathing":
breathing()
else:
led.duty(msg['data'] % 1024)

client = MQTTClient(TYPE + ": " + mac, config["MQTT_HOST"], config["MQTT_PORT"], config["MQTT_ACCOUNT"], config["MQTT_PASSWORD"])
client.set_callback(mqtt_callback)
client.connect()
client.subscribe(mac)

while True:
client.check_msg()
time.sleep(0.2)