Вы можете настроить выводы микроконтроллера в режим входа или выхода, перевести выход в низкий (0V) или высокий (3.3V) уровень, выбрать внутренние подтягивающие резисторы (pull resistors), выбрать тип выхода и скорость его переключения. В этой статье будут показаны примеры работы с GPIO микроконтроллера STM32F103RBT6 на оценочной плате STM32F103R-BOARD [1] с помощью функций CMSIS [3]. Непонятные термины и сокращения см. в статье [2].
[Тактирование GPIO]
Чтобы можно было работать с выводом, нужно разрешить его тактирование. Это делается с помощью программирования блока RCC (Reset and Clock Control). У микроконтроллера STM32F103xxx все выводы GPIO обслуживаются шиной AHB2. В примерах мы будем использовать порты GPIOB и GPIOC, потому что на плате [1] светодиоды D1 и D2 подключены к ножкам портов PB9 и PB8, а кнопки S2 и S3 к PC0 и PC1.
Мы можем разрешить тактирование следующим образом:
//RCC_APB2PeriphResetCmd(RCC_APB2Periph_GPIOB, DISABLE);
//RCC_APB2PeriphResetCmd(RCC_APB2Periph_GPIOC, DISABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC, ENABLE);
Примечание: в примерах от OLIMEX перед разрешением тактов почему-то тактирование запрещалось, однако на практике оказалось, что это делать не нужно, и поэтому первые строчки я закомментировал.
Подробнее про настройку тактирования при первоначальном старте микроконтроллера см. статью [4].
[Настройка GPIO]
На следующем шаге необходимо подготовить структуру опций порта GPIO_InitTypeDef, чтобы правильно настроить его поведение. Если Вы подключили библиотеку GPIO к проекту (это файлы stm32f10x_gpio.c и stm32f10x_gpio.h), то можете сделать это следующим образом:
// Переменная для настройки опций порта GPIO:
GPIO_InitTypeDef GPIO_InitDef;
Опции порта настраиваются через 3 поля структуры GPIO_InitTypeDef:
GPIO_Pin: выбор ножек, для которых будут устанавливаться опции (битовая маска). GPIO_Speed: выбор скорости работы вывода. GPIO_Mode: выбор режима работы порта (вход, выход, периферийное устройство, АЦП или ЦАП, наличие или отсутствие подтягивающего резистора, открытый сток или двухтактный драйвер).
Каждое из перечисленных выше полей имеет свой набор опций.
GPIO_Pin. Ниже показано использование поля GPIO_Pin, которое выбирает настраиваемые выводы портов.
// Применение настроек только к порту GPIO_Pin_8:
GPIO_InitDef.GPIO_Pin = GPIO_Pin_8;
// Если Вы хотите одинаково настроить несколько выводов портов,
// то в поле GPIO_Pin записывается соответствующая маска. Например,
// порты GPIO_Pin_8 и GPIO_Pin_9 будут настроены одинаково:
GPIO_InitDef.GPIO_Pin = GPIO_Pin_8 | GPIO_Pin_9;
// Следующая настройка задает одинаковые опции ко всем выводам портов:
GPIO_InitDef.GPIO_Pin = GPIO_Pin_All;
GPIO_Speed. Поле выбирает скорость работы GPIO (100, 50, 25 или 2 МГц).
GPIO_Speed_100MHz GPIO_Speed_50MHz GPIO_Speed_25MHz GPIO_Speed_2MHz
GPIO_Mode. Это поле выбирает режим работы порта.
GPIO_Mode_AIN: аналоговый вход (АЦП). GPIO_Mode_IN_FLOATING: плавающий вход (без подтягивающего резистора). GPIO_Mode_IPD: вход с нижним подтягивающим резистором. GPIO_Mode_IPU: вход с верхним подтягивающим резистором. GPIO_Mode_Out_OD: выход с открытым стоком (Open Drain). GPIO_Mode_Out_PP: двухтактный выход (Push-Pull). GPIO_Mode_AF_OD: аналоговый выход (ЦАП на основе ШИМ) с открытым стоком. GPIO_Mode_AF_PP: аналоговый выход (ЦАП на основе ШИМ) с двухтактным драйвером.
После того, как поля структуры GPIO_InitDef настроены должным образом, нужно вызывать функцию GPIO_InitDef со ссылкой на эту структуру.
Пример функции, которая настраивает порты PB9 и PB8 для управления светодиодами D1 и D2 платки [1]:
#define LEDSPORT GPIOB
#define LED1_PIN GPIO_Pin_9
#define LED2_PIN GPIO_Pin_8
inline void LEDs_init (void)
{
// Структура для настройки портов:
GPIO_InitTypeDef GPIO_InitStructure;
// Разрешение тактирования GPIOB:
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
// Инициализация полей структуры:
GPIO_InitStructure.GPIO_Pin = LED1_PIN | LED2_PIN;// ножки портов PB9 и PB8
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; // двухтактный драйвер
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; // скорость 50 МГц
// Настройка портов светодиодов.
GPIO_Init(LEDSPORT, &GPIO_InitStructure);
}
Примечание: в этом примере выходы портов PB9 и PB8 настроены как двухтактные GPIO_Mode_Out_PP, хотя можно было использовать драйвер с общим стоком GPIO_Mode_Out_OD (потому что светодиоды D1 и D2 подключены к +3.3V).
[Управление выходами GPIO]
Переключать выход в лог. 0 или в лог. 1 может функция GPIO_WriteBit:
void GPIO_WriteBit(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin, BitAction BitVal);
Первый параметр задает группу ножек портов (для светодиодов D1 и D2 это GPIOB), второй параметр задает маску для управляемых портов, третий параметр задает тип действия с портами (сброс или установка).
// Перевод в лог. 0 вывода порта светодиода D1 (светодиод загорится):
GPIO_WriteBit(LEDSPORT, LED1_PIN, Bit_RESET);
// Перевод в лог. 1 вывода порта светодиода D1 (светодиод погаснет):
GPIO_WriteBit(LEDSPORT, LED1_PIN, Bit_SET);
[Опрос входов GPIO]
На платке [1] есть две кнопки S2 и S3, подключенные к ножкам портов PC0 и PC1 соответственно. Ниже показано, как сконфигурировать их на вход с разрешением верхнего подтягивающего резистора (нажатие на кнопку будет переводить уровень входа с лог. 1 на лог. 0).
inline void S2S3_init (void)
{
GPIO_InitTypeDef GPIO_InitStructure;
// Разрешение тактирования GPIOC:
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC, ENABLE);
// Настройка полей структуры для кнопок:
GPIO_InitStructure.GPIO_Pin = S2_PIN | S3_PIN; // ножки кнопок
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU; // Входы с pull-up резистором
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz;// скорость работы 2 МГц
// Инициализация входов кнопок:
GPIO_Init(BUTTONSPORT, &GPIO_InitStructure);
}
// Макрос, возвращающий 1, если кнопка нажата:
#define PRESSED(x) GPIO_ReadInputDataBit(BUTTONSPORT,x)?0:1
Прочитать логический уровень цифрового входа можно функцией GPIO_ReadInputDataBit:
uint8_t GPIO_ReadInputDataBit(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin);
Первый параметр задает группу ножек портов (для кнопок S2 и S3 это GPIOC), второй задает маску, определяющую конкретный опрашиваемый вывод порта. Пример чтения уровня кнопки S2:
if (0 == GPIO_ReadInputDataBit(GPIOC, GPIO_Pin_0))
{
// Кнопка нажата, зажжем светодиод D1:
GPIO_WriteBit(GPIOB, GPIO_Pin_9, Bit_RESET);
}
else
{
// Кнопка отпущена, погасим светодиод D1:
GPIO_WriteBit(GPIOB, GPIO_Pin_9, Bit_SET);
}
[Ссылки]
1. STM32F103R-BOARD. 2. STM32: аббревиатуры и термины. 3. Cortex Microcontroller Software Interface Standard. 4. STM32: тактирование и запуск. |