GPIO-пины Raspberry Pi и их использование из Python
14 декабря 2016
В уже довольно не новом посте, посвященном Raspberry Pi, это устройство рассматривалось исключительно, как маленький и очень дешевый компьютер. Бесспорно, Raspberry Pi им и является. Но, помимо этого, у Raspberry Pi есть еще и 26 пинов GPIO (General Purpose Input Output), что очень кстати в свете моего недавнего увлечения электроникой. Почему? Давайте разберемся.
Отмечу, что все написанное ниже справедливо для Raspberry Pi 2 Model B. Если у вас другая малина, то расположение пинов и другие детали могут отличаться. Поэтому обязательно сверьтесь с официальной документацией. В качестве операционной системы я использовал релиз Raspbian от 2016-09-28, который можно скачать здесь. Более поздние релизы мне не нравятся, потому что из соображений безопасности в них решили по умолчанию отключать SSH. Что довольно смешно, потому что в этот же релиз решили включать Adobe Flash.
Итак, расположение пинов описано на официальном сайте:
На этой картинке явно изображен один из углов устройства (слева вверху), поэтому по ошибке пронумеровать пины вверх ногами довольно сложно. Очень интересно, что курили ребята, решившие так нумеровать пины. Если кто-нибудь знает ответ, расскажите, пожалуйста, в комментариях. Чтобы окончательно всех запутать, они решили сделать две нумерации. Выше представлена «логическая» нумерация. Под этими номерами пины видны операционной системе. Есть еще и «физическая» нумерация, про которую можно прочитать по приведенной выше ссылке. В рамках данной заметки используется исключительно «логическая» нумерация, изображенная на картинке.
Допустим, мы хотим программно управлять напряжением, подаваемым на 2-й пин. Проще всего это сделать через sysfs.
Первым делом «экспортируем» пин, без этого шага им не получится управлять:
Делаем его out-пином, то есть, он будет либо подавать, либо не подавать напряжение в 3.3 вольта:
Подаем напряжение:
Перестаем подавать напряжение:
Узнаем, подается ли сейчас напряжение:
По завершении работы пину можно сделать unexport:
Есть мнение, и не только мое, что 3.3 вольта — как-то маловато. Кроме того, было бы неплохо не только включать и выключать напряжение, но и изменять его в некотором диапазоне. Увы, насколько мне известно, ничего этого Raspberry Pi не умеет. Поговаривают, что умеет Arduino, но опыта использования этого устройства на момент написания этих строк у меня нет.
Можете подключить пин к цепи из светодиода и резистора с сопротивлением 470 Ом и проверить, что описанным выше образом светодиод можно включать и выключать. Для земли (то есть, минуса) можно использовать любой пин, изображенный на приведенной выше схеме черным цветом. Понятно, что работу с sysfs можно автоматизировать на любом языке программирования по вкусу. Можно подключить сразу три светодиода разного цвета и получить программно управляемый светофор. Собственно, это я и сделал, воспользовавшись пинами 3 и 4.
Важно! После загрузки Raspberry Pi некоторые пины по дэфолту могут подавать напряжение. Возможно, это не то, чего вы хотите для вашей цепи. У меня по дэфолту ток был на пинах 2, 3 и 14. Я бы советовал перепроверить эту информацию на вашей конкретной Raspberry Pi и конкретной версии Raspbian. Имейте также в виду, что написанная вами же программа может оставить пины в неизвестном состоянии (например, если вы прибьете ее kill’ом). Наверное, в общем случае лучше всего проектировать цепь так, чтобы она была готова к любым комбинациям наличия или отсутствия тока на используемых вами пинах.
До сих пор были рассмотрены out-пины. Они как бы «пишут» на макетную плату, но не позволяют узнать ее текущее состояние. Например, нажата ли в настоящих момент какая-то кнопка. Даже если цепь разомкнута, out-пины об этом не знают. Поэтому есть еще и in-пины.
Экспортируем 5-ый пин и делаем его in-пином:
echo in > /sys/class/gpio/gpio5/direction
Этот пин я подключил к цепи из резистора сопротивлением 10 кОм и кнопки, которая в нажатом состоянии замыкает цепь, а в отпущенном размыкает.
«Прочитать» кнопку можно так:
Считывается 1, если кнопка не нажата, то есть, цепь разомкнута, и 0, если кнопка нажата, то есть, цепь замкнута.
В итоге получилась такая конструкция (иллюстрация про кнопку взята отсюда):
А вот и скрипт на Python, который при нажатии на кнопку тушит текущий светодиод и зажигает следующий за ним:
import RPi.GPIO as GPIO
import time
# Use "logical" pin numbers
GPIO.setmode(GPIO.BCM)
# Disable "This channel is already in use" warnings
GPIO.setwarnings(False)
# Setup LED's: 2 - green, 3 - yellow, 4 - red
for i in range(2,5):
GPIO.setup(i, GPIO.OUT)
GPIO.output(i, False)
current_led = 2
GPIO.output(current_led, True)
# Prepare to read button state
BUTTON = 5
PRESSED_CODE = 0
GPIO.setup(BUTTON, GPIO.IN, pull_up_down=GPIO.PUD_UP)
while True:
# GPIO.wait_for_edge(BUTTON, GPIO.FALLING)
# print("Button pressed")
# GPIO.wait_for_edge(BUTTON, GPIO.RISING)
# print("Button released")
time.sleep(0.05)
if GPIO.input(BUTTON) == PRESSED_CODE:
GPIO.output(current_led, False)
current_led = max(2, (current_led + 1) % 5)
GPIO.output(current_led, True)
time.sleep(0.1)
Опытным путем удалось подобрать временные задержки, при которых светодиоды переключаются в точности так, как ожидает пользователь. Закомментированный в приведенном коде метод wait_for_edge на практике работает совершенно непредсказуемо. Например, если зажать кнопку на несколько секунд, то последующие нажатия будут приводить к зажиганию светодиодов в каком-то почти случайном порядке.
Насколько мне известно, это по большому счету все, что можно сделать с помощью GPIO на Raspberry Pi. Поправьте, если я не прав.
Дополнение: В комментариях подсказывают, что малина также умеет и ШИМ. Еще один пример использования GPIO в одноплатном компьютере описывает заметка Реверс-инжиниринг роутера на примере GL.iNet GL-AR750.
Метки: Linux, Python, Электроника.