Управление портами ввода-вывода через регистры CMSIS

Одним из способов формирования начальной конфигурации является использование STM32CubeMX и библиотеки HAL. Для передачи данных в программе можно использовать регистры CMSIS. Обычно начальные настройки остаются неизменными в течение выполнения программы.

С портами ввода-вывода все более сложно. Их использование затрудняется как высокочастотными сигналами, так и необходимостью оперативно изменять режимы работы. В определенных случаях, особенно при двунаправленных сигналах, может потребоваться быстрое изменение порта на режим входа или выхода.

В связи с этим, прямое управление портами ввода-вывода через доступ к регистрам является широко используемым методом.

Для примера мы собираемся установить режимы работы:

  • Для вывода PB12 – вход с подтягивающим резистором к шине питания;
  • Для вывода PB13 – активный выход.

Позже подключим к этим выводам кнопку и светодиод, напишем управляющую программу.

Для конфигурации порта GPIOB необходимо выполнить определенную последовательность действий.

Прежде всего, разрешить работу порта в регистре Разрешения тактирования периферийных устройств шины APB2 (APB2 peripheral clock enable register) RCC_APB2ENR. За порт B отвечает бит IOPBEN. Установим его в 1.

RCC->APB2ENR |= RCC_APB2ENR_IOPBEN;

Конфигурирование этой операции уже было выполнено за нас с помощью STM32CubeMX. Нам оставалось только выбрать активные выводы, соответствующие порту B.

Биты конфигурации и режима для вывода PB12 расположены в регистре:

GPIOB_CRH, биты CNF12[1:0] и MODE12[1:0].

Смотрим по таблицам режима и конфигурации портов. Надо установить состояние:

CNF12[1:0], MODE12[1:0] = 10, 00 (режим вход).

Установка состояния в регистрах конфигурации.

image

Структура для регистров портов в нем описана так.

Typedef struct

{

__IO uint32_t CRL;

__IO uint32_t CRH;

__IO uint32_t IDR;

__IO uint32_t ODR;

__IO uint32_t BSRR;

__IO uint32_t BRR;

__IO uint32_t LCKR;

} GPIO_TypeDef;

В ней все наши регистры для управления портами ввода-вывода, о которых мы говорили в предыдущем уроке.

Мы должны установить в регистре GPIOB_CRH, биты 19-16 в состояние 1000. Можно просто загрузить в регистр данное.

GPIOB->CRH = 0x00080000;

В этом случае мы сбросим все остальные биты. Что-то перестанет работать. Но если в загружаемом числе сформировать все биты этого регистра сразу, то способ вполне допустимый. Более того это самый быстрый и короткий вариант.

Если мы хотим затронуть только нужные биты, то можно сделать так.

GPIOB->CRH &= 0xfff0ffff; // сбрасываем биты 16-19

GPIOB->CRH |= 0x00080000; // устанавливаем биты

Вариант быстрый, но запутанный. Надо вычислять расположение битов в слове, большая вероятность ошибки.

Можно несколько упростить, используя операцию сдвига.

GPIOB->CRH &= ~ ( 0b1111 << 16 ); // сбрасываем биты 16-19

GPIOB->CRH |= 0b1000 << 16; // устанавливаем биты

Все вычисления с константами компилятор сделает на этапе трансляции и в правой части операций получатся точно такие числа, как и в предыдущем варианте.

В файле stm32f103xb.h есть имена и для битов регистра GPIOx_CRH. Вот, что касается 12го разряда.

image

Установка регистра конфигурации с использованием имен битов выглядит так.

GPIOB->CRH &= ~ (GPIO_CRH_CNF12 | GPIO_CRH_MODE12); // сбрасываем биты полей CNF и MODE

GPIOB->CRH |= (0b10 << GPIO_CRH_CNF12_Pos) | (0b00 << GPIO_CRH_MODE12_Pos) ; // устанавливаем биты

Это предпочтительный, общепринятый способ доступа к отдельным полям регистров.

Установим таким способом вывод PB13 в режим выхода. Для этого надо в поля CNF13[1:0], MODE13[1:0] установить = 00, 10 (режим выход).

GPIOB->CRH &= ~ (GPIO_CRH_CNF13 | GPIO_CRH_MODE13); // сбрасываем биты полей CNF и MODE

GPIOB->CRH |= (0b00 << GPIO_CRH_CNF13_Pos) | (0b10 << GPIO_CRH_MODE13_Pos) ; // устанавливаем биты

Теперь попробуем считать и установить состояния выводов. Давайте подключим к выводу PB12 кнопку, а к выводу PB13 светодиод.

image

И напишем программу, которая управляет светодиодом с помощью кнопки. Кнопка нажата – светодиод светится, отжата – светодиод погашен.

Считать состояние вывода можно через регистр ввода данных.

В структуре GPIO_TypeDef это регистр IDR. Проверяем 12й бит.

image

Для бита 12 регистра IDR есть имя, но оно не сильно улучшает читаемость программы.

image

Используя имя бита можно написать:

If( (GPIOB->IDR & GPIO_IDR_IDR12) == 0 ) {

Теперь об установке логического состояния выхода. Есть несколько вариантов.

Первый – через регистр вывода. Установка бита 13:

GPIOB->ODR |= 1 << 13; Или GPIOB->ODR |= GPIO_ODR_ODR13;

Сброс бита 13:

GPIOB->ODR &= ~(1 << 13); Или GPIOB->ODR &= ~ GPIO_ODR_ODR13;

Вставляем в логические блоки включение и выключение светодиода.

image

И всю эту конструкцию в цикл while(1) в файле main.c.

Для установки состояния вывода порта мы использовали последовательность: чтение регистра вывода данных, установку бита и запись в этот же регистр. В предыдущем уроке я писал про регистр установки/сброса битов, с помощью которого можно выполнить изменение состояния выхода одним обращением к регистру.

Если нам надо установить вывод PB13 в 1, то:

GPIOB -> BSRR = GPIO_BSRR_BS13; // установка бита

Для сброса бита надо выполнить команду:

GPIOB -> BSRR = GPIO_BSRR_BR13; // сброс бита

Можно сбросить или установить сразу несколько битов одним обращением к регистру BSRR. Это будет выглядеть так.

GPIOB -> BSRR = GPIO_BSRR_BS10 | GPIO_BSRR_BS15 | GPIO_BSRR_BR11 | GPIO_BSRR_BR12; // установить биты 10 и 15, сбросить биты 11 и 12

Проверяем в программе.

image

Еще для завершения конфигурации портов надо установить 1 в регистр вывода данных для бита PB12, настроенного на вход. Тем самым мы подключим подтягивающий резистор к шине питания, а не к земле.

GPIOB -> BSRR = GPIO_BSRR_BS12; // подтягивающий резистор к + 3 В

Добавим эту строку в блок начальной конфигурации портов.

С регистром защиты LCKR разберетесь сами. Установка и сброс битов:

GPIOB -> LCKR |= GPIO_LCKR_LCK12 | GPIO_LCKR_LCK13;

GPIOB -> LCKR &= ~ (GPIO_LCKR_LCK110 | GPIO_LCKR_LCK11);

GPIOB -> LCKR |= GPIO_LCKR_LCKK;

GPIOB -> LCKR &= ~ GPIO_LCKR_LCKK;

Автор: Эдуард

Микроконтроллер STM32

Одна из линеек микроконтроллеров, которые производит компания STMicroelectronics.

Применяемость

Создана для широкого спектра применений, и применяются в различных областях, включая автоматизацию домашней электроники, транспортные средства, медицинские устройства, устройства IoT, промышленные автоматизированные системы и различные приборы и устройства.