Top.Mail.Ru

Raspberry Pi. Работа с портами ввода-вывода GPIO.

В сегодняшней статье мы рассмотрим основные нюансы и механизмы управления портами ввода-вывода GPIO платы Raspberri Pi. И, конечно же, как обычно, все проверим на практическом примере.

Все версии Raspberry Pi оснащены штыревым разъемом, на который выведены порты GPIO. Начиная с 2014-го года разъем стал 40-пиновым (ранее было 26). На версиях Pi Zero и Pi Zero W присутствует посадочное место для разъема, но физически он не распаян:

Плата Pi Zero

В любом случае, как и с любой другой платой, расположение сигналов на этом разъеме для конкретной модификации лучше всего проверить по официальному даташиту. Хотя на разных версиях плат 40-пиновые разъемы для совместимости идентичны. Распиновка и сам разъем выглядят следующим образом:

Raspberry Pi GPIO

Порты можно разделить на несколько категорий:

Распределение GPIO по типу

Разберем по очереди... Пины 3.3V и 5V могут использоваться для питания внешних устройств, подключенных к плате. При этом ограничение по току выглядит так:

  • Максимальный ток для вывода 5V определяется по формуле:
I_{5V} = I_{вх} \medspace - \medspace I_{п}

где I_{вх} - это входной ток источника, который мы используем для питания платы. А I_{п} - это ток, потребляемый самой платой, а также внешними устройствами, подключенными по USB. То есть мы подаем входной ток, часть его потребляют узлы платы, а то, что остается мы можем использовать для дополнительных устройств, подключенных к пину 5V.

  • Для выводов 3.3V все проще - максимальный ток составляет 50 мА и на этом точка.

В итоге за вычетом выводов 3.3V, 5V и Ground остаются 28 пинов GPIO, помеченных на схеме зеленым. GPIO0 и GPIO1 можно считать зарезервированными (их назначение обязательно обсудим в отдельной статье). Таким образом, остается 26 выводов, которые можно использовать по-своему усмотрению. Каждый из них может быть сконфигурирован на работу в том или ином режиме. Вот, к примеру, возможные функции портов для платы Raspberry Pi 4:

Альтернативные функции GPIO Raspberry Pi

То есть любой из портов ввода-вывода может выполнять до 6-ти различных функций, в зависимости от конфигурации. В частности, GPIO2 может быть использован как сигнал SDA для I2C1 (SDA1), либо, к примеру, как сигнал MOSI для интерфейса SPI3 (SPI3_MOSI).

Об I2C и SPI поговорим в ближайших статьях, а сегодня нас интересует использование GPIO в качестве "обычных" входов и выходов. В режиме выхода на пин может быть выведен высокий (3.3 В) или низкий (0 В) уровень напряжения. А, соответственно, в режиме входа мы можем проанализировать, какой уровень подан на пин - высокий или низкий - 3.3 В или 0 В. Тут важно обратить внимание, что порты не являются толерантными к 5 В, то есть подавать на вход 5 В категорически нельзя.

В режиме входа для любого из GPIO можно активировать внутреннюю подтяжку к питанию или земле (pull-up/pull-down). Если вывод настроен на использование подтяжки вверх, то это означает, что при отсутствии сигнала со входа будет считываться высокий уровень. С pull-down ситуация обратная - на входе в данном случае будет низкий уровень.

Исключением являются пины GPIO2 и GPIO3. Они имеют фиксированную подтяжку вверх, без вариантов.

В режиме выхода мы снова возвращаемся к ключевому параметру, а именно к ограничению по току. Максимальный ток для одного вывода составляет 16 мА. При этом, если используются несколько выходов, то суммарный ток не должен превышать 50 мА. Превышение допустимых значений с большой вероятностью приведет к выгоранию порта.

Собственно, давайте рассмотрим практический пример. Задействуем два вывода GPIO - один в качестве входа, второй в качестве выхода. На вход подключим кнопку, а на выход - светодиод. И реализуем программу, которая будет опрашивать сигнал на входе и по нажатию кнопки зажигать светодиод.

Выберем GPIO3 для светодиода и GPIO4 для кнопки. Схема подключения будет такой:

Схема подключения кнопки и светодиода

Давайте в двух словах разберем, что, как и зачем подключено. Начнем с кнопки. Программно активируем для GPIO4 подтяжку вверх, поэтому если кнопка не нажата мы получим на входе высокий уровень (логическую единицу). Соответственно, для того, чтобы определить нажатие кнопки, подключим ее к земле. В итоге при нажатой кнопке на входе будет низкий уровень (логический ноль). Поскольку используем внутреннюю подтяжку, в этом примере ставить дополнительный внешний резистор подтяжки не будем.

Резистор R_{1} - токоограничительный. Как вытекает из названия он нужен для ограничения тока ) Рассмотрим, что произойдет, если вывод GPIO4 будет ошибочно настроен не как вход, а как выход и на нем будет 3.3 В. При нажатии кнопки произойдет короткое замыкание 3.3 В на землю, что приведет к безвозвратному повреждению порта платы. Это в случае отсутствия резистора.

А при наличии резистора ток будет ограничен величиной:

I = \frac{3.3 \medspace В}{1000 \medspace Ом} = 3.3 \medspace мА

