Открытый сток stm32 максимальное питание. STM32 Порты GPIO. Работа в разных режимах

GPIO (general-purpose input/output,Интерфейс ввода/ вывода общего назначения)- Интерфейс связывающий микроконтроллер с внешними устройствами (Кнопками, светодиодами, датчиками и так далее).

Как и любой другой микроконтроллер, микроконтроллер STM 32, имеет в своем составе интерфейс ввода/вывода. Данный интерфейс позволяет управлять внешними устройствами путем передачи сигналов низкого и высокого уровня через контакты GPIO , а так же принимать данные с них, путем приема сигналов низкого или высокого уровня. Контакты GPIO , группируются в порты(GPIOA ,GPIOB ,GPIOC …). Каждый контакт может работать на прием или передачу данных.

Рассмотрим режимы работы контакта GPIO :

    Hi Z вход - В таком состоянии сопротивление входа стремится к бесконечности, и он ведет себя как отключенный от схемы.

    Вход с подтяжкой к питанию - Контакт работает на прием данных. Когда данных нет, контакт подтягивается к логической “1” (напряжению питания). Это делается, что бы избежать помех и искажения данных.

    Вход с подтяжкой к земле - Контакт работает на прием данных. Когда данных нет, контакт подтягивается к логическому “0” (земле). Это делается, что бы избежать помех и искажения данных.

    Аналоговый вход - Контакт работает в аналоговом режиме, что позволяет выводить на него сигнал ЦАП или считывать сигнал для АЦП.

    Выход с открытым коллектором .

    Двухтактный выход - Контакт работает на передачу данных. Контакт может быть установлен в логическую “1” либо в логический “ ”, соответствующим регистром.

    Альтернативный режим с подтяжкой .

    Альтернативный режим с открытым коллектором .

Альтернативные режимы пока рассматривать не будем, равно как выход с открытым коллектором и аналоговый вход. Рассмотрим подробнее режимы работы “Вход с подтяжкой к питанию/земле” и “Двухтактный выход”.

Как и любую другую периферию, перед использованием GPIO необходимо настроить. Так как периферия микроконтроллеров STM 32 очень богата и разнообразна, разработчики потрудились облегчить жизнь пользователям и избавить их от ручной правки регистров, путем создания библиотек HAL и SPL . Разумеется, никто не запрещает вам вручную править регистры. Хоть ручная правка регистров и сложна, однако позволяет лучше понять работу микроконтроллера и оптимизировать прошивку.

Но мы не будет сильно углубляться в дебри даташитов и регистров. Возьмем библиотеку SPL и с её помощью инициализируем порты ввода/вывода нашей платы STM 32 F 3 DISCOVERY .

Работать будем в среде Keil uVision 5.

Как создать свой первый проект в данной среде смотрите здесь:

Добавим следующий код:

#include "stm32f30x_gpio.h" #include "stm32f30x_rcc.h" void InitGPIO(void) { GPIO_InitTypeDef PORTE; GPIO_InitTypeDef PORTA; RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOE,ENABLE); RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOA,ENABLE); GPIO_StructInit (&PORTE); PORTE.GPIO_Mode = GPIO_Mode_OUT; PORTE.GPIO_OType = GPIO_OType_PP; PORTE.GPIO_Pin = GPIO_Pin_10; PORTE.GPIO_PuPd = GPIO_PuPd_DOWN; PORTE.GPIO_Speed = GPIO_Speed_50MHz; GPIO_StructInit (&PORTA); PORTA.GPIO_Mode = GPIO_Mode_IN; PORTA.GPIO_Pin = GPIO_Pin_0; PORTA.GPIO_PuPd = GPIO_PuPd_DOWN; PORTA.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init (GPIOE,&PORTE); GPIO_Init (GPIOA,&PORTA); }; int main(void) { InitGPIO(); while (1) { if (GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_0)==1) { GPIO_SetBits(GPIOE,GPIO_Pin_10); } else { GPIO_ResetBits(GPIOE,GPIO_Pin_10); } } }

#include "stm32f30x_gpio.h"

#include "stm32f30x_rcc.h"

void InitGPIO (void )

GPIO_InitTypeDef PORTE ;

