PWM与呼吸灯¶
概要¶
-
脉宽调制技术的原理与属性(占空比,频率)
-
MicroPython-ESP32 PWM部分的API文档
-
通过PWM脉宽调节技术控制LED的亮度的演示实例。
keywords : 占空比 PWM LED 呼吸灯
提出问题¶
之前我们一直在使用数字信号来控制LED灯的亮灭,那我们该如何使用数字信号控制小灯的亮度呢?
这就不得不提及我们的PWM脉宽调制技术了。
PWM脉宽调制技术¶
PWM的全称为Pulse Width Modulation,翻译成中文是脉冲宽度调节,是把模拟信号调制成脉波的技术。
如果控制LED,亮1s,然后灭1s, 往复循环, 那我们可以看到LED在闪烁。如果我们把这个周期缩小到200ms,亮100ms,然后灭100ms,往复循环, 可以看到LED灯在高频闪烁。这个周期持续缩小,持续缩小,总有一个临界值,我们的人眼分辨不出来LED在频闪,而此时LED的亮度处在灭与亮之间亮度的中间值, 达到了1/2亮度。
我们可以调节一个周期内,LED亮与灭的比例, 通过调节比例,就可以达到控制LED亮度的目的。在一个周期内,高电平时间占总体周期的比例,称之为占空比 (duty)。
例如PWM的控制周期为100ms,其中20ms为高电平,80ms为低电平,则占空比就是 20/100 = 20%。
注意有时候占空比有时候在嵌入式并不是百分比,而是参考其分辨率。有的单片机例如Arduino,它的占空比取值为0-255。
ESP32的duty取值范围为
0 <= duty <= 1023
分辨率越高,也就意味着你可以调节的亮度的档位也就越高,引脚输出的平均电压处于0-3.3v之间 划分成1024份,你可以取其任意一个。
PWM的第二个属性就是频率, 频率为控制周期T的倒数。在上面这个例子里面,100ms就是控制周期,那频率就是
1s / 0.1s = 10HZ
频率的取值范围由硬件决定,ESP32的PWM频率范围为0 < freq <= 78125
PWM-常用API¶
PWM可在所有输出引脚上启用。但其存在局限:须全部为同一频率,且仅有8个通道。频率须位于1Hz和78125Hz之间.
在引脚上使用PWM,您须首先创建一个引脚对象,例如:
这里用的是GPIO2 安信可的NodeMCU-32S开发板的板载LED
>>> from machine import Pin,PWM >>> led_pin = Pin(2, Pin.OUT)
使用以下指令创建PWM对象:
# 把Pin对象传入PWM的构造器中 >>> led_pwm = PWM(led_pin) # 初始化PWM 频率=500, 占空比=512 >>> led_pwm.init(500, 512)
或者初始化的时候,一步到位
>>> led_pwm = PWM(led_pin, freq=500, duty=512)
您也可使用以下方法设置频率与占空比:
>>> led_pwm.freq(500) >>> led_pwm.duty(512)
注意:占空比介于0至1023间,其中512为50%。若您打印PWM对象,则该对象将告知您其当前配置:
>>> led_pwm PWM(12, freq=500, duty=512)
您也可调用没有参数的freq()
和duty()
方法以获取其当前值。
引脚将继续保持在PWM模式,直至您使用以下指令取消此模式:
>>> led_pwm.deinit()
注意: pwm使用完了之后,需要销毁,注意deinit
使用PWM来控制LED的亮度¶
相信聪明的你已经从以上的API讲解中明白,只要我们更改了控制LED的引脚上的PWM输出的占空比,即可完成对亮度的控制。
让我们编写一个叫做Switch
的类,传入一个Pin
对象,和PWM输出的占空比。
from machine import PWM from machine import Pin class Switch(): """ 创建一个开关类 """ def __init__(self, pin, freq=1000): """ 初始化绑定一个引脚,设置默认的PWM频率为1000 """ self.pwm = PWM(pin,freq=freq) def change_duty(self, duty): """ 改变占空比 """ if 0 <= duty and duty <= 1023: self.pwm.duty(duty) else: print('警告:占空比只能为 [0-1023] ') def deinit(self): """ 销毁 """ self.pwm.deinit()
我们创建一个switch.py
将以上的代码放入其中:
现在你可以通过创建一个Switch对象来控制某个管脚的输出了。
>>> switch = Switch(Pin(2)) #创建一个switch对象,控制我们的板载led >>> switch.change_duty(0) #不亮 >>> switch.change_duty(100) #很微弱 >>> switch.change_duty(500) #接近一半的亮度 >>> switch.change_duty(1000) #几乎全亮 # 释放pwm资源 >>> switch.deinit()
测试完毕,记得释放资源,因为PWM资源的限制,当你不再使用的时候, 需要释放PWM资源,执行deinit()
函数释放资源。 注意,在MicroPython里面,自定义的__del__
函数,并不会执行。所以我们需要自己定义一个函数deinit
,用来释放对象的资源, 这也是MicroPython的规范, 经常释放资源是一个好习惯。
PWM呼吸灯¶
上面的例程,效果并不是很容易展示,所以笔者打算以PWM输出来模拟一个呼吸灯的效果,并展示给大家看。
import machine import utime, math from switch import Switch from machine import Pin switch_led = Switch(Pin(2)) def pulse(switch, period, gears): # 呼吸灯核心代码 # 借用sin正弦函数,将PWM范围控制在 23 - 1023范围内 # switch 开关对象 # period 呼吸一次的周期 单位/毫秒 # gears 呼吸过程中经历的亮度档位数 for i in range(2 * gears): switch.change_duty(int(math.sin(i / gears * math.pi) * 500) + 523) # 延时 utime.sleep_ms(int(period / (2 * gears))) # 呼吸十次 for i in range(10): pulse(switch_led, 2000, 100) # 释放资源 switch_led.deinit()
效果图如下