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()
效果圖如下