GPIO_InitTypeDef PORTA ;

RCC_AHBPeriphClockCmd (RCC_AHBPeriph_GPIOE , ENABLE ) ;

RCC_AHBPeriphClockCmd (RCC_AHBPeriph_GPIOA , ENABLE ) ;

GPIO_StructInit (& PORTE ) ;

PORTE . GPIO_Mode = GPIO_Mode_OUT ;

PORTE . GPIO_OType = GPIO_OType_PP ;

PORTE . GPIO_Pin = GPIO_Pin_10 ;

PORTE . GPIO_PuPd = GPIO_PuPd_DOWN ;

PORTE . GPIO_Speed = GPIO_Speed_50MHz ;

GPIO_StructInit (& PORTA ) ;

PORTA . GPIO_Mode = GPIO_Mode_IN ;

PORTA . GPIO_Pin = GPIO_Pin_0 ;

PORTA . GPIO_PuPd = GPIO_PuPd_DOWN ;

PORTA . GPIO_Speed = GPIO_Speed_50MHz ;

GPIO_Init (GPIOE , & PORTE ) ;

GPIO_Init (GPIOA , & PORTA ) ;

int main (void )

InitGPIO () ;

while (1 )

if (GPIO_ReadInputDataBit (GPIOA , GPIO_Pin_0 ) == 1 )

GPIO_SetBits (GPIOE , GPIO_Pin_10 ) ;

else

GPIO_ResetBits (GPIOE , GPIO_Pin_10 ) ;

Итак, разберем подробнее, что же происходит в данном коде.

Точка входа - функция main , именно с неё начинается работа нашей прошивки. Сначала вызывается функция InitGPIO ,в которой мы настраиваем работу наших портов. Остановимся на ней подобробнее.

Вначале создаются две структуры GPIO_InitTypeDef инициализации портов GPIOE ,GPIOA , названные мною как PORTA ,PORTE . Данные структуры являются частью библиотеки SPL , и содержат в себе параметры работы соответствующих портов.

Затем, происходит включение тактирование портов GPIOA ,GPIOE командами RCC_AHBPeriphClockCmd. Следует помнить что, изначально тактирование периферии контроллера отключено, в целях снижения энергопотребления. Данной командой мы включаем или выключаем тактирование периферии шины AHB . Подробнее о тактировании поговорим в следующих уроках.

После этого мы заполняем поля структуры GPIO_InitTypeDef , для портов GPIOE ,GPIOA . Предварительно структуру можно проинициализировать (записать в неё стандартные значения) командой GPIO_StructInit. Рассмотрим поля структуры GPIO_InitTypeDef:

  • GPIO _Mode - Режим работы порта.
  • GPIO_OType - При настройке порта на выход, данным полем задается его тип (С открытым стоком или двухтактный).
  • GPIO_Pin - Данным полем мы выбираем, какие ножки порта настраивать.
  • GPIO_PuPd - Выбираем режим подтяжки к напряжению питания или к земле.
  • GPIO_Speed - Скорость работы порта.

Итак, поля заполнены, теперь инициализируем порты согласно тому, что прописано в соответствующей структуре командой GPIO_Init.

На этом функция InitGPIO заканчивается.

После вызова функции InitGPIO , наступает основной цикл программы while . В нем мы считываем входящее значение 0 ножки порта GPIOA (К которой подключена кнопка USER платы STM 32 F 3 DISCOVERY ). Делаем мы это командой GPIO_ReadInputDataBit, которая возвращает входное значение выбранной ножки порта. В соответствии с состоянием ножки 0 порта GPIOA , выставляем значение 10 ножки порта GPIOE командами GPIO_ResetBits и GPIO_S etBits. Команда GPIO _ResetBits устанавливает логический ноль на выбранной ножке порта, а команда GPIO _SetBits устанавливает логическую единицу на выбранной нами ножке.

Когда вы загрузите данную программу в плату STM 32 F 3 DISCOVERY , не забудьте нажать кнопку RESET , которая сбросит микроконтроллер. После этого нажимайте кнопку USER и смотрите за результатом.

Любое копирование, воспроизведение, цитирование материала, или его частей разрешено только с письменного согласия администрации MKPROG .RU . Незаконное копирование, цитирование, воспроизведение преследуется по закону!

