STM32-Порты ввода/вывода
Открываем STM32CubeMX, выбираем «Access to MCU selector», выбираем контроллер, например STM32F103C8T6 (стоит на bluepill)
Откроется примерно следующее окно

Слева в разделе System Core -> SYS выбираем Debug -> Serial Wire (этим мы добавляем возможность отладки и перепрошивки без Reset)
разделе System Core -> RCC выбираем High Speed Clock (HSE) -> Crystal/… resonator (этим мы добавляем кварцевый резонатор)
далее выбираем требуемый пин (например PC13) и нажимаем на него левой кнопкой мыши.
общий вид меню будет как на рисунке
Для пина мы можем выбрать ряд функций, наиболее интересны в рамках статьи — функции Input и Output.
Для примера выберем Output.
Перейдем в меню System Core -> GPIO (в старых версиях CubeMX вкладка Configurations -> GPIO )

GPIO Output level — уровень после инициализации.
GPIO mode — тип пина (притяжка/открытый коллектор)
GPIO Pull up/Pull down — тип притяжки (не притянуто/притянуто к vcc/притянуто к gnd)
стоит оговориться что притяжка (потягивающий резистор) в stm32 достаточно высокоомный и его нежелательно использовать для интерфейсов связи.
например DS1302 (RTC) управляются по I2C, я делал программную реализацию и пришлось использовать open drain и внешний подтягивающий резистор в 10к
Впрочем всегда и на всех контроллерах рекомендуются внешние резисторы для интерфейсов связи.
Maximum output speed — максимальная скорость переключения (влияет на фронты импульсов и потребление)
User Label — пользовательское обозначение (в файле main.h создается #define и впоследствии можно обращаться к пину посредством этого имени) обычно я прописываю (переписываю) это вручную, чтобы при изменении пинов в CubeMX не задумываться о пинах и правильном их названии, а потом в проекте изменяю дерективы defines.
Перейдем во вкладку Clock Configuration

Настроим тактирование от внешнего кварцевого резонатора (включали его выше) частотой 8МГц (если у вас другой-впишите свое значение), для этого выберем HSE (external)
выберем PLLCLK (тактирование от сигнала после умножителя частоты) в результате SysCLK и HCLK стали равными 16МГц (при кварце 8МГц) максимальная частота для этого м/к 72МГц.
Стоит оговориться — максимальная частота обозначает и максимальное потребление, поэтому разумнее всего использовать максимальную частоту на стадии разработки и отладки проекта, после оптимизировать код и уменьшать частоту и потребление.
После переходим на вкладку Project Manager вводим название проекта, его расположение, выбираем Toolchain/IDE ( у меня Keil uVision поэтому выбираю MDK ARM).
Примечание: Во вкладке «Code Generator» можно выбрать «Copy only the necessary library files» в этом случае CubeMX скопирует только требуемый библиотеки и проект будет весить существенно меньше.
Нажимаем GENERATE CODE справа в верху и CubeMX сгенерирует проект.
В сгенерированном проекте в файле main.c в вечном цикле можно прописать код, например:
HAL_GPIO_TogglePin(GPIOC,GPIO_PIN_13);
HAL_Delay(100);
Фрагмет кода будет выглядеть так:
/* USER CODE BEGIN WHILE */
while (1)
{
HAL_GPIO_TogglePin(GPIOC,GPIO_PIN_13);
HAL_Delay(100);
/* USER CODE END WHILE */
ВАЖНО пользовательский код писать между тегами /* USER CODE BEGIN WHILE */ и /* USER CODE END WHILE */, тогда при изменении в CubeMX эта часть кода не удалится!
Далее для платы BluePill подключаем программатор ST-LINK в соответствии с распиновкой:
VCC-3v3
SWDIO-SWDIO
SWCLK-SWCLK
GND-GND
на более «навороченных» отладочных платах Discovery/Nucleo программатор установлен на плате и достаточно подключить его по usb к компьютеру и поставить перемычки на прошивку контроллера.
Компилируем код и загружаем его.
HAL_Delay(100); — функция задержки в библиотеке HAL, создает задержку в мс (в данном случае 100мс)
Функция изменения состояния пина:
HAL_GPIO_TogglePin(GPIOC, GPIO_PIN_13); //если первичное состояние 1, то меняет на 0; а если 0, то меняет на 1
Функция выставления уровня на пине:
HAL_GPIO_WritePin(GPIOC, GPIO_PIN_13, GPIO_PIN_RESET); //лог. 0
HAL_GPIO_WritePin(GPIOC, GPIO_PIN_13, GPIO_PIN_SET); //лог. 1
Функция чтения состояния пина:
HAL_GPIO_ReadPin(GPIOC, GPIO_PIN_13);
В библиотеке HAL нет возможности обращаться сразу ко всему порту, поэтому приходится прописывать пины через «или»
Например:
HAL_GPIO_WritePin(GPIOC, GPIO_PIN_13 | GPIO_PIN_14, GPIO_PIN_RESET); //выставить пины 13 и 14 в лог. 0
