<button id="ssm6u"><optgroup id="ssm6u"></optgroup></button>
  • 跳轉至

    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

    例如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()
    

    效果圖如下

    參考文獻

    經典科普:為什么電影24幀就行,但游戲要60幀?

    人類顯示器的黑歷史

    定義PWM-upycraft文檔


    韩国精品无码一区二区三区,精品无码一区二区三区AV,欧洲丰满美熟女乱又伦AV,亚洲午夜久久久影院伊人