Порты ввода/вывода GPIO в STM32 имеют по 16 линий, каждая из которых может быть настроена необходимым образом. Поддерживаются функции цифрового ввода, цифрового вывода, входа внешнего прерывания, а также функции ввода/вывода других модулей микроконтроллера. Программирование STM32 для работы с GPIO основано на использовании регистров конфигурации, чтения, записи, защиты конфигурации и регистра битового доступа.

Регистры конфигурации порта.

Port configuration register low (GPIOx_CRL) (x=A..G)

Port configuration register high (GPIOx_CRH) (x=A..G)

Для программирования режимов работы портов ввода/вывода STM32, используются два 32 разрядных регистра для каждого GPIO. Они позволяют произвольно настроить режим работы любой отдельной линии. Регистр GPIOx_CRL отвечает за линии с номерами от 0 до 7, GPIOx_CRH – за линии 8-15. Для каждой из них в регистре имеется два двухразрядных поля CNFy и MODEy. Первое определяет тип работы линии, второе – направление обмена по линии. все биты доступны для чтения/записи.

Регистр GPIOx_CRL

Бит регистра

Поле

Линия ввода/вывода

Бит регистра

Поле

Линия ввода/ вывода

Регистр GPIOX_CRH

Бит регистра

Поле

Линия ввода/вывода

Бит регистра

Поле

Линия ввода/вывода

Поле MODEy может принимать следующие значения:

  • 00 – линия работает на ввод. Данное состояние устанавливается после сброса.
  • 01 – линия работает на выход, с максимальной частотой переключения 10 МГц
  • 10 – линия работает на выход, с максимальной частотой переключения 20 МГц
  • 11 – линия работает на выход, с максимальной частотой переключения 50 МГц

Поле CNFy зависит от направления передачи. При работе на вход (MODEy=0) доступны следующие состояния:

  • 00 – аналоговый вход.
  • 01 – вход в третьем состоянии. (Устанавливается после сброса).
  • 10 – вход с подтягивающим резистором
  • 11 – зарезервировано для будущих применений.

При работе на выход (MODEy>0) поле CNFy может иметь следующие состояния:

  • 00 – цифровой выход
  • 01 – цифровой выход с открытым стоком
  • 10 – цифровой выход, подключенный специализированным блокам
  • 11 – цифровой выход, подключенный специализированным блокам с открытым стоком

Регистр защиты от изменения настроек

Port configuration lock register (GPIOx_LCKR) (x=A..G)

Поле

Поле

Установить блокируемый бит в GPIOx_LCKRДля невозможности изменения настроек порта в микроконтроллерах STM32 используется регистр GPIOx_LCKR. Его младщие 15 бит отвечают за соответсвующие линии порта ввода/вывода. Бит 16, установленный в 1, разрешает блокировку изменения настроек. все биты доступны на чтение/запись. Для усложнения жизни пользователям ;-) , используется специальный алгоритм установки защиты. Если он применен, то следующее изменение конфигурации доступно только после сброса. Алгоритм установки защиты выглядит следующим образом:

  1. Установить бит 16 GPIOx_LCKR.
  2. Сбросить бит 16 GPIOx_LCKR.
  3. Установить бит 16 GPIOx_LCKR.
  4. Прочитать GPIOx_LCKR
  5. Повторно прочитать GPIOx_LCKR

Регистры установки состояния линий

В отличие от привычных 8-ми битных моделей, в STM32 имеется несколько регистров, отвечающих за состояние линий порта ввода вывода. Условно они разделены на две группы – регистры порта и регистры установки отдельных битов.

Выходной регистр порта ввода/вывода

Port output data register (GPIOx_ODR) (x=A..G)

Поле

Поле

Данный регистр имеет разрядность 32, но используются только младшие 16 бит. Биты с 16 по 31 не используются. При записи в GPIOx_ODR какого-либо значения, это значение устанавливается на выходных линиях соответствующего порта. Биты регистра доступны только для чтения/записи.

Входной регистр

Port input data register (GPIOx_IDR) (x=A..G)

