Допустим, нам необходимо перенести нашу последнюю программу на другой микроконтроллер семейства STM32. Это потребует множества переписываний и изменений в коде, включая открытие технической документации, проверку имен и форматов, исправление ошибок и т.д. Однако, все эти трудности могут быть устранены с помощью библиотеки HAL, которая позволяет работать с понятными объектами вместо сложных регистров конфигурации. Изучим работу с портами GPIO и выводами портов, управление которыми не сложнее, чем в системе Arduino, за исключением большего количества режимов.
Необходимо установить конфигурацию выводов:
PB12 – Вход с подтягивающим на шину питания резистором. К нему у нас подключена кнопка.
PB13 – Активный выход. Мы подключили к нему светодиод.
PC13 – Активный выход. К нему подключен светодиод платы.
Реализовать алгоритм управления светодиодом от кнопки:
Кнопка нажата – светодиод светится;
Кнопка отжата – светодиод погашен.
Постановка задачи.

С помощью STM32CubeMX создадим проект Lesson8_1, в котором настроим только систему тактирования. Конфигурацию портов создавать нее будем. Сделаем это с помощью функций библиотеки HAL. Будем заполнять файл main.c постепенно.
Команды инициализации будем вставлять в блок

Файла maiv.c.
Если мы не разрешили тактирование портов в STM32CubeMX, то надо это сделать функцией __HAL_RCC_GPIOx_CLK_ENABLE().
Не будем вдаваться в подробности, просто выполним команды разрешения портов B и C.
__HAL_RCC_GPIOB_CLK_ENABLE(); // разрешение порта B
__HAL_RCC_GPIOC_CLK_ENABLE(); // разрешение порта C
Заходим в справочник по функциям HAL для управления портами и видим на первом месте функцию инициализации HAL_GPIO_Init.
Void HAL_GPIO_Init (GPIO_TypeDef * GPIOx, GPIO_InitTypeDef * GPIO_Init)
Функция имеет 2 аргумента:
GPIOx – это имя порта, с которым мы работаем. Указывается в общепринятом виде: GPIOA, GPIOB, GPIOC и т.д.
GPIO_Init – указатель на структуру параметров инициализации.
Структура описывается так:

Подробно назначение элементов структуры и варианты значений для них можно посмотреть в справочнике.
Для инициализации порта нам необходимо объявить структуру типа GPIO_InitTypeDef.
GPIO_InitTypeDef GPIO_InitStruct = {0};
Задаем нужные элементы структуры для вывода PB12.

Вызываем функцию HAL_GPIO_Init для порта B.
HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
Делаем тоже самое для выводов PB13 и PC13.

Установка конфигурации наших трех выходов закончена.
Дальше нам необходимо считать состояние вывода PB12. К нему мы подключили кнопку.
Сделать это можно функцией HAL_GPIO_ReadPin.
Полный формат: GPIO_PinState HAL_GPIO_ReadPin (GPIO_TypeDef * GPIOx, uint16_t GPIO_Pin).
У функции 2 аргумента:
GPIOx – выбор порта (GPIOA, GPIOB, GPIOC … ).
Pin – номер вывода (GPIO_PIN_0 … GPIO_PIN_15).
Функция возвращает состояние вывода, которое может принимать 2 значения:
GPIO_PIN_SET – высокий уровень;
GPIO_PIN_RESET – низкий уровень.
Блок проверки состояния кнопки будет выглядеть так.

Вставляем его в программу, но уже в цикл while(1) перед завершением блока.

Теперь надо в зависимости от положения кнопки установить вывод PB13 (светодиод) в нужное состояние.
Для установки и сброса выводов портов есть функция HAL_GPIO_WritePin.
Формат: void HAL_GPIO_WritePin (GPIO_TypeDef * GPIOx, uint16_t GPIO_Pin, GPIO_PinState PinState).
Аргументы:
GPIOx – выбор порта (GPIOA, GPIOB, GPIOC … ).
Pin – номер вывода (GPIO_PIN_0 … GPIO_PIN_15).
PinState – состояние вывода:
GPIO_PIN_SET – высокий уровень;
GPIO_PIN_RESET – низкий уровень.
Чтобы зажечь светодиод надо вызвать функцию:
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_13, GPIO_PIN_RESET); // сброс вывода PB13
Погасить светодиод можно функцией:
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_13, GPIO_PIN_SET); // установка вывода PB13
Вставляем эти команды в ветки оператора условного перехода.

Для обращения к кнопке, светодиоду мы использовали абсолютные имена – номера выводов, название портов. Это не совсем удобно.
Давайте создадим новый проект Lesson8_2. Настроим конфигурацию системы тактирования, назначим вывод PB12 на режим вход с подтягивающим к питанию резистором, определим вывод PB13, как активный вывод. И самое главное – присвоим им имена (User label) Button и Led.
Откроем новый проект. Заглянем в файл main.h.

Там вот такой блок.

STM32CubeMX сделал для кнопки 2 переназначения основных аргументов HAL-функций управления портами :
К имени вывода (Button) он добавил _Pin и присвоил стандартное название номера вывода GPIO_PIN_12.
К имени вывода (Button) он добавил _GPIO_Port и присвоил стандартное название порта GPIOB.
И такую же операцию конфигуратор совершил над именем светодиода (Led).
Теперь в функциях в качестве параметров мы можем использовать символьные имена, часть которых мы задали на этапе конфигурации с помощью STM32CubeMX.
С учетом этого наша конструкция в цикле while() будет выглядеть так:

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