В данном случае получаем 3.3 мА, что вполне допустимо, и позволит сохранить порту жизнь в случае возникновения замыкания.

Итак, переходим к диоду, который подключен через резистор R_{2}. Каждому диоду соответствует своя собственная вольт-амперная характеристика (ВАХ), определяющая возможные значения прямого напряжения и тока. Рассмотрим первый попавшийся под руку светодиод, например такой - ссылка:

Светодиод

Открываем даташит на него и находим зависимость тока от напряжения при прямом включении:

Вольт-амперная характеристика

Максимальный ток для GPIO в режиме выхода, как мы уже выяснили, составляет 16 мА. Чтобы не превысить это значение подадим на светодиод, например, 10 мА. Этому току, исходя из графика, соответствует напряжение 2 В. Теперь по закону Ома нам остается только определить величину резистора. На выходе GPIO у нас 3.3 В, на диоде должно падать 2 В, значит на резисторе остается:

U_{рез} = 3.3 \medspace В \medspace - \medspace 2 \medspace В = 1.3 \medspace В

При этом ток в цепи должен быть равен 10 мА, тогда сопротивление резистора:

R_{2} = \frac{1.3 \medspace В}{10 \medspace мА} = 130 \medspace Ом

Если точной величины под рукой нет, можно взять резистор номиналом чуть больше. В общем, суть тут одна - обеспечить режим работы, при котором ток через выход не превышает допустимые 16 мА. Для большинства светодиодов в документации просто приводятся конкретные типовые значения напряжения и тока, например 2.5 В и 15 мА. Расчет будет выглядеть точно так же, как и рассмотренный, просто значения другие.

В общем, с подключением разобрались, время переходить к программной реализации. Существует огромное многообразие возможных способов для управления GPIO, мы же сегодня остановимся на использовании python.

И для работы с портами ввода-вывода используем библиотеку/модуль RPi.GPIO. В Raspberry Pi OS он включен по умолчанию, но в случае отсутствия команда для установки такая:

sudo apt-get install python-rpi.gpio

Создаем файл gpio_test.py и добавляем в него следующий код:

import RPi.GPIO as GPIO
import time

GPIO_LED = 3
GPIO_BUTTON = 4
DELAY_TIME = 0.5

GPIO.setmode(GPIO.BCM)

GPIO.setup(GPIO_LED, GPIO.OUT)
GPIO.output(GPIO_LED, GPIO.LOW)

GPIO.setup(GPIO_BUTTON, GPIO.IN, pull_up_down=GPIO.PUD_UP)

try:
    while True:
        time.sleep(DELAY_TIME)
        
        if GPIO.input(GPIO_BUTTON) == 0:
            GPIO.output(GPIO_LED, GPIO.HIGH)
            print('led on')
        else:
            GPIO.output(GPIO_LED, GPIO.LOW)
            print('led off')
except KeyboardInterrupt:
    GPIO.cleanup()
    print('exiting')

Пройдемся подробнее, прямо по всем строкам последовательно. Делаем import модулей для работы с GPIO и для использования временной задержки:

import RPi.GPIO as GPIO
import time

Добавим переменные для хранения номеров портов и величины задержки. У нас светодиод на GPIO3, а кнопка на GPIO4. Так и определим:

GPIO_LED = 3
GPIO_BUTTON = 4
DELAY_TIME = 0.5

Далее настроим режим нумерации портов, чтобы номера соответствовали названию сигнала (например, GPIO3), а не порядковому номеру на разъеме:

GPIO.setmode(GPIO.BCM)

Настраиваем GPIO3 на работу в режиме выхода и гасим светодиод, подав низкий уровень:

GPIO.setup(GPIO_LED, GPIO.OUT)
GPIO.output(GPIO_LED, GPIO.LOW)

GPIO4 - в режиме входа с подтяжкой вверх:

GPIO.setup(GPIO_BUTTON, GPIO.IN, pull_up_down=GPIO.PUD_UP)

Далее организуем вечный цикл while True, в котором и будем проверять состояние кнопки и мигать светодиодом. Только обернем его в блок try, чтобы отловить исключение, возникающее, когда пользователь завершает процесс (нажав Ctrl + C). В случае завершения выполнения программы вызываем GPIO.cleanup():

try:
    while True:
        time.sleep(DELAY_TIME)
        
        if GPIO.input(GPIO_BUTTON) == 0:
            GPIO.output(GPIO_LED, GPIO.HIGH)
            print('led on')
        else:
            GPIO.output(GPIO_LED, GPIO.LOW)
            print('led off')
except KeyboardInterrupt:
    GPIO.cleanup()
    print('exiting')

Ну и, конечно, здесь же у нас вся полезная работа. Если кнопка нажата (а в нашей схеме этому соответствует низкий уровень/логический ноль на GPIO4), то зажигаем светодиод и выводим сообщение "led on". При отпускании кнопки - обратный процесс. Проверять кнопку будем каждые 0.5 с (DELAY_TIME).

Запускаем программу командой:

python gpio_test.py

И теперь, нажимая кнопку, можем наблюдать включение и выключение светодиода, как мы и планировали 👍

Подписаться
Уведомить о
guest

0 комментариев
Межтекстовые Отзывы
Посмотреть все комментарии
0
Оставьте комментарий! Напишите, что думаете по поводу статьи.x