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, который можно скачать здесь.
Итак, расположение пинов описано на официальном сайте:
На этой картинке явно изображен один из углов устройства (слева вверху), поэтому по ошибке пронумеровать пины вверх ногами довольно сложно. Очень интересно, что курили ребята, решившие так нумеровать пины.
Допустим, мы хотим программно управлять напряжением, подаваемым на 2-й пин. Проще всего это сделать через sysfs.
Первым делом «экспортируем» пин, без этого шага им не получится управлять:
Делаем его out-пином, то есть, он будет либо подавать, либо не подавать напряжение в 3.3 вольта:
Подаем напряжение:
Перестаем подавать напряжение:
Узнаем, подается ли сейчас напряжение:
По завершении работы пину можно сделать unexport:
Есть мнение, что 3.3 вольта — это как-то маловато. Кроме того, было бы неплохо не только включать и выключать напряжение, но и изменять его в некотором диапазоне. Увы, насколько мне известно, ничего этого Raspberry Pi не умеет. Поговаривают, что умеет Arduino, но опыта использования этого устройства на момент написания этих строк у меня нет.
Можете подключить пин к цепи из светодиода и резистора с сопротивлением 470 Ом и проверить, что описанным выше образом светодиод можно включать и выключать. Для земли (то есть, минуса) можно использовать любой пин, изображенный на приведенной выше схеме черным цветом. Понятно, что работу с sysfs можно автоматизировать на любом языке программирования по вкусу.
Важно! После загрузки 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: таймеры и GPIO.
Метки: Linux, Python, Электроника.
Вы можете прислать свой комментарий мне на почту, или воспользоваться комментариями в Telegram-группе.