定時器¶
概要¶
本文介紹了定時器與回調函數的概念,以及如何在MicroPython-ESP32中使用定時器,最后用定時器控制LED進行周期的閃爍。
keywords Timer callback led blink
什么是定時器?¶
定時器你可以理解為一個鬧鐘,你可以設定特定時間之后執行某件事情,也可以周期的執行某件事情,比如每隔1s鐘變換一下LED的亮燈狀態。
定時器與utime
模塊中的sleep
延時函數最大區別在于,延時函數期間,CPU就如同進入了睡眠,之后的事情只有等睡醒之后再做,這種情況我們稱之為阻塞, 睡覺阻塞了cpu去完成其他的任務,必須等待CPU睡醒;而定時器是非阻塞的,在未到達定時器定時周期結束之前,CPU可以去做別的事情,等到定時器計時完畢,便會去通知CPU,CPU再去執行回調函數 (在你設定鬧鐘之前,你決定要在鬧鐘響了之后去做的事情)。
定時器每個周期都會產生一次中斷,然后調用特定的 回調函數callback, 定時器中斷屬于內部中斷.
中斷¶
CPU的中斷分為很多種,不同的中斷擁有不同的優先級別。當多個中斷同時發生時,計算機按照優先級來以此處理
Timer-常用API¶
Timer
類被封裝在machine
模塊中。
from machine import Timer
實例化一個Timer
對象,傳入一個任意正整數作為ID。
例如:
timer = Timer(1)
然后需要 初始化定時器:
timer.init(period=1000, mode=Timer.PERIODIC , callback=callback)
-
period
定時器執行的周期,單位是ms
, 隔period ms 執行一次。 period取值范圍:0 < period <= 3435973836
-
mode
定時器的執行模式 -
Timer.PERIODIC
周期執行 -
Timer.ONE_SHOT
只執行一次,執行完了定時器就結束 -
callback
: 定時器的回調函數,傳入的一個參數是timer
如果你想在callback函數里面傳入其他參數,可以參照下方 定時器控制LED閃爍 中的 Lambda表達式 的方法。
timer.init(period=period, mode=Timer.PERIODIC, callback=lambda t:led_toggle(led_pin))
最后,定時器使用完了記得要釋放定時器資源,鍵盤中斷并不會銷毀定時器,定時器會一直產生回調函數。
timer.deinit()
定時器控制LED閃爍¶
定時器控制LED閃爍 timer_led_blink.py
from machine import Timer,Pin import utime def toggle_led(led_pin): ''' LED狀態反轉 ''' led_pin.value(not led_pin.value()) def led_blink_timed(timer, led_pin, freq=10): ''' led 按照特定的頻率進行閃爍 LED閃爍周期 = 1000ms / 頻率 狀態變換間隔(period) = LED閃爍周期/ 2 ''' # 計算狀態變換間隔時間 ms period = int(0.5 * 1000 / freq) # 初始化定時器 # 這里回調是使用了lambada表達式,因為回調函數需要傳入led_pin timer.init(period=period, mode=Timer.PERIODIC, callback=lambda t:toggle_led(led_pin)) # 聲明引腳 D2 作為LED的引腳 led_pin = Pin(2, Pin.OUT) timer = Timer(1) # 創建定時器對象 led_blink_timed(timer, led_pin, freq=20)
效果展示:
工程經驗¶
注意,不要在定時器回調函數里面創建變量,可以使用 全局變量 global,因為定時器每次都創建變量比較消耗內存。
在毫秒級周期執行的定時器回調函數里面,
千萬不要在終端里面Print
千萬不要在終端里面Print
千萬不要在終端里面Print
因為在終端Print打印會干擾Timer回調函數執行頻率。而且定時器在產生按鍵中斷CTRL+C
的時候 并不會注銷,如果定時器回調函數一直在打印,它會一直打印 占用REPL資源,影響你使用REPL。