Электроника для всех
Блог о электронике
ARM. Учебный Курс. Порты GPIO
Над портами инженеры STM поубивались знатно. Такой прорвы настроек и возможных режимо я, честно говоря, даже не ожидал. Порты у STM32F1xx могут работать в режиме* :
С железной части порты бывают двух видов стандартные и устойчивые к напряжению в 5 вольт. При том, что напряжение питания у STM32 максимум 3.3 вольта. Разница у портов в схемотехнике. А точнее в том, что у 5V tolerant входов защитные диоды видут на какую то особую шину питания Vdd_ft. Полагаю, что там стоит нечто вроде небольшого повышателя, накачивающего напругу до 5 вольт.

Стандартный вывод

Вывод 5V Tolerant
Остальное все более менее стандартно. Сигнал на выход может вывалиться либо с периферии (стрелочка Alternate function Output) либо с выходного регистра. В который мы вольны записывать биты напрямую, либо же воспользоваться служебными регистрами установки/снятия битов.
Входной сигнал с ноги попадает в Data register и в Alternate Function Input. Причем селектора там нет, а значит можно по ходу дела считывать и глядеть что там творит периферия.
Т.к. RM0008 это общий документ, сразу на все семейство STM32F10x то распиновку выводов конткретного чипа в конкретном корпусе надо смотреть в конкретном даташите. Для STM32F103C8T6, что стоит на Pinboard II она выглядит следующим образом * : 
Но этого недостаточно, тут только названия GPIO. А есть же еще альтернативные функции, т.е. периферия. Там же, в даташите, вы найдете такую большую и страшную таблицу, показывающую привязку выводов к периферии, а также разные свойства выводов.
Вот примерный кусок того, что вы должны найти* : 
Разберем ее чуть подробней.
Также настояяятельно рекомендую читать сноски и пояснения к этой таблице. Там много всяких уточнений.
Итак, портом управляют следующие регистры
Пара GPIOx_CRH:GPIOx_CRL
Т.к. порты в STM32 шестнадцати разрядные, а на конфигурацию одной ноги выделено аж четыре бита, то на 16 выводов надо 64 бита. Т.е. два регистра. В CRL хранятся конфиги выводов от 0 до 7, а в CRH с 8 до 15го.
Выглядит внутри так:

Красными блоками я выделил группы битов, отвечающих за одну ножку. Тут конфигурируются выводы от 0 до 7. Это CRL. В CRH то же самое, но настраиваются пины от 8го до 15го.
Все возможные состояния описываются в таблице 18 и 19 из User Manual
Тут стоит обратить внимание на скоростной режим порта. Т.е. с какой частотой он может дрыгать лапой. Полагаю сия настройка должна влиять на энергопотребление. Т.е. если жалко батарейку и не планируем дрыгать быстро, то имеет смысл поставить минимальную частоту.
Какой режим выставить зависит от того, что мы хотим получить. Если для ручного дрыганья портами все просто и ясно, то для периферии возможны затупы. Т.к. тут надо вручную выставлять нужные режимы портов для периферии. А кому какой? Ответ на это дает пачка таблиц с 20 по 31 из User Manual * Там таблицы такого вида:
Где сказано для какого режима периферии какой режим порта надо поставить. Так что курите документацию. Это вам не AVR, тут ее просто горы 🙂
Искать там просто — находишь нужную периферию в таблице в разделе 8.3 и смотришь куда ее можно перекинуть. Затем идешь в раздел 8.4.2 и смотришь какие биты для этого нужно записать в регистр AFIO_MAPR.
Структура регистра ODR проста — первые биты от 0 до 15 отвечают за соответствующий вывод, а старшие, от 16 и до 31го не используются вообще.
Все же, что на ноге появилось, вылезает во входном регистре GPIOx_IDR. Это аналог регистра PINx в AVR. Т.е. в каком логическом уровне находится вывод МК, такое значение в этом регистре. Даташит говорит, что данные считываются на каждом такте шины APB2.
Структура регистра GPIO_IDR похожая на ODR. Т.е. первые 16 бит отвечают за соответствующие выводы, а старшие не используются.
Также там есть регистры атомарных действий. Позволяющие менять значения битов в ODR без использования операций чтение-модификация-запись.
С BRR все просто. Его младшие 16 бит отвечают за сброс бита в ODR.
Т.е. надо тебе, например, сбросить бит 3 в ODR, не трогая остальные. Без BRR регистра, надо было бы сначала считать ODR, потом по маске загасить нужный бит, не трогая остальные, а потом вернуть его обратно в ODR в уже измененном виде. Как минимум тут будет три команды. Между которыми может вломиться прерывание и обгадить нам всю малину. C регистром сброса все упрощается до одной команды. Нам нужно только лишь записать «адын» в третий бит GPIOx_BRR и усе, бит 3 в ODR будет сброшен. На нули же никакой реакции не будет. Таким образом можно сбрасывать и несколько битов.
Регистр BSRR работает аналогично, только на установку. Т.е. записал ты единичку в третий разряд BSSR и она автоматом выставилась в ODR.
Разница лишь в том, что в BRR старшие биты (т.е. 16 до 31) не влияют ни на что, а в BSSR они активны и сбрасывают бит. Записал в бит 0 BSRR единичку — бит 0 в ODR выставился. Записал в бит 16 BSRR единичку — бит 0 в ODR сбросился. Потому то он и зовется Bit Set/Reset Register.
Каждый бит регистра LCKR отвечает за один бит порта. А 16й бит регистра LCKR (LCKK) служит ключиком. Для того, чтобы заблочить порт нужно:
Выставить в регистре GPIO_LCKR биты выводов которые мы хотим заблокировать.
В процессе записи ключевой последовательности нельзя модфицировать биты регистра LCKR кроме 16го, ключевого. Иначе замок не сработает.
Порты GPIO сидят на шине APB2 и тактируются оттуда. По умолчанию тактирование ВЫКЛЮЧЕНО! сделано это скорей ради экономии энергии. Нет тактов — нет потребления. Вообще вся периферия изначально отключена от тактирования. Поэтому то часто возникают непонятки — порты все настроил, а нифига не работает.

Как видишь, тут каждой периферийной шняге, что висит на шине APB2 присвоен битик. Каждому из портов (от А до G) тоже. Также отдельный бит присвоен альтернативному использованию портов. Бит AFIO. Вот выставляешь эти битики и поехало.
Подведем итог. Что нам надо сделать, чтобы помигать таки этим чертовым диодиком?
Просто как раз-два-три! И чего я тут распинаюсь 😉
CMSIS
Теперь поглядим на представление наших портов через призму CMSIS и попробуем написать кусочек кода для мигания. Мигать будем битом на B05.
// Выставляем тактирование в APB2 RCC->APB2ENR |= RCC_APB2ENR_IOPBEN; // Конфигурируем CRL регистры. GPIOB->CRL &=
Сброс и запись мы делаем через один и тот же регистр BSRR. А записываем в него разное число.
GPIO_BSRR_BR5 = 0x00200000
GPIO_BSRR_BS5 = 0x00000020
Разница лишь в половине в которую идет запись бита. Также можно и напрямую пинать данные в ODR.
Набросал простенький примерчик в Keil и запустил на Pinboard II
Видео уж прикладывать не буду. Что вы, в самом деле, мигающий диод не видели? 😉 Уж, надеюсь, поверите мне на слово 🙂
to do… тут надо дописать ту же самую портянку, но про LPC1343… когда нибудь.
Спасибо. Вы потрясающие! Всего за месяц мы собрали нужную сумму в 500000 на хоккейную коробку для детского дома Аистенок. Из которых 125000+ было от вас, читателей EasyElectronics. Были даже переводы на 25000+ и просто поток платежей на 251 рубль. Это невероятно круто. Сейчас идет заключение договора и подготовка к строительству!
А я встрял на три года, как минимум, ежемесячной пахоты над статьями :)))))))))))) Спасибо вам за такой мощный пинок.
108 thoughts on “ARM. Учебный Курс. Порты GPIO”
Ох, такую статью бы, да две недели назад.. Было бы здорово 🙂
Сейчас я почти со всем уже разобрался сам, уткнувшись в даташиты.
А в режиме «открытый коллектор» можно рулить напряжением большим чем 5вольт
Лучше не стоит. Защитные диоды никуда не денутся, а по ним лишняя напруга уйдет в шину питания со всеми нехорошими последствиями.
а нафига тогда этот режим. чем он отличается от обычного нуля на выходе. тот же открытый нижний транзистор, и закрытый верхний.
или может защитные диоды все же как то отрубаются от пина, и там настоящий ОК выходит )))
Тем что когда в ODR=1 выход в Hi-Z. Тут верхний всегда закрыт.
DI напиши статью о работе с I2C и SPI на этих контроллерах.
Напишу… в этом или следующем году 🙂
А что за режим push-pull? не совсем понятно
Два транзистора. Верхний и нижний. Между ними вывод. Верхний ведет на шину питания, нижний на землю. Открываем верхний — вывод жестко прижимается к питанию. Открываем нижний — к земле.
А, все понял) спасибки DI)
Нормально push-pull называется двухтактным выходом, что в цифровой, что в аналоговой (усилители) технике. А тяни-толкай это, как пошутил аффтар, из доктора Айболита
ооо… давно не было статьей.
А для чего блокировка нужна? Кроме теоретического сферического STM32 в вакууме?
То есть в случае необходимости блокируем пин, а если нужно его поменять программно перезагружаем контроллер?
Спасибо, очень познавательная статья!
А как насчет bit-band?
Есть там такая фраза в даташите как «These bits can be read and written by software and can be accessed in Word mode only.», под описанием регистра ODR. Однако гугление показало что народ вроде как делал и оно работало. Еще пытался найти набор удобных дефайнов для всех пинов(вида PORTA8, например), но не нашел, впрочем тут можно заморочится и самому сенерить, посмотрев по каким адресам там чего лежит.
Кстати, получается атомарно инвертировать бит нельзя? Жалко, например у xmega если память не изменяет есть такая функция(спец регистр типа BSRR). Интересен самый простоый и/или быстрый способ инвертировать бит в регистре.
Есть. У STM32 с этим все в порядке. ЕМНИП инверснуть можно через битбанд, там вроде как регистр на set, clear и invert, но надо уточнить.
Битбанда нет в LPC младших версий.
У LPC1343 есть битовый доступ через MASKED_ACCESS. Причем это не отдельная команда, область в адресном пространстве (массив по сути). Более того доступ ко всему порту идет через эту же область (где маска == все выводы).
Написано как всегда легко и понятно. Только вот ее бы год или месяцев 9 назад, что бы не тупить в талмуды даташитов…
DI, а можешь поделиться планами, что по армам планируешь рассматривать?
Ну еще хорошо бы добавить что на Remap тоже такты давать надо.
Что имеется в виду в вопросе про Bit-Band? если руление битами через область памяти в которой каждый байт соответствует своему биту — то да, оно работает, во всяком случае на STM32. Разве что несколько геморно высчитывать адреса.
На ремап в смысле на тот GPIO куда сремапилось? Думаю это очевидно. Нет?
Или там еще куда то надо загнать?
Немного неправильно выразился. Там врубаются такты на регистры управления альтернативными функциями, регистр ремапа тоже относится к этой группе.
У меня для ремапа SPI1 в коде идут 2 команды:
// alternative func enable
RCC->APB2ENR |= RCC_APB2ENR_AFIOEN;
AFIO->MAPR |= AFIO_MAPR_SWJ_CFG_JTAGDISABLE; // disable JTAG
// remap SPI1 to port B
AFIO->MAPR |= AFIO_MAPR_SPI1_REMAP;
Ну и отрубание JTAGа тут докучи
Ага, т.е. вот это:
RCC->APB2ENR |= RCC_APB2ENR_AFIOEN;
Обязательно при ремапе.
А нет готовых дефайнов всех GPIO_Pin_х с высчитанными адресами?
В CMSIS этого не нашел.
Все, не надо, написал простую программку, сам сгенерил 🙂
http://tmp.avr.net.ru/bit.zip
Нате.
Там два файла, один с дефайнами для F100 (для F10x тоже скорее всего подойдет, не смотрел даташит, пока что 100RBT6 ковыряю). Вид дефайнов
PORTx_y (пример PORTA_12) и PINx_y (пример PINA_12). Это соответственно биты регистра ODR и IDR.
Второй файлик — программа для генерации первого. Написана на коленке за 5 минут, лишь бы генерило. Изменять под свой вкус. Вообще было бы круто написать такое для всех битов всей переферии, но это придется повозиться.
Было бы интересно найти/сгенерить для всех регистров переферии(а они в стм32 как я понял ВСЕ попадают в зону битбанда). Тогда можно будет
GPIOA->CRH |= GPIO_CRH_MODE9_0 | GPIO_CRH_MODE9_1;
Заменить на
GPIOA_MODE9_0 = 1;
GPIOA_MODE9_1 = 1;
Как по мне, так вторая запись нагляднее и удобнее
Так это, у периферии есть базовый адрес, остальные смещения. Думаю можно сделать макрос которому подсовываешь базовый адрес, имя бита и опа…
Есть в СooCox IDE в
#include «stm32f10x_gpio.h»
на асме зажечь светики на STM32 value line discovery
последние (SET_BIT_IO GPIOC, GPIO_ODR, 8 и SET_BIT_IO GPIOC, GPIO_ODR, 9) как раз макрос битбанда
Интересно, почему все настойчиво думают, что на вордпрессе работают ББ коды форума и что они тут вообще есть 🙂
а кнопки «редактировать» ответ нет 🙁
а там внизу, под окном в котором печатаешь сообщение, мелким шрифтом чего-то про коды сказано. Я глянул мельком, в тексте присутствовало, я его и воткнул 😀
P.S. Во: Можно использовать следующие HTML-теги и атрибуты: \ \ \ \ \
Гадость… Она таки сожрала все тэги. И кстати почему-то сечас тэг code показало как надо, а в прошлых комментах его проигнорировало…
Язык можно выбирать разный.
Биты CNF[1:0] изначально выставлены в единицы? Просто в АРМах новичок и не совсем понятны операции &=
. По отдельности норм. В мануале ничего не нашел. Или просто не там ищу. Хотелось бы узнать что к чему. И еще вопрос? Как определяется битовая маска? В даташнике где то?
Не помню, сбрасываю для верности, чтобы битмаски сразу накладывать по OR. Обращай внимание на звездочки в конце предложений. Наведешь на них — увидишь сноску на конкретную страницу даташита или юзермануала.
Битмаски все прописаны в CMSIS читай описание библиотеки CMSIS
В курсе ARM есть статья по CMSIS там подробно расписано, что как и где искать.
Хорошо. После прочтенного (смотрю пример в статье Keil+CMSIS):
1. Выражение GPIOA->CRL &=
GPIO_CRL_CNF3;
Бит маска GPIO_CRL_CNF3 согласно хидеру 0x0000C000.
2. После операции
она становится 0хFFFF3FFF.
3. Т.к. 3 бит надо обнулить выполняем операцию 0хFFFF3FFF & 0x00000000.
Может я что то упустил?
в пункте 3 вы выполняете операцию (GPIOA->CRL & 0хFFFF3FFF)
получается битмаска умножается на ее инверсию? 0x0000C000 & 0хFFFF3FFF и получаем сброс, т.е. обнуленные биты CNF3?
Битмаска помноженная на ее инверсию Всегда даст ноль 🙂
кстати обнуляться два бита группы 3 и 4. (3= 0b0011)
Так, давайте разберемся по порядку, чтобы не было вопросов.
GPIO_CRL_CNF3;
Это эквивалентно
GPIOA->CRL = GPIOA->CRL & (
GPIO_CRL_CNF3); (написание выше используется для сокращения).
Дальше, подставляем значение битмаски
GPIOA->CRL = GPIOA->CRL & (
0x0000C000);
Теперь побитово инвертируем и получаем фактически это:
GPIOA->CRL = GPIOA->CRL & 0хFFFF3FFF;
Таким образом, что мы имеем — в регистр CRL порта А записывается он же, помноженный на 0хFFFF3FFF. Так как умножение Х на 1 дает Х, то везде где в полученном числе стоят 1 — останется то значение которое до этого было в регистре. Так как умножение Х на 0 дает 0, то везде где в полученном числе стоят 0 — получится 0.
Тоесть этим действием мы обнуляем в регистре CRL те биты, которые соответствуют 1 в изначальной маске GPIO_CRL_CNF, при этом все остальные биты остаются в таком же состоянии, в каком и были до этого.
Вот теперь понятно откуда «биты» растут!:) И с последовательностью операторов все норм теперь. Спасибо.
Вот теперь понятно откуда «биты» растут!:) Спасибо.
di halt, это конечно интересно, но хотелось бы почитать статьи для полных новичков, — например как работает кварц, подробный разбор небольших схем с транзистором, как куда идет сигнал и тп.
DI HALT, посоветуйте транзистор для электронного ключа (лучше импортный, рос. не смогу достать, никогда ничего не паял, появилась потребность сделать тросик к фотоаппарату, управляемый с платы), сигнал с вывода STM32l152 на плате STM32L-discovery. Вывод как понимаю нужно переводить в режим тяни-толкай?
Но вам лучше применить оптореле. CPC1035N, например. Будет куда проще и надежней.
спасибо за ответ, есть ли какие нибудь аналоги с корпусом не SMD?
вопрос цены, возможностей и целей, для многих задач этой платы «за глаза»
раньше в авр начинали с меги8 или 16 — так вот F100RB быстрее обоих, флеша больше (128 кб), озу больше и так далее..
более чем достаточно чтобы начать! да и продолжить тоже 🙂
Можешь, но смотри на отличия между МК. Отдельно я их оговаривать не буду.
DI HALT, добрый день. Знаю что вы работали с модулями Radiocrafts RC1240, прочитал вашу статью, но т.к. там последний коммент датируется 2010 годом, решил написать сюда, в надежде на вашу помощь)
Не подскажете, в чем может быть проблема — три модуля закупил (из одной партии, явно, даже в одной ленте были), подключаю по даташиту — никакого отклика, даже тестового меандра с 20го пина нет.
Соединял как в даташите — Vcc — 3.3В (пробовал также и с 5.0В), все пины GND, понятное дело, на землю, CTS, RTS, CONFIG — подключены к пину Vdd. On/Off пин подключен к Vcc.
Reset — висит в воздухе, пробовал также коснуться им Gnd и потом бросить в воздухе, а также — коснуться им Gnd и потом подключить к Vdd.
Антену пока не паял.
На выходе Vdd присутствуют искомые 2.7В, замеры потребляемого модулем тока соответствуют даташитовским — после включения показывает 20.5 мА, когда On/Off подключаю к земле — 0 мА, когда CTS, RTS на землю — 9 мА. Но меандра нет. И уарт молчит. Никаких реакций на
CONFIG->LOW нет.
Уже все перепробовал, даже с оф. дистрибютерами связался — те почесали голову и сказали «свяжемся позже».
Сброс бит в ODR можно выполнить посредством 2 регистров — это разряды 15-0 BRR и разряды 31-16 BSRR? Я правильно понял, у них одинаковое предназначение?
Извиняюсь за офтоп, но как в IAR посмотреть сколько памяти (flash, RAM и EEPROM) используется микроконтроллером?
Добрый вечер всем! Возник вопрос про 7 сегментный индикатор. На индикацию ничего не выводит, прошиваю — тишина (точнее «темнота») хотя JTAGом смотрю все биты в порядке. Может в коде что не так.
#include «stm32f10x.h»
#define SYSCLK_FREQ_72MHz 72000000
void Delay_ms(unsigned long takt)
<
unsigned long clk=(SYSCLK_FREQ_72MHz/1000000)*takt;
GPIOE->CRH |= GPIO_CRH_MODE8_0;
GPIOE->CRH |= GPIO_CRH_MODE9_0;
GPIOE->CRH |= GPIO_CRH_MODE10_0;
GPIOE->CRH |= GPIO_CRH_MODE11_0;
GPIOE->CRH |= GPIO_CRH_MODE12_0;
GPIOE->CRH |= GPIO_CRH_MODE13_0;
GPIOE->CRH |= GPIO_CRH_MODE14_0;
GPIOE->CRH |= GPIO_CRH_MODE15_0;
GPIOE->ODR = chisla[schet];
schet++;
if (schet == 10) schet=0;
Чтот меня смущает строчка активации порта. Ты точно на порт такты подал?
Как я понял вы про нее RCC->APB2ENR |= RCC_APB2ENR_IOPEEN ( с армами недавно работаю). Да, как положено. JTAG показывает APB2ENR 0х00000040. по даташиту сходится 6 бит в единицу.
В коде все ок, вроде бы. А взять мой пример и переписать его на твой порт?
А где его найти можно? не встречал 7 сегментник к СТМ32
ПРивет! Вопрос следующий. Как обратно ремапнуть порты в состояние дефолта? Камень stm32f107. Выводы РС10 и РС11 настроены как ТХ и RX USART3. Почитал даташит — думаю это делается с помощью регистра Event control register (AFIO_EVCR). Нужно уточнение правильно ли или нет. Спасибо!
Одной командой не получится. Т.к. порты 16ти разрядные. Но думаю можно будет накорячить через указатели и привязать разные половинки к одному значению. Порты то замаплены в память.
Никак нельзя… порты 16ти битные, следовательно, даже на асме будет 2 команды вывода значений в 2 порта по 16 бит..
Подскажите, пожалуйста, только начал тут разбираться с программированием STMок несколлько раз перечитал раздел статьи о GPIOx_LCKR (блокировкой порта) и так толком не понял зачем он нужен, я думал бит LCKK блокирует весь порт от изменений а нифига! 🙂
Вот кусок кода (STM32F103C8):
http://easyelectronics.ru/repository.php?act=view&id=99
PS:
1) хотелось бы поподробней про этот момент.
2) Почему приходится делать столько телодвижений для блокировки? Не проще ли просто записать 1 в бит LCKK?
А у тебя вообще блокировка включилась? Может ты из таймингов выбился? Бит установился в реале?
Так сделано, чтобы случайно не включилась блокировка. Например, при срыве стека. Это очень серьезная фича, потом через такой форватер прогоняется.
Зачем регистр BSRR и записывает и сбрасывает порты? Если сразу запишу в него вот это значение BSRR=0x00010001, что с выходом произойдет? И раз такой уж универсальный регистр этот BSRR, то зачем тогда еще один BRR который только сбрасывает биты? Может какие-то особенности его применения есть?
Вот уж не знаю, надо спросить у разработчиков. Он либо сбросится либо вставится. По моему там сброс более приоритетный. Но не помню, в ДШ было написано, что там приоритетней.
Никаких особенностей я не заметил. Вообще складывается ощущение, что имея такое огромное адресное пространство разработчики изголялись кто во что горазд. Мол а я и так могу и так могу и этак могу.
Доброго времени суток! Помогите разобраться с GPIO у процессора Ambarella тема тут http://3ppc.net/forum/showthread.php?p=521399#post521399
Не могу понять что за режимы SW и HW? Может подскажите?
Растолкуйте пожалуйста такую вещь:
Есть ли разница между режимами входа с подтяжкой к питанию и с подтяжкой к земле? При наличии входного сигнала результат все равно одинаков. У меня только такое объяснение: при отсутствии входного сигнала в одном случае на входе будет +Uп а в другом 0, другого смысла не вижу.
И в чем смысл выхода с открытым стоком, с физической точки зрения? Какое применение этого режима?
Именно так, разное поведение при отсутствии сигнала. А открытый сток это выход позволяющий коротить сигнал на землю и только так. Полезен при работе на шину с подтяжкой. Вроде i2c или 1-wire.
Нигде не нашел информации о нагрузочной способности портов ввода вывода. Какой ток могут выдавать обычные пины и толерантные к 5в? На PB2 если я подключу к линейке светодиодов, ничего не попалю? Там 200 Ом резисторы, т.е. ток
Работа через GPIO в Raspberry Pi 3
Одна из основных функций одноплатных компьютеров семейства Raspberry Pi — обеспечивать взаимодействие с разнообразной периферией. Это могут быть датчики, реле и двигатели, лампочки и прочие исполнительные модули и блоки. За такое «общение» отвечает встроенный в платы Raspberry Pi GPIO — интерфейс ввода-вывода. Рассмотрим его подробнее на примере RPi 3 B.
Что такое колодка GPIO
GPIO — сокращение, означающая General-Purpose Input-Output, или общий интерфейс ввода/вывода. Он содержит цифровые входы и выходы для подключения датчиков, разнообразных контроллеров, дисплеев, реле и прочей электронной периферии. Внешне GPIO похож на «гребенку» из штырьков-пинов. В Raspberry Pi 3 его внешний вид таков (в верхней части платы):
Колодка GPIO Raspberry чем-то напоминает интерфейс подключения жестких дисков IDE.
Для правильной работы через GPIO необходимо знать конфигурацию пинов. В Raspberry Pi распиновка такова:
Разъемов питания 4. Прочие пины способны выступать в роли входа или выхода. Кроме того, некоторые из них многофункциональны и могут работать как интерфейс UART, I2C, SPI или ШИМ.
Рассмотрим более подробно устройство «гребенки».
Устройство GPIO
Число пинов на колодке GPIO Raspberry Pi 3 равняется 40. Они пронумерованы и делятся на три группы:
Первые необходимы для подачи электричества разных напряжений — 3.3 и 5 В. Разница между ними была рассмотрена выше. Вторые обеспечивают безопасность работы платы, отводя электричество. А третьи выступают в качестве интерфейсов, принимая и отдавая данные. Именно к ним пользователь подключает свои модули и приборы.
Схема пинов Raspberry Pi 3 Model B:
На данной схеме pinout выводы пронумерованы по следующему принципу:
Выходы 1 и 17 обеспечивают питание 3.3 В, 2 и 4 — для 5 В. «Земля» расположена на 9, 25 и 39, и на 6, 14, 20, 30, 34. Прочие контакты — интерфейсные порты.
Особенности GPIO «малинки»
При работе необходимо учитывать несколько важных моментов:
Важно помнить: все «ножки» колодки соединены с процессором напрямую, некорректные операции и неверное подключение способно привести к полной неработоспособности платы.
Поэтому при правильном проектировании приспособлений с большим количеством используемых выводов GPIO схема должна предусматривать дополнительные меры безопасности. Желательно делать защитные развязки электронными ключами, через трансформаторы напряжений и различные буферы.
Как правило, RPi3 работает под управлением ОС семейства Linux (Raspbian или другой). Сразу после загрузки системы напряжение на пинах низкое и остается таковым до изменения запустившимся скриптом или программой. Но в промежуток от подачи электропитания до инициализации системных драйверов пины в произвольном порядке способны выдавать высокое напряжение. Это следует учитывать и изолировать по питанию входы-выходы в процессе запуска системы.
Особые порты
Внешние модули можно подсоединять к любым портам «гребенки» GPIO. Но есть два особенных, которые плата резервирует для специфических задач. На обычной схеме их номера — 27 и 28. Они предназначены для плат расширения, и желательно не использовать их без необходимости.
Нумерация
Выше рассматривались номера пинов. Но важно понимать, что заложенная в центральный процессор логическая нумерация отличается от приведенной на схеме физической. Ее особенности:
Этот принцип следует учитывать при создании кода, поскольку ПО ориентируется именно на логические номера. Их схема:
У новичков это может вызвать недоумение и путаницу. Для помощи в решении проблемы существует программная библиотека Wiring Pi с собственной альтернативной нумерацией. Так, логический GPIO2 в ней определен как WIringPI 8. Это может показаться непонятным, но после освоения библиотеки ее принцип нумерования становится привычным и удобным.
Способы взаимодействия с интерфейсом GPIO
Интерфейсная гребенка позволяет работать с собой несколькими путями:
Управление на bash
Чтение данных со входа номер 24:
echo 24 > /sys/class/gpio/export
echo in > /sys/class/gpio/gpio24/direction
cat > /sys/class/gpio/gpio24/value
Управление через Python
Питон — один из самых популярных языков разработки под Raspberry, и в нем создан богатый инструментарий. В последних дистрибутивах ОС Raspbian уже присутствует и сама среда Python, и необходимая для работы библиотека RPi.GPIO. Если же таковой нет, ее можно загрузить из репозитория:
sudo apt-get install python-rpi.gpio
Далее необходимо подгрузить этот модуль в программу:
import RPi.GPIO as GPIO
Далее следует определиться с порядком нумерации — брать ли «физический» по номерам портов на микрокомпьютере, или использовать принцип обращения по номерам процессорных каналов (BCM):
GPIO.setmode (GPIO.BOARD)
GPIO.setmode (GPIO.BCM)
Преимущество первого пути — универсальность: он будет работать с любой ревизией контроллера. BCM обращается непосредственно к каналам процессора на более низком уровне.
На следующем шаге выбирается режим работы портов input или output.
GPIO.setup(channel, GPIO.IN)
GPIO.setup(channel, GPIO.OUT)
Сразу же можно определить начальное состояние выходов RPi3:
GPIO.setup(channel, GPIO.OUT, GPIO.LOW)
GPIO.setup(channel, GPIO.OUT, GPIO.HIGH)
Команда на чтение информации со входа:
Запись значения на выход GPIO:
Пример работы
Рассмотрим пример взаимодействия RPi3 и простой схемы со светодиодом через написанную на Python программу.
Для начала понадобится «малинка» с установленным ПО и средой разработки, макетная плата, диод, кнопка и резисторы. Схема подключения приведена ниже:
Здесь R1 имеет сопротивление 10 кОм, R2 — 1 кОм, а резистор R3 — 220 кОм.
Что обеспечивает подобная модель:
Написанный на Python скрипт включения-выключения лампочки:
Import RPi.GPIO as GPIO
GPIO.setmode (GPIO.BCM)
GPIO.setup (4, GPIO.OUT)
GPIO.output (4, 1)
GPIO.cleanup ()
Для «моргания» диодом:
import RPi.GPIO as GPIO #импорт библиотеки дл¤ работы с GPIO
import time #импорт библиотеки дл¤ ожидани¤
GPIO.setmode(GPIO.BCM) #»запуск» GPIO
GPIO.setup(4, GPIO.OUT) #объ¤вл¤ем 4 порт как выход
while True: #цикл
GPIO.output(4, 1) #вкл светодиода
time.sleep(1) #пауза 1 с
GPIO.output(4, 0) #выкл светодиода
time.sleep(1) #пауза 1 с
Включение лампочки с кнопки:
import RPi.GPIO as GPIO #импорт библиотеки дл¤ работы с GPIO
GPIO.setmode(GPIO.BCM) #»запуск» GPIO
GPIO.setup(4, GPIO.OUT) #объ¤вл¤ем 4 порт как выход
GPIO.setup(3, GPIO.IN) #объ¤вл¤ем 3 порт как вход
while True: #цикл
if GPIO.input(3) == False: #если кнопка нажата
GPIO.output(4, 1) #вкл светодиода
else:
GPIO.output(4, 0) #выкл светодиода
Пример управления выходами с клавиатуры:
Готовую программу следует сохранить в удобную папку и запустить командой Питона:
sudo python путь_к_исполняемому_файлу/имя_программы.py
Python предоставляет широкое поле возможностей для программирования «Распберри» и позволяет реализовывать гораздо более сложные схемы. Кроме того, с платой можно взаимодействовать на практически любом распространенном языке — одном из семейства C, Perl, Erlang и другое. Существуют даже реализации проектов на Java и HTML5.
Заключение
GPIO — удобное и универсальное решение, позволяющий подключать к RPi 3 разнообразную периферию и программировать ее поведение на одном из привычных языков. Логика взаимодействия довольно проста, а GPIO, как и сама «малинка», хорошо документирован, что обеспечивает легкий вход в программирование с использованием этого интерфейса даже новичкам в мире IT.
Начинающим можно порекомендовать язык Python, как несложный в освоении и логичный. В нем присутствуют все необходимые библиотеки работы с GPIO, ускоряющие и упрощающие процесс разработки.