Бит 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16
Поле Резерв
Бит 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 1
Поле IDR15 IDR14 IDR13 IDR12 IDR11 IDR10 IDR9 IDR8 IDR7 IDR6 IDR5 IDR4 IDR3 IDR2 IDR1 IDR0

Аналогично регистру выхода, регистр входа имеет толь 16 младших действующих бит из 32. Чтение GPIOx_IDR возвращает значение состояния всех линий порта. Биты регистра доступны только для чтения.

Регистр битовых операций

Port bit set/reset register (GPIOx_BSRR) (x=A..G)

Бит 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16
Поле BR15 BR14 BR13 BR12 BR11 BR10 BR9 BR8 BR7 BR6 BR5 BR4 BR3 BR2 BR1 BR0
Бит 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 1
Поле BS15 BS14 BS13 BS12 BS11 BS10 BS9 BS8 BS7 BS6 BS5 BS4 BS3 BS2 BS1 BS0

Данный регистр позволяет обращаться к конкретной линии ввода вывода микроконтроллера STM32. Запись единицы в один из старших разрядов сбрасывает выход линии, а запись единицы в младшие разряды устанавливает высокий уровень сигнала на соответствующей линии. Запись в регистр производится в формате слова, при этом нулевые биты никакого действия не оказывают. Биты регистра доступны только для записи.

Регистр сброса

Port bit reset register (GPIOx_BRR) (x=A..G)

Бит 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16
Поле Резерв
Бит 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 1
Поле BR15 BR14 BR13 BR12 BR11 BR10 BR9 BR8 BR7 BR6 BR5 BR4 BR3 BR2 BR1 BR0

Данный регистр производит сброс высокого уровня линии, установленной в регистре GPIOx_ODR. Задействованы только младшие 16 бит, доступных только для записи.

Каждый порт STM32 состоит из 16 выводов, а каждый вывод может быть сконфигурирован одним из 8 способов.

Ниже изображена структура порта ввода-вывода.


Для того чтобы порт заработал его надо подключить к шине APB2 , установив соответствующий бит IOPxEN , в регистре разрешения тактирования периферийных блоков RCC_APB2ENR .
RCC->APB2ENR |= RCC_APB2ENR_IOPxEN; // Разрешить тактирование PORTx.
После включения все выводы находятся в состоянии плавающего входа , он же высокоимпедансный вход , он же Hi-Z , он же третье состояние .
  • Выходной драйвер выключен
  • Триггер Шмитта отключён
  • Подтягивающие резисторы отключены
  • В регистре IDR всегда “0”

В режиме входа

  • Выходной драйвер выключен
  • В зависимости от настройки, включаются резисторы подтяжки
  • Каждый такт шины APB2 данные с входа поступают в регистр IDR, считав этот регистр можно узнать состояние ножки

В режиме выхода

  • В режиме Open Drain при записи “0” открывается нижний транзистор, при записи “1” линия остаётся не подключённой
  • В режиме Push Pull при записи “1” открывается верхний транзистор, при записи “0” - нижний
  • Входной Триггер Шмитта включён
  • Резисторы подтяжки отключены

В режиме альтернативной функции

  • Драйвер включается в режиме Push Pull или Open Drain, в зависимости от конфигурации
  • Выходной драйвер управляется сигналами периферии, а не регистром ODR
  • Входной триггер Шмитта включён
  • Резисторы подтяжки отключены
  • По каждому такту шины APB2 данные c выхода передаются в регистр IDR, оттуда же их можно считать в режиме Open Drain
  • Чтение регистра ODR возвращает последнее записанное значение в режиме Push Pull

Из таблицы видно, что возможны два варианта конфигурации, в режиме альтернативной функции: Push Pull и Open Drain . Например, мы хотим, настроить в режим альтернативной функции ножку, отвечающую за приём данных по USART. Для этого в Reference Manual RM0008, начиная с 161 страницы, идут таблицы, в которых можно посмотреть как cконфигурировать вывод, для разной периферии.


Нам подойдет Input floating или Input pull-up .

Конфигурация выводов задаётся в регистрах GPIOx_CRL , GPIOx_CRH , в этих регистрах для конфигурации каждого вывода отведено 4 бита, MODE и CNF . В GPIOx_CRL конфигурируются выводы с 0 по 7, а в GPIOx_CRH с 8 по 15.



Если MODE = 00 , то вывод настроен на вход, конфигурация входа в таком случае задаётся в регистрах CNF . Если MODE не равен 00, в таком случае вывод настроен как выход, а значение MODE задаёт максимальную частоту, с которой может он переключаться.
//Полагаем что выводы после сброса в режиме плавающего входа //разрешаем тактирование порта A RCC->APB2ENR |= RCC_APB2ENR_IOPAEN; //вход с подтяжкой к + GPIOA->CRL &= ~GPIO_CRL_CNF0; GPIOA->CRL |= GPIO_CRL_CNF0_1; GPIOA->ODR |= GPIO_ODR_ODR0; //вход с подтяжкой к - GPIOA->CRL &= ~GPIO_CRL_CNF1; GPIOA->CRL |= GPIO_CRL_CNF1_1; GPIOA->ODR &= ~GPIO_ODR_ODR1; //аналоговый режим GPIOA->CRL &= ~GPIO_CRL_CNF2; //выход с открытым стоком 2MHz GPIOA->CRL &= ~GPIO_CRL_CNF3; GPIOA->CRL |= GPIO_CRL_CNF3_0; GPIOA->CRL |= GPIO_CRL_MODE3_1; //двухтактный выход 10MHz GPIOA->CRL &= ~GPIO_CRL_CNF4; GPIOA->CRL |= GPIO_CRL_MODE4_0; //альтернативная ф-ция, двухтактный выход, 50 MHz GPIOA->CRL &= ~GPIO_CRL_CNF5; GPIOA->CRL |= GPIO_CRL_CNF5_1; GPIOA->CRL |= GPIO_CRL_MODE5; //альтернативная ф-ция, выход с открытым стоком, 50 MHz GPIOA->CRL |= GPIO_CRL_CNF6; GPIOA->CRL |= GPIO_CRL_MODE6;
Считать состояние входа можно с помощью Port input data register или коротко GPIOx_IDR , где x – название порта, может быть от A до G. Считать состояние любого вывода можно из 16 младших бит, старшие 16 бит не используются.


//проверяем значение нулевого вывода порта А if (GPIOА->IDR & GPIO_IDR_IDR0)
Если порт настроен на выход, управлять его состоянием можно с помощью регистра Port output data register или GPIOx_ODR . Значение, которое мы запишем в этот регистр, появится на соответствующих выводах порта. Для установки состояния порта, выделены 16 младших бит, старшие 16 бит не используются.


//если вывод в режиме входа то активируется подтяжка к питанию GPIOA->ODR |= GPIO_ODR_ODR0; //или к земле GPIOA->ODR &= ~GPIO_ODR_ODR0; //если в режиме выхода, то на нём установится соответствующий лог.уровень //например так можно установить все выходы порта в 1 GPIOA->ODR = 0xFFFF;
В STM32 возможно атомарно управлять отдельными битами порта с помощью регистров GPIOx_BSRR (Port Bit Set/Reset Register) и GPIOx_BRR (Port Bit Reset Register).
Для установки отдельного бита порта вручную, надо считать значение порта, изменить нужный бит с помощью маски и результат вернуть обратно в GPIOx_ODR . Так как действий целых три, то возникшее между ними прерывание, может подпортить данные. С помощью описанных выше регистров, это делается в одно действие.
Для сброса бита надо в нулевой бит GPIOx_BRR записать единичку, при этом в нулевой бит GPIOx_ODR запишется 0, для этой операции выделены младшие 16 бит, старшие 16 бит не используются.


//сбросить нулевой бит порта А GPIOA->BRR = GPIO_BRR_BR0;
С GPIOx_BSRR всё чуть интереснее, младшие 16 бит отвечают за установку 1, старшие 16 бит за сброс в 0. Чтобы установить 1 в нулевой бит, надо в нулевой бит GPIOx_BSRR записать 1. Чтобы установить 0 в нулевой бит, надо в 16 бит установить 1.


