Большинство выводов STM32 могут быть сконфигурированы как вход или выход и могут быть подключены либо к портам GPIO, либо к «альтернативным функциям» (другим периферийным устройствам). В соответствии со стандартным соглашением об именах контакты вызываются их функцией GPIO — например, PA0 (бит 0 порта A) или PB9 (бит 9 порта B). С учетом конкретных аппаратных ограничений каждый вывод может быть сконфигурирован в режимах, показанных в следующем рисунке:
По умолчанию большинство выводов сбрасывается на «Input Floating» — это гарантирует, что при включении системы не возникнет аппаратных конфликтов. Библиотека встроенного программного обеспечения предоставляет процедуру инициализации в stm32f10x_gpio. [Ch], которая может использоваться для перенастройки выводов:
// see stm32f10x_gpio.h GPIO_InitTypeDef GPIO_InitStructure; GPIO_StructInit(&GPIO_InitStructure); GPIO_InitStructure.GPIO_Pin = GPIO_Pin_13; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz; GPIO_Init(GPIOC , &GPIO_InitStructure);
При настройке выхода, как показано выше, у нас есть три варианта «скорости» вывода: 50 МГц, 10 МГц и 2 МГц. Как правило, по причинам энергопотребления и шума желательно использовать самую низкую скорость, соответствующую требованиям ввода-вывода. Поле GPIO_Pin является битовым вектором, и можно настроить несколько выводов, связанных с одним портом, за один шаг.
Примечание. Выводы для отдельных частей(включая назначение периферийных устройств к выводам) определены в соответствующих даташитах, а НЕ в руководстве по программированию!
Как мы уже видели, мы можем записать значение на вывод, управляющий светодиодом, с помощью следующих процедур:
GPIO_WriteBit(GPIOC , GPIO_Pin_13 , x); // x is Bit_SET or Bit_RESET
Модуль библиотеки gpio предоставляет процедуры для чтения и записи как отдельных выводов, так и целых портов — последнее особенно полезно при захвате параллельных данных. Поучительно прочитать stm32f10x_gpio.h. Чтобы (повторно) настроить вывод, связанный с нашей платой, мы можем использовать следующий код (после настройки RCC для порта A!):
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; GPIO_Init(GPIOA , &GPIO_InitStructure);
Чтобы прочитать текущее значение кнопки, мы можем выполнить:
GPIO_ReadInputDataBit(GPIOA , GPIO_Pin_0)
Вспомним, что каждый порт GPIO управляется 7 регистрами:
typedef struct
{
volatile uint32_t CRL;
volatile uint32_t CRH;
volatile uint32_t IDR;
volatile uint32_t ODR;
volatile uint32_t BSRR;
volatile uint32_t BRR;
volatile uint32_t LCKR;
} GPIO_TypeDef;
16 бит каждого порта сконфигурированы с помощью CRL (биты 0-7) и CHR (контакты 8-15). Для поддержки различных режимов ввода / вывода для каждого бита GPIO требуется 4 бита конфигурации. 16 бит GPIO могут считываться параллельно (IDR) и записываться параллельно (ODR). Для удобства регистры BSRR и BRR предоставляют механизм для установки и сброса отдельных битов. Регистр блокировки LCKR предоставляет механизм для «блокировки» конфигурации отдельных битов от реконфигурации программного обеспечения и, следовательно, для защиты оборудования от программных ошибок.
Можно изменить программу blink, чтобы дополнительно отслеживать состояние кнопки пользователя (PAxx) на светодиоде (PC13). Чтобы посмотреть, как настроить оба светодиода с помощью одного вызова GPIO_Init.
