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 мс не даёт циклу выполняться на полной загрузке 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() и медленный ввод-вывод снова безопасны.

Аргумент trigger выбирает, какой фронт вызывает срабатывание: