3.10. GPIO 輸入

從 GPIO 接腳讀取開關(或任何數位訊號)同樣會經由 machine.Pin,這次設定為輸入。其介面與輸出對稱:設定模式,然後可在主迴圈中輪詢接腳的值,或註冊一個在值變化時觸發的中斷處理常式。

3.10.1. 設定輸入

Pin.IN 傳給建構式,並可選擇性地傳入上下拉電阻:

from machine import Pin

button = Pin("P0", Pin.IN, Pin.PULL_UP)

這會將 P0 設定為輸入,並啟用 MCU 的內部上拉電阻。在接腳上沒有接任何東西時,上拉會將其維持在高電位;將開關從接腳接到接地閉合則會將其拉低。

3.10.2. 讀取值

value() 不帶引數時會回傳目前的狀態──``0`` 代表低電位,1 代表高電位:

if button.value() == 0:
    print("button pressed")
else:
    print("button released")

在主迴圈的模式中,輪詢看起來像這樣:

while True:
    if button.value() == 0:
        do_action()
    time.sleep_ms(50)

這 50 ms 的睡眠避免迴圈以滿載 CPU 運行。

3.10.3. 中斷驅動的輸入

Polling works, but every iteration of the main loop costs CPU time. For inputs that change rarely -- a button press once a minute, an alarm signal -- irq() registers a handler that runs only when the pin changes.

該處理常式在中斷環境中執行,這限制了它能做的事:

  • 不可配置記憶體。建立新物件──串列、字串、例外、格式化字串──在 ISR 內可能會失敗,因為堆積(heap)被鎖定。請在模組層級預先配置處理常式所需的任何緩衝區。

  • 不可進行長時間運行的工作。處理常式應該交派出去並回傳。在 ISR 內耗費實際時間會延誤其他所有事情(其他中斷、主迴圈、USB 流量)。

  • 不可在緊湊的 ISR 中列印。print() 會配置記憶體、在 UART 上阻塞,是處理常式所能做的最昂貴的事情之一。

標準的模式是讓 ISR 透過 micropython.schedule() 排程真正的工作,它會將一個函式排入佇列,在下一個安全的時間點回到主要環境執行:

import micropython

def handle_press(pin):
    print("button pressed")

def on_press(pin):
    micropython.schedule(handle_press, pin)

button.irq(handler=on_press, trigger=Pin.IRQ_FALLING)

ISR 只有一行:將回呼函式排入佇列並回傳。handle_press 接著在正常環境中執行,在那裡進行記憶體配置、print() 與緩慢的 I/O 又都是安全的了。

trigger 引數選擇由哪個邊緣觸發: