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. 割り込み駆動の入力

ポーリングは機能しますが、メインループの反復ごとにCPU時間を消費します。めったに変化しない入力、たとえば1分に1回のボタン押下やアラーム信号などに対しては、irq() が、ピンが変化したときにのみ実行されるハンドラを登録します。

ハンドラは割り込みコンテキストで実行されるため、実行できることに制約があります。

  • メモリ割り当て禁止。 リスト、文字列、例外、フォーマット済み文字列などの新しいオブジェクトの生成は、ヒープがロックされているためISR内で失敗する可能性があります。ハンドラが必要とするバッファは、モジュールスコープで事前に割り当てておきます。

  • 長時間実行の処理禁止。 ハンドラは処理を引き渡してすぐに戻るべきです。ISR内で実時間を費やすと、他のすべて(他の割り込み、メインループ、USBトラフィック)が遅延します。

  • タイトなISR内での出力禁止。 print() はメモリを割り当て、UARTでブロックし、ハンドラが行いうる最もコストの高い処理の1つです。

標準的なパターンは、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は1行で済みます。すなわち、コールバックをキューに入れて戻るだけです。その後 handle_press が通常コンテキストで実行され、そこではメモリ割り当て、print()、低速なI/Oがすべて再び安全になります。

trigger 引数は、どのエッジで発火するかを選択します。