//сбросить нулевой бит GPIOA->BSRR = GPIO_BSRR_BR0; //установить нулевой бит GPIOA->BSRR = GPIO_BSRR_BS0;
У STM32 есть возможность защитить конфигурацию порта от изменения, для этого выделен регистр GPIOx_LCKR . Младшие 16 бит используются для выбора вывода, который хотим заблокировать (выбор бита осуществляется установкой единицы), затем специальной последовательностью записей в 16 бит(LCKK ) осуществляется блокировка.


Последовательность следующая: записать в LCKK 1 , записать 0 ,записать 1, затем из регистра LCKR считать 0, считать 1. Последняя считанная единица говорит о том, что вывод заблокирован. Разблокировка вывода произойдёт только после перезагрузки контроллера.
#include "stm32f10x.h" uint32_t temp; int main(void) { //разрешаем тактирование порта RCC->APB2ENR |= RCC_APB2ENR_IOPAEN; //настраиваем как двухтактный выход GPIOA->CRL &= ~GPIO_CRL_CNF0; //с максимальной частотой 50MHz GPIOA->CRL |= GPIO_CRL_MODE0; //выбираем вывод который хотим залочить GPIOA->LCKR |= GPIO_LCKR_LCK0; //записываем 1 GPIOA->LCKR |= GPIO_LCKR_LCKK; //записываем 0 GPIOA->LCKR &= ~GPIO_LCKR_LCKK; //записываем 1 GPIOA->LCKR |= GPIO_LCKR_LCKK; //считываем 2 раза temp = GPIOA->LCKR; temp = GPIOA->LCKR; }
Для получения более подробной информации можно обратиться Reference Manual RM0008 , к разделу General-purpose and alternate-function I/Os (GPIOs and AFIOs) .

Во втором уроке цикла, посвященного работе с микроконтроллерами STM32, речь пойдет о портах ввода/вывода.
Порты микроконтроллера позволяют взаимодействовать с внешними устройствами, начиная от светодиода и кнопки и заканчивая более сложными устройствами: дисплеями, GPS и GSM модемами и так далее. Также порты позволяют организовать связь с другими устройствами, например с компьютером.

General Purpose Input/Output (GPIO). GPIO основной и часто применяемый способ связи с внешней средой. Порты могут работать в двух режимах: вход (прием сигнала) и выход (передача сигнала). Работают они только с логическими уровнями 0 (низкий уровень) или 1 (высокий уровень).
Например, если подключить к порту в режиме выхода светодиод, то при подаче сигнала высокого уровня светодиод будет светиться, а при подаче низкого – потухнет.
Если включить вывод в режим входа и подключить к нему кнопку, то с помощью микроконтроллера можно отслеживать ее состояние: нажатое или отпущенное.
По сути GPIO самый простой и примитивный способ организации работы с внешними устройствами, но использование обработки прерываний и таймеров значительно расширяет возможности. Речь о них пойдет немного позже.

Решим первую практическую задачу: управление светодиодами и считывание состояние кнопки.
Следует отметить очень важный момент – порты микроконтроллера могут выдать ток не более 20 мА. Хотя выдать он их может, но один раз и ненадолго, до хлопка и сизого дыма;). Для подключения более мощных нагрузок следует использовать силовые ключи.

Итак, начнем. Для работы возьмем плату STM32F4 Discovery. На ней изначально установлена пользовательская кнопка, подключенная к порту PA0 и 4 светодиода, подключенные к портам PD12-PD15.

Схема подключение кнопки и светодиодов показаны на рисунке.

Резистор R1 номиналом 10кОм – «подтяжка к земле», позволяет избежать ситуации, когда порт не подключен ни к «0», ни к «1» - этого необходимо избегать, а резистор решает эту проблему. Такую подтяжку можно включить и программно, но лучше обезопасить себя так.

Резисторы R2-R5 330Ом ограничивают ток, протекающий через светодиоды. Их можно выбрать в диапазоне от 200Ом до 1кОм, все зависит от необходимой яркости.

Теперь перейдем к написанию программы. В качестве среды разработки я использую . Среда бесплатная и, на мой взгляд, удобная. Как начинать в ней работать рассказывать не буду – в интернете по ней достаточно информации, для прошивки использую STM32 ST-LINK Utility.
Для начала включаем тактирование порта A, к которому подключена кнопка:

RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE);

Теперь нужно правильно сконфигурировать порт:

//Структура содержащая настройки порта GPIO_InitTypeDef GPIO_InitStructure; //задаем номер вывода, если кнопка подключена, например к 6 порту, то пишем GPIO_Pin_6 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0; //порт будет работать как цифровой вход GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN;

Существует несколько вариантов режима работы порта:
GPIO_Mode_IN – цифровой вход;
GPIO_Mode_OUT – цифровой выход;
GPIO_Mode_AF – альтернативная функция (UART и т.д.);
GPIO_Mode_AN – аналоговый режим.

//включаем подтяжку к «земле» GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_DOWN;

Возможны следующие режимы «подтяжки»:
GPIO_PuPd_NOPULL – без подтяжки, вывод «болтается в воздухе»
GPIO_PuPd_UP – подтяжка к 3,3В
GPIO_PuPd_DOWN – подтяжка к «земле»

//вызов функции инициализации GPIO_Init(GPIOA, &GPIO_InitStructure);

Теперь сконфигурируем выводы, к которым подключены светодиоды:

//Включаем тактирование порта D RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOD, ENABLE); //Выбираем нужные выводы GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12| GPIO_Pin_13| GPIO_Pin_14| GPIO_Pin_15; //Включаем режим выхода GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT; //вызов функции инициализации GPIO_Init(GPIOD, &GPIO_InitStructure);

Вот и все, порты сконфигурированы. Теперь напишем обработку в основном цикле программы:

