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 시간이 듭니다. 드물게 변하는 입력 – 분당 한 번 누르는 버튼, 알람 신호 등 – 에 대해서는 irq() 가 핀이 변할 때 실행되는 핸들러를 등록합니다.

핸들러는 인터럽트 컨텍스트 에서 실행되며, 이는 핸들러가 할 수 있는 일을 제약합니다:

  • 메모리 할당 금지. 새 객체 – 리스트, 문자열, 예외, 포맷된 문자열 – 를 만드는 것은 힙이 잠겨 있기 때문에 ISR 내부에서 실패할 수 있습니다. 핸들러가 필요로 하는 버퍼는 모듈 범위에서 미리 할당하세요.

  • 장시간 실행되는 작업 금지. 핸들러는 작업을 넘기고 반환해야 합니다. 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 인자는 어느 에지가 발화할지 선택합니다: