3.14. 使用 PWM 进行 LED 调光¶
用 PWM 和 RC 滤波器生成模拟量 页面使用 RC 低通滤波器从 PWM 信号中提取出直流电压。对于 LED 而言,并不需要该滤波器——人眼本身就完成了取平均的工作。
当 LED 以快于约 60 Hz 的频率开关时,视觉系统就无法再分辨单个脉冲,而会感知到一个等于平均光输出的稳定亮度。50 % 的占空比看起来大约是一半亮度;25 % 是四分之一;10 % 则很暗。
接线方式与 GPIO 输出 中静态外接 LED 的方式相同——一个与 LED 串联的限流电阻,其阻值依据 电子学基础 中的规则来确定。改变的仅是软件部分:该引脚作为 PWM 输出运行,而不是普通的 Pin.OUT。
3.14.1. 选择频率¶
对于 LED 调光,PWM 频率只需越过人眼的闪烁阈值即可:
低于约 60 Hz 时,人眼会直接看到脉冲。
低于约 200 Hz 时,余光视觉和快速的眼球运动仍可能察觉到闪烁。
1 kHz 舒适地高于上述所有阈值,是一个典型的默认值。
对于 GPIO 上的小型 LED 而言,没有什么有意义的上限;从 1 kHz 到 10 kHz 的任何频率对人眼来说表现都相同。
3.14.2. 渐变¶
渐入/渐出循环将占空比从关闭扫到完全开启再扫回来,并在每一步短暂停留:
import time
from machine import PWM, Pin
led = PWM(Pin("P7"), freq=1000, duty_u16=0)
while True:
for d in range(0, 65535, 256):
led.duty_u16(d)
time.sleep_ms(5)
for d in range(65535, 0, -256):
led.duty_u16(d)
time.sleep_ms(5)
在 1 kHz PWM 和 5 ms 步进下,人眼会看到两个方向上都很平滑的渐变,表观亮度跟随占空比的数值变化。
感知亮度与占空比并非严格的线性关系——人眼的响应大致遵循平方或立方律——因此 duty_u16 的线性扫描看起来并不像亮度的线性扫描。要获得感知上更平滑的渐变,应按曲线来步进占空比。
一个便利的纯整数技巧是:步进一个 8 位计数器,并用它的平方作为占空比。255 × 255 = 65025 在舍入误差范围内已接近满量程,因此扫描可以覆盖整个范围:
import time
from machine import PWM, Pin
led = PWM(Pin("P7"), freq=1000, duty_u16=0)
while True:
for step in range(256):
led.duty_u16(step * step) # 0..65025, roughly quadratic
time.sleep_ms(5)
for step in range(255, -1, -1):
led.duty_u16(step * step)
time.sleep_ms(5)
现在从关闭到全亮,渐变在表观亮度上感觉大致均匀。