While(1) { //Если кнопка нажата, то… if (GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_0)==1) { GPIO_SetBits(GPIOD, GPIO_Pin_12); //Подаем «1» на PD12 delay(); //Функция задержки GPIO_SetBits(GPIOD, GPIO_Pin_13); //Подаем «1» на PD13 delay(); GPIO_SetBits(GPIOD, GPIO_Pin_14); //Подаем «1» на PD14 delay(); GPIO_SetBits(GPIOD, GPIO_Pin_15); //Подаем «1» на PD15 delay(); GPIO_ResetBits(GPIOD, GPIO_Pin_12|GPIO_Pin_13|GPIO_Pin_14|GPIO_Pin_15); //Сбрасываем все пины в «0» delay(); } }

Вот и все, программа готова. Полная версия в архиве с проектом. Работа платы показана на видео.

В этой статье перейдем к разбору действий для управления портами ввода/вывода. В технической документации к плате Discovery с чипом STM32f407VG указано, что светодиоды подключены к порту GPIOD и ножкам 12, 13, 14, 15. Смотрим в RM0090 Reference manual, и видим, что регистры управления порта D (GPIOD) занимают пространство в памяти, начиная с адреса 0x4002 0C00. Дальше в документации идет описания регистров управления GPIOx (где "х" имя порта:A,B,C...). Первый регистр - GPIOx_MODER , адрес смещения - ноль, то есть он первый в блоке и находится по адресу 0x40020C00. Он отвечает за направление тока: на вход, выход, или режим альтернативной функции (то есть к ножкам можно подключать разные внутренние блоки/интерфейсы передачи\приема данных, а не только использовать для вкл/выкл +3V). Так как нам нужно зажечь светодиод, устанавливаем режим вывода ножек 12,13,14,15 . Записываем "01" в каждую пару битов нужных ножек, и записываем получившееся число в указатель на регистр GPIOD moder:

*((uint32_t*)0x40020C00)=0х55000000;

Смотрим дальше, следующий регистр GPIOxOTYPER , можно оставить по умолчанию. GPIOxSPEEDR , скорость считывания состояния ножки, можем оставить по умолчанию. GPIOxPUPDR -регистр позволяет "прижать" ножку к положительному или отрицательному значению тока.
GPIOx_IDR - Регистр только для чтения, указывает на логическое значение на соответствующей ножке. Можно его использовать, например, если нужно узнать нажата ли кнопка, или пришел ли какой нибудь сигнал на ножку.
GPIOx_ODR - регистр для чтения и записи. Запись "1" в нужный бит подаст логическую единицу на соответствующую ножку. Запись "0" - сбросит бит, и установит на ножке логический ноль.
GPIOx_BSRR - Регистр устанавливает логический ноль или единицу на ножках. в отличии от регистра GPIOx_ODR, значение которого нужно переписывать целиком ради установки отдельного бита, GPIOx_BSRR - можно точечно устанавливать соответствующие биты регистра GPIOx_ODR, не перезаписывая его значения целиком. Установка "1" в биты 0-15 , установит биты 0-15 в GPIOx_ODR. Установка "1" в биты 16-31 установит "0" в биты 0-15 в GPIOx_ODR. запись "0" в регистр GPIOx_BSRR не дает никакого эффекта.
GPIOx_LCKR - регистр устанавливающий блокировку на изменение настроек регистров портов.
GPIOx_AFRL - Регистр альтернативных функций ножек 0-7.
GPIOx_AFRH - Регистр альтернативных функций ножек 7-15.

Адреса регистров GPIO

#define RCC_GPIO *((uint32_t*)0x40023830) //.................
#define GPIOA_MODER *((uint32_t*)0x40020000)
#define GPIOA_OTYPER *((uint32_t*)0x40020004)
#define GPIOA_OSPEEDR *((uint32_t*)0x40020008)
#define GPIOA_IDR *((uint32_t*)0x40020010)
#define GPIOA_PUPDR *((uint32_t*)0x4002000C)
#define GPIOA_ODR *((uint32_t*)0x0x40020014)
#define GPIOA_BSRR *((uint32_t*)0x40020018)
#define GPIOA_AFRL *((uint32_t*)0x40020020)
#define GPIOA_AFRH *((uint32_t*)0x40020024)
//.................
#define GPIOB_MODER *((uint32_t*)0x40020400)
#define GPIOB_OTYPER *((uint32_t*)0x40020404)
#define GPIOB_OSPEEDR *((uint32_t*)0x40020408)
#define GPIOB_IDR *((uint32_t*)0x40020410)
#define GPIOB_PUPDR *((uint32_t*)0x4002040C)
#define GPIOB_ODR *((uint32_t*)0x40020414)
#define GPIOB_BSRR *((uint32_t*)0x40020418)
#define GPIOB_AFRL *((uint32_t*)0x40020420)
#define GPIOB_AFRH *((uint32_t*)0x40020424)
//................
#define GPIOC_MODER *((uint32_t*)0x40020800)
#define GPIOC_OTYPER *((uint32_t*)0x40020804)
#define GPIOC_OSPEEDR *((uint32_t*)0x40020808)
#define GPIOC_IDR *((uint32_t*)0x40020810)
#define GPIOC_PUPDR *((uint32_t*)0x4002080C)
#define GPIOC_ODR *((uint32_t*)0x40020814)
#define GPIOC_BSRR *((uint32_t*)0x40020818)
#define GPIOC_AFRL *((uint32_t*)0x40020820)
#define GPIOC_AFRH *((uint32_t*)0x40020824)
//.................
#define GPIOD_MODER *((uint32_t*)0x40020C00)
#define GPIOD_OTYPER *((uint32_t*)0x40020C04)
#define GPIOD_OSPEEDR *((uint32_t*)0x40020C08)
#define GPIOD_IDR *((uint32_t*)0x40020C10)
#define GPIOD_PUPDR *((uint32_t*)0x40020C0C)
#define GPIOD_ODR *((uint32_t*)0x40020C14)
#define GPIOD_BSRR *((uint32_t*)0x40020C18)
#define GPIOD_AFRL *((uint32_t*)0x40020C20)
#define GPIOD_AFRH *((uint32_t*)0x40020C24)
//................
#define GPIOE_MODER *((uint32_t*)0x40021000)
#define GPIOE_OTYPER *((uint32_t*)0x40021004)
#define GPIOE_OSPEEDR *((uint32_t*)0x40021008)
#define GPIOE_IDR *((uint32_t*)0x40021010)
#define GPIOE_PUPDR *((uint32_t*)0x4002100C)
#define GPIOE_ODR *((uint32_t*)0x40021014)
#define GPIOE_BSRR *((uint32_t*)0x40021018)
#define GPIOE_AFRL *((uint32_t*)0x40021020)
#define GPIOE_AFRH *((uint32_t*)0x40021024)




Top