Stm8. описание gpio и библиотека spl

STM Урок 3. Библиотека SPL. Подключаем кнопку

Урок 3

Библиотека SPL. Подключаем кнопку

Сегодня мы с вами продолжим работу с библиотекой SPL, которую мы подключили на прошлом занятии. Хотя это прошло слегка нестандартным способом, но тем не менее нам это удалось. Вообщем, библиотеку мы подключили, но практически с её функциями мы пока не работали.

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

Запустим порект, соберём его, настроим программатор, поршьём контроллер и проверим работоспособность кода прошлого занятия, но уже в номвом проекте.

Теперь можно начинать написание нового кода.

Подключим к плате светодиодную матрицу, состоящую из 10 светодиодов.

Также мы не забываем в цепь каждого светодиода включить токоограничивающий резистор. У меня резисторы исользуются номиналом в 680 ом. Вот схема подключения (нажмите на картинку для увеличения изображения)

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

Вот так выглядит данная функция в справке.

Почему мы выбрали именно данную шину? Это объясняется и в Reference Manual на контроллер, а также есть и в справке дальше в объяснении функции. Практически все порты ввода-выводы находятся именно на этой шине

У данной функции 2 аргумента. Первый – это указатель на саму периферию AHB1 и порт ввода-вывода, который мы собираемся начинать тактировать ну или заканчивать, а второй параметр – это команда, она и отвечает за включение или отключение тактирования (ENABLE или DISABLE). Давайте добавим данную функцию в наш код. Откроем файл main.h и вставим код в функцию port_ini. Пока код будем вставлять поверх старого, чтобы ничего не забыть

void port_ini(void)
<
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOD, ENABLE);//включим тактирование порта D

Теперь порт у нас тактируется. Затем нужно нам включить всё остальное.

Сначала инициализация ножек порта. Для этого нам нужна будет структура. Тут есть один нюанс. Данная структура должна быть объявлена до включения тактирования. Вот такая вот структура

Объявим структуру. Имя может быть любое. Но надо привыкать присваивать переменным, структурам, массивам такие имена, чтобы они сами о себе говорили. Тогда у нас будет меньше шансов не понять свой код в дальнейшем и запутаться в нём. Особенно, если этот код мы хотим кому-то показать

void port_ini(void)
<
GPIO_InitTypeDef InitD; //для светодиодов

RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOD, ENABLE);//включим тактирование порта D

В любой структуре перед её использованием нужно заполнить поля. Давайте этим займёмся.

Первое поле будет GPIO_Pin. В том же файле справки есть варианты данного поля

Данное поле говорит о том, какие именно ножки порта мы будем использовать. Перечисляются они через операцию «ИЛИ»

RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOD, ENABLE);//включим тактирование порта D

//светодиоды
InitD.GPIO_Pin = GPIO_Pin_0|GPIO_Pin_1|GPIO_Pin_2|GPIO_Pin_3|GPIO_Pin_4|
GPIO_Pin_5|GPIO_Pin_6|GPIO_Pin_7|GPIO_Pin_8|GPIO_Pin_9;

Таким образом мы объявляем для инициализации в поле структуры определённые ножки порта.

Следующее поле структуры – GPIO_Mode, это также структура, и здесь у нас есть вот такие вот варианты выбора

Я думаю данные варианты сами о себе прекрасно говорят.

В нашем случае потребуется конфигурация порта на выход

InitD.GPIO_Pin = GPIO_Pin_0|GPIO_Pin_1|GPIO_Pin_2|GPIO_Pin_3|GPIO_Pin_4|
GPIO_Pin_5|GPIO_Pin_6|GPIO_Pin_7|GPIO_Pin_8|GPIO_Pin_9;
InitD.GPIO_Mode = GPIO_Mode_OUT;

Следующее поле – GPIO_OType.

Здесь тоже ничего сложного. Выбираем тип Pull Push, открытый коллектор нам не нужен

InitD.GPIO_Mode = GPIO_Mode_OUT;
InitD.GPIO_OType = GPIO_OType_PP;

Следующее поле – GPIO_Speed:

Есть также синонимы.

#define GPIO_Speed_2MHz GPIO_Low_Speed
#define GPIO_Speed_25MHz GPIO_Medium_Speed
#define GPIO_Speed_50MHz GPIO_Fast_Speed
#define GPIO_Speed_100MHz GPIO_High_Speed

Выбираем 2 МГц. Нам спешить некуда

InitD.GPIO_OType = GPIO_OType_PP;
InitD.GPIO_Speed = GPIO_Speed_2MHz;

И последний параметр (поле) структуры – это GPIO_PuPd, который отвечает за подтягивание резистора к ондой из шины питания.

Мы никуда подтягиваться не будем

InitD.GPIO_Speed = GPIO_Speed_2MHz;
InitD.GPIO_PuPd = GPIO_PuPd_NOPULL;

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

Вот функция. Файл справки тот же

Первый параметр – это порт, а второй – указатель на нашу только что заполненную структуру, причем именно указатель.

InitD.GPIO_PuPd = GPIO_PuPd_NOPULL;
GPIO_Init(GPIOD,&InitD); //инициализация ножек порта

Всё. Порт для светодиодов мы инициализировали. Теперь попробуем поуправлять данным портом. Найдём две функции, одна из которых включает ножку порта, а другая отключает

Давайте теперь перейдём в main() и в бесконечном цикле исправим код следующим образом

while(1)
<
GPIO_SetBits(GPIOD, GPIO_Pin_0);
delay(1000000);
GPIO_ResetBits(GPIOD, GPIO_Pin_0);
GPIO_SetBits(GPIOD, GPIO_Pin_1);
delay(1000000);
GPIO_ResetBits(GPIOD, GPIO_Pin_1);
GPIO_SetBits(GPIOD, GPIO_Pin_2);
delay(1000000);
GPIO_ResetBits(GPIOD, GPIO_Pin_2);
GPIO_SetBits(GPIOD, GPIO_Pin_3);
delay(1000000);
GPIO_ResetBits(GPIOD, GPIO_Pin_3);
GPIO_SetBits(GPIOD, GPIO_Pin_4);
delay(1000000);
GPIO_ResetBits(GPIOD, GPIO_Pin_4);
GPIO_SetBits(GPIOD, GPIO_Pin_5);
delay(1000000);
GPIO_ResetBits(GPIOD, GPIO_Pin_5);
GPIO_SetBits(GPIOD, GPIO_Pin_6);
delay(1000000);
GPIO_ResetBits(GPIOD, GPIO_Pin_6);
GPIO_SetBits(GPIOD, GPIO_Pin_7);
delay(1000000);
GPIO_ResetBits(GPIOD, GPIO_Pin_7);
GPIO_SetBits(GPIOD, GPIO_Pin_8);
delay(1000000);
GPIO_ResetBits(GPIOD, GPIO_Pin_8);
GPIO_SetBits(GPIOD, GPIO_Pin_9);
delay(1000000);
GPIO_ResetBits(GPIOD, GPIO_Pin_9);

>

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

Теперь исправим немного код в бесконечном цикле, чтобы предыдущий светодиод у нас гас не сразу, а на следующем цикле, и бежать тогда у нас буду одновременно два огонька

<
GPIO_SetBits(GPIOD, GPIO_Pin_0);
delay(1000000);
GPIO_ResetBits(GPIOD, GPIO_Pin_9);
GPIO_SetBits(GPIOD, GPIO_Pin_1);
delay(1000000);
GPIO_ResetBits(GPIOD, GPIO_Pin_);
GPIO_SetBits(GPIOD, GPIO_Pin_2);
delay(1000000);
GPIO_ResetBits(GPIOD, GPIO_Pin_1);
GPIO_SetBits(GPIOD, GPIO_Pin_3);
delay(1000000);
GPIO_ResetBits(GPIOD, GPIO_Pin_2);
GPIO_SetBits(GPIOD, GPIO_Pin_4);
delay(1000000);
GPIO_ResetBits(GPIOD, GPIO_Pin_3);
GPIO_SetBits(GPIOD, GPIO_Pin_5);
delay(1000000);
GPIO_ResetBits(GPIOD, GPIO_Pin_4);
GPIO_SetBits(GPIOD, GPIO_Pin_6);
delay(1000000);
GPIO_ResetBits(GPIOD, GPIO_Pin_5);
GPIO_SetBits(GPIOD, GPIO_Pin_7);
delay(1000000);
GPIO_ResetBits(GPIOD, GPIO_Pin_6);
GPIO_SetBits(GPIOD, GPIO_Pin_8);
delay(1000000);
GPIO_ResetBits(GPIOD, GPIO_Pin_7);
GPIO_SetBits(GPIOD, GPIO_Pin_9);
delay(1000000);
GPIO_ResetBits(GPIOD, GPIO_Pin_8);
>

Прошьём и посмотрим результат.

Вообщем, научились мы управлять ножками портов на выход. Теперь попробуем отследить состояние порта, которое будет зависеть от подключенной на плате синей кноки. Данная кнопка подключена к ножке 0 порта A, то есть к PA0

Но так как кнопка подключена уже не к порту D, то порт A мы должны также инициализировать, сначала включим для него тактирование, так как тактирование портов у нас отключено из соображений энергоэффективности. Сначала создадим структуру

GPIO_InitTypeDef InitA0; //для кнопки
GPIO_InitTypeDef InitD; //для светодиодов

Запустим тактирование порта, таким же образом проинициализируем поля структуры, соответственно используюя там инициализацию на вход (GPIO_Mode_IN) и в конце вызовем функцию инициализации ножки 0 порта

GPIO_Init(GPIOD,&InitD); //инициализация ножек порта

RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE);//включим тактирование порта A

//кнопка
InitA0.GPIO_Pin = GPIO_Pin_0;
InitA0.GPIO_Mode = GPIO_Mode_IN;
InitA0.GPIO_OType = GPIO_OType_OD;
InitA0.GPIO_Speed = GPIO_Speed_2MHz;
InitA0.GPIO_PuPd = GPIO_PuPd_NOPULL;
GPIO_Init(GPIOA,&InitA0); //инициализация ножек порта

>

А отслеживать состояние ножки мы будем при помощи вот такой функции, похожей также и на ту, с помощью которой мы управляем портами, включенными на выход

Вернёмся в main() в бесконечный цикл и обернём наш код в бесконечном цикле в условие

while(1)
<
if(GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_0)==1) //кнопка нажата
<

GPIO_SetBits(GPIOD, GPIO_Pin_0);
delay(1000000);
GPIO_ResetBits(GPIOD, GPIO_Pin_9);
GPIO_SetBits(GPIOD, GPIO_Pin_1);
delay(1000000);
GPIO_ResetBits(GPIOD, GPIO_Pin_0);
GPIO_SetBits(GPIOD, GPIO_Pin_2);
delay(1000000);
GPIO_ResetBits(GPIOD, GPIO_Pin_1);
GPIO_SetBits(GPIOD, GPIO_Pin_3);
delay(1000000);
GPIO_ResetBits(GPIOD, GPIO_Pin_2);
GPIO_SetBits(GPIOD, GPIO_Pin_4);
delay(1000000);
GPIO_ResetBits(GPIOD, GPIO_Pin_3);
GPIO_SetBits(GPIOD, GPIO_Pin_5);
delay(1000000);
GPIO_ResetBits(GPIOD, GPIO_Pin_4);
GPIO_SetBits(GPIOD, GPIO_Pin_6);
delay(1000000);
GPIO_ResetBits(GPIOD, GPIO_Pin_5);
GPIO_SetBits(GPIOD, GPIO_Pin_7);
delay(1000000);
GPIO_ResetBits(GPIOD, GPIO_Pin_6);
GPIO_SetBits(GPIOD, GPIO_Pin_8);
delay(1000000);
GPIO_ResetBits(GPIOD, GPIO_Pin_7);
GPIO_SetBits(GPIOD, GPIO_Pin_9);
delay(1000000);
GPIO_ResetBits(GPIOD, GPIO_Pin_8);
>
else GPIO_ResetBits(GPIOD,GPIO_Pin_0|GPIO_Pin_1|GPIO_Pin_2|GPIO_Pin_3|GPIO_Pin_4|
GPIO_Pin_5|GPIO_Pin_6|GPIO_Pin_7|GPIO_Pin_8|GPIO_Pin_9);
>

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

addelectronics › Блог › Изучаем STM32. Урок 5. SPL — Standard Peripherals Library

Добрый день. Решил написать ещё одну статейку по STM32. На этот раз мы поговорим о SPL -Standard Peripherals Library. Вообще на данный момент у нас есть 3 варианта написания наших программ для STM32

1)CMSIS — это стандартная библиотека для кортексов. То есть это стандарт. С помощью этой библиотеки мы можем писать наши программы — но только с прямой записью в регистры. Это самый профессиональный способ написания программ, и кстати самый правильный, но сложный, так как придётся от а до я учить даташиты, постоянно сидеть с открытыми доками на процессор чтобы найти куда записать тот или иной бит в регистры.

2)SPL -Standard Peripherals Library — это попытка ST Electronics выпустить одну общую библиотеку для объединения всех своих процессоров. ЧТобы было проще переносить код и т.д и т.п. Работать проще как для начинающего, но всё равно всё вбиваем ручками — Никакой Автоматики!

3)HAL — Hardware Acess Level — это вторая попытка ST Electronics выпустить единую библиотеку для разработки. Заодно с ней вышла и программа CubeMX для настройки всего этого хозяйства.Всё гладко и хорошо по началау, но только по началу — дальше всё, приехали — ни примеров, ни обзоров. Поэтому пока не исследуют эту библиотеку вдоль и поперёк- делов не будет)))

То есть смысл в том что SPL уже вдоль и поперёк всю распилили и изучили. Поэтому, хочешь не хочешь а учить нужно. И вообще нужно стремиться к CMSIS. Но это уже кому захочется))

Итак, давайте попробуем написать простейшую программу для мигания светодиодом с помощью SPL. Первое что нам понадобиться — Reference Manual и Datasheet на наш контроллер. Я этот пример буду писать для контроллера установленного на отладочной плате STM32F4 Discovery — STM32F407VGT6

Идём на сайт ST.com и вбиваем в поиск наш процессор. Качаем в найденном Datasheet и далее переходим на вкладку Design Resources и ниже ищем Reference Manual.

Далее, думаем, что нам нужно. Нужно нам помигать светодиодом. Раз помигать светодиодом, значит мы должны настроить нашу ножку к которой этот светодиод подключён. Вспоминаем (ну или если не знали то читаем) — что изначально все порты микроконтроллера отключены от тактирования, для экономии энергии. Нам же нужно включить тактирование на нужный нам порт. Светодиод у нас подключен к пину 12 порта D.

Читайте также  Как протянуть проводку под гипсокартоном?

Открываем Reference Manual и пробцем искать интересные нам слова как GPIO, Bus, AHB…
Я в самом начале документа нашёл вот такую интересную информацию

Далее. Переходим уже к практике, чтобы сразу и писать программу и читать. Создаём проект в CooCox — Create New Project. Даём название проекту

Далее выбираем для чего мы пишем — Процессор или демо плата. В нашем случае Chip

Выбираем нужный нам контроллер и нажимаем FINISH

Открывается окно репозитория, где нам предлагают выбрать нужные нам библиотеки. Так как нам нужно подать тактирование на порт подключаем библиотеку RCC, Далее — мы же будем работать с портами ввода-вывода, значит подключаем библиотеку GPIO. Также включаем CMSIS BOOT.

Первым делом нам нужно подключить заголовочные файлы

#include «stm32f4xx.h»
#include «stm32f4xx_gpio.h»
#include «stm32f4xx_rcc.h»

Далее, нам нужно проинициализировать нужную переферию. Можно для этого написать отдельную функцию типа init_gpio(), в ней описать всю инициализацию, и потом вызвать её в mainn(), а можно чтобы по простому пока — прямо в main() и написать всю инициализацию. Так и сделаем.

Первое что нам нужно, это подать тактирование на наш portD. Как мы помним — порты ввода-вывода у нас сидят на шине AHB1. Для простоты в CooCox есть примеры инициализаций прямо в репозитории. Вверху на вкладке открываем опять страницу репозитория, где мы библиотеки подключали. Нажимаем на библиотеку RCC, и справа мы видим большой перечень функций. Ищем вот такую RCC_AHB1PeriphClockCmd, нажимаем на неёи видим её полное описание. Выделяем и копируем её в наш проект
void RCC_AHB1PeriphClockCmd ( uint32_t RCC_AHB1Periph, FunctionalState NewState);

Убираем слово void из начала нашей строчки, и далее вписываем два аргумента. Первый Что мы включаем, второй Enable — типо включаем. Кстати начиная писать начало аргумента, нижимете Ctrl+Пробел и у вас вылазит подсказка для упрощения работы.

Итак, тактирование на наш порт D подали. Теперь нам нужно настроить ножку нашего порта. Параметры нашей ножки такие — Выход, Push-Pull, Низкая скорость до 2MHz

Первое, что нам нужно, это обозначить структуру, которая будет хранить настройки нашего порта.Давайте её назовём PIN_INIT. Что такое структура в языке C — читайте в Google!

GPIO_InitTypeDef PIN_INIT;

Теперь нам нужно инициализировать структуру, которую мы только что создали.
GPIO_StructInit (&PIN_INIT);

& — это значок показывает нам что это указатель

Теперь нам нужно нужно заполнить эту структуру.
PIN_INIT.GPIO_Mode = GPIO_Mode_OUT; //режим — выход
PIN_INIT.GPIO_OType = GPIO_OType_PP ; //тип — Push-Pull
PIN_INIT.GPIO_Pin = GPIO_Pin_12; // — пин 12
PIN_INIT.GPIO_Speed = GPIO_Speed_2MHz; //Низкая скорость работы

Ну и осталось записать данные в структуру командой
GPIO_Init(GPIOD, &PIN_INIT); //инициализируем

на этомсобственно и заканчивается вся наша настройка. Но у нас же по тех. заданию — мигание ветодиодом, значит нам нужно ещё и задержку реализовать. Сделаем её примитивной. Вообще все задержки делаются на таймерах и работают в качестве флажков.

Вот наша примитивная задержка

void Delay_ms(uint32_t ms)
<
int i;
for(i=0;i 21 августа 2015 в 15:37

Начинаем писать под stm8, выбираем среды разработки и стартуем

На пути в программировании stm8 есть развилка, о ней сегодня и поговорим.

Определимся что речь будет идти о средах которые могут писать под си. Для начала поговорим о подходах, я выделю 2 основных.

Первый установка ST Visual Develop и выбор в качестве компилятора COSMIC Бывший платный, а ныне бесплатный, но со своими заморочками; регистрация, получение ключа, и прочие танцы с бубном.

Второй же вариант, более простой VS Code + PlatformIO и компилятор SDCC полностью свободный. И опять же не все так просто. Sdcc не умеет исключать не используемые функции. Я решил этот вопрос хоть и успешно, но не без дополнительных действий при написании кода.

Первая среда, для любителей всё делать правильно

Для начала нам нужен ST Visual Develop. Устанавливаем и ставим запуск ярлыка всегда от администратора. В придачу к нему нам дают ST Visual Programmer, полезный инструмент, особенно когда стоит защита от записи и надо разблокировать микроконтроллер, а ведь китайские blue pill всегда приходят заблокированными. Китайцы бояться что мы украдём их круто оптимизированный Blink.

Дальше нужно будет получить компилятор COSMIC и его лицензионный ключ. Заполняем то что просят, получаем дистрибутив и делаем запрос ключа по электронной почте (тут рулетка кому то сразу придёт, кому то придётся подождать).

После пройденного лабиринта из форм и запросов, когда всё уже установлено, начнём

При первом запуске нужно указать расположение ключа, его лучше поместить в директорию компилятора. После создания нажимаем F7, ошибок быть не должно. Если писать на чистых регистрах, то всё готово, но я такой хардкор не люблю, поэтому продолжим и добавим SPL библиотеку.

Распакуем куда-нибудь и заходим в папку STM8S_StdPeriph_LibProjectSTM8S_StdPeriph_Template. Тут у нас шаблон проекта stm8s_conf.h — это конфигурационный файл библиотеки, через него выбирается контроллер. Зайдём в main тут сразу с первых строк #include «stm8s.h» это ссылка на основную библиотеку, а так же кусок кода отладки который начинается с #ifdef USE_FULL_ASSERT , без отладочного кода будут сыпаться ошибки.

Теперь когда мы прошлись по верхам давайте пробовать запускать библиотеку. Добавляем в проект из шаблона main и конфигурационный файл в. В include files добавляем всё из STM8S_StdPeriph_LibLibrariesSTM8S_StdPeriph_Driverinc.

Теперь всё должно собраться.

Добавим stm8s_gpio.c и соберём простецкую мигалку. У меня один из светодиодов висит на D3, конфигурация ноги на выход выглядит так:

Её вписываем в main до бесконечного цикла.

А вот функция смены состояния. GPIO_WriteReverse(GPIOD, GPIO_PIN_3); вписываем её в бесконечный цикл.

Но вот незадача, в SPL нету функций задержки, скопипастим из примера GPIO в библиотеке. Там она выглядит следующим образом.

Впишем её в конец перед #ifdef USE_FULL_ASSERT. Так же впишем её прототип в начало, где под это выделено место в шаблонном main.

Ну и наконец впишем функцию со значением в бесконечный цикл после функции смены состояния: Delay(0xFFFF);

Подключаем ST-Link и прошиваем, для этого нажимаем Start Debugging и Run. Светодиод моргает значит всё хорошо.

Теперь посмотрим со стороны на эту среду.

По плюсам; у неё есть полноценная отладка, поддержка SPL из коробки. По минусам; она старая из этого вытекает, не очень приятный интерфейс и старый диалект си, на который многие свежие библиотеки придётся переписывать, в частности ставить переменные только вначале функций. Вес кода оставляет желать лучшего. Ну последний камень, этот инструмент может просто взять и вылететь, такое бывает, нечасто, но всё же.

Вторая среда, для тех кто не любит заморачиваться.

Второй подход — это свободный и обновляемый компилятор SDCC, а так же среда PlatformIO.

Для начала установим VS Code и станем рабами Microsoft, далее найдём расширение PlatformIO.

Ждём пока миллион ползунков пройдёт до конца и перезапускаем программу. Открываем расширение (может быть и само откроется). Создаём новый проект и выбираем ближайшую плату с stm8s (микроконтроллер можно будет изменить в конфигурационном файле). В качестве фреймворка выбираем SPL мы же не ардуинщики, нас интересует хардкор.

Не удивляйтесь, проект будет создаваться прилично долго, потому как он на ходу будет подгружать компилятор, библиотеки и тд. И вот перед нами возник девственно голый проект, закрываем его он нам больше не нужен. В меню где мы создавали проект, открываем пример spl-blink, суть в том что blink генерирует неплохой шаблон в котором можно сразу писать. Правим пример под себя и прошиваем, всё моргает.

Разберем поподробнее среду разработки. Во первых весь проект должен лежать в src, иначе среда ведёт себя неадекватно. Во вторых открываем stm8s_conf.h и видим что все библиотеки кроме GPIO закомментированы, если этого не сделать то у мк не хватит памяти что бы поместить весь SPL в микроконтроллер (помните в начале я говорил что он загружает все функции что видит в код?).

Выходит что тут мы должны будем ручкам включать и отключать библиотеки, а если пойти дальше в оптимизацию как я и сделал, то нужно будет каждую функцию включать и отключать. Часть конфигурационного файла у меня выглядит следующим образом:

Каждую функцию я включаю через макрос, для этого у меня переписана большая часть SPL. Если вам оптимизация сильно не нужна, то такой упоротостью можете не заниматься.

Пройдёмся по преимуществам: работает почти из коробки, полностью бесплатно без попрошайничества, редакции языка обновляются и не придётся учить и переписывать код под си 80-90г. Сам интерфейс настраиваемый и намного приятнее. Для тех кто не любит win есть linux версия.

По минусам: нету полноценной отладки (над ней активно работают, но пока ничего приближённого к cosmic я не видел), в проекте небольшой хаос, раскидать по папкам пока нельзя.

Послевкусие.

Ну и на последок есть ещё среды, варианты и компиляторы, но либо это тот же SDCC вкрученный силой в Eclipse или ещё куда и работающий хуже чем в VS Code, либо это платные варианты IAR, Raisonance. Я лично пользуюсь и тем и тем, но чаще VS Code. Рекомендовать ничего не буду каждому своё, увидимся в комментариях)

STM8S+SDCC+SPL: использование модуля UART1 на примере функции printf()

UART обладает двумя важными преимуществами перед остальными интерфейсами: во-первых, через TTL-конвертер его напрямую можно подключить к компьютеру, а во-вторых, линии связи между двумя узлами могут достигать 50 метров, что позволяет без проблем построить, к примеру, локальную сеть типа SmartHome. В STM8 скорость передачи через UART может достигать 1Mbit/s при частоте системной шины в 16MHz.

Микроконтроллеры STM8S могут обладать несколькими UART модулями,правда характеристики этих модулей немного разнятся:

Читайте также  Многоканальная охрана для удаленных объектов

Использование UART с помощью стандартной периферийной библиотеки(далее SPL), не сложнее, чем в AVR или даже Arduino. Библиотека, в папке Examples содержит готовые примеры использования UART, которые подробно прокомментированы. НО что бы не скатиться до потребительского отношения, бездумно используя чужой код, я предлагаю пошуршать немного мануалами, чтобы понять, чем же все-таки являются USART модули в STM8, и как ими пользоваться максимально эффективно.

Основные возможности UART1 в stm8s103f3:

LIN и CAN это локальные сети созданные для использования в автомобилестроении:

Так же имеется поддержка IrDA

Кроме этого имеется еще Smartcard

Как видно, вариантов использования UART много, но сейчас нас будет интересовать классический UART протокол: 8N1.

Регистры модуля UART1 в SPL описываются следующей структурой:

DR — регистр данных, BRRx — определяют скорость интерфейса, SR — флаговые/статусные регистры, CRх — управляющие режимами работы UART регистры, PSCR — позволяет понизить тактовую частоту UART модуля. Если к примеру, скорость передачи 9600 bod, то незачем модуль гонять вхолостую, можно поставить делитель на 64. GTR — Guard Time Register используется в Smartcard, задает величину защищенного интервала в тактах системной шины тактирования.

Функцией UART1_DeInit(), в регистры записываются следующие значения по умолчанию:

Функционал модуля UART1 реализуется следующими функциями:

Пример программы для пересылки данных с микроконтроллера на компьютер через UART:

Так же как в AVR, для использования функции printf() нужно только задать функцию putchar(char c), после чего системная библиотека сделает все за вас. Кстати, прошивка вместе с printf(), начинает весить уже от 5 Kбайт.

Результат работы выглядит как-то так:

я предлагаю заглянуть в код функции UART1_SendData8(c):

а так же UART1_GetFlagStatus(UART1_FLAG_TXE):

но самая интересная функция, это конечно UART1_Init():

И здесь кроется довольно массивный «подводный камень». Дело в следущем. Как помнится, в AVR была хитрая формула для преобразования скорости передачи в значение регистра UBRR. В STM8 имеется не менее хитрая формула для регистров BRRx:

своя табличка тоже наличествует:

Как не трудно заметить, функция прямо пропорциональна fMASTER. Значение fMASTER UART1_Init() берет из модуля CLK с помощью функции CLK_GetClock():

А сама CLK_GetClock() выглядит так:

Так вот. Если чип будет использовать внешний резонатор HSE, значение частоты резонатора будет браться из именованной константы HSE_VALUE в stm8s.h:

.т.е. если ваш кварц не на 16 МГц, и вы не вписали частоту кварца во время компиляции, или не поправили заголовочный файл stm8s.h, то работать корректно ваш модуль UART не будет. Такой вот тест на внимательность.

Разобравшись c BRRx, осталось пробежаться по управляющим регистрам UART1_CRx. Общая карта регистров для модуля UART1 в STM8S выглядит так:

UART1_Init() для конфигурации UART1 использует регистры: CR1, CR2, CR3.

В CR1 у нас устанвливается длина фрейма равной восьми(установкой бита 4 M), а также сбрасывается аппаратный контроль четности( биты 2 PCEN и бит 1 PS) . Для ясности напомню формат UART кадра:

  • Остальные биты:
  • Биты 7 и 6 отвечают за передачу кадром 9 бит. Если не ошибаюсь, такое используется в Multi-Processor communication когда локальную сеть строят на одном UART модуле. Тогда несколько бит используются для адресации устройства. Подробнее об этом можно почитать здесь: «Время говорить с камнями или USART Multi-processor Communication Mode» , сам я с этой штукой ни разу не сталкивался.
  • Бит 5 отключает тактирование от UART, в целях энергосбережения.
  • Бит 3 WAKE — определяет способ пробуждения из энергосберегающего режима. 0 — по освобожлению линии, 1 — по принятию адреса.
  • Бит 0 PIEN — разрешает/запрещает прерывание по четности. Прерывание генерируется когда устанавливается флаг PE в регистре UART1_SR.

Кстати, про прерывания. Прерывания UART могут вызывать следующие события:

Полезно будет эту табличку запомнить на будущее. А пока рассмотрим регистр UART_CR2:

Здесь нас интересуют биты 3 TEN и 2 REN, разрешение передачи и приема соответственно. В принципе, т.к. микроконтроллер работает только на передачу, можно было выставить только TEN, тогда пин Rx можно было бы использовать в других задачах.

Биты с седьмого по четвертый устанавливают источник вызова прерывания.

Бит RWU, определяет находится ли UART в «спящем» режиме или в активном. Как я понял из описания, UART можно вывести из режима сна, передачей специальной последовательности.

SBK — этот бит используется для отправки разрывающего стоп-бита. Устанавливается программно, сбрасывается аппаратно.

Здесь нас интересуют STOP биты 5:6, которые определяют количество стоп-битов: одни, два или полтора;

LINEN включает LIN режим;

  • Остальные биты настраивают вывод синхронизирующего тактового сигнала SCLK pin для работы USART в синхронном режиме.
  • CLKEN включает выдачу тактового сигнала для SCLK pin.
  • CPOL задает полярность SCLK pin;
  • CPHA задет фазу SCLK pin. Передача бита данных будет синхронизирована по первому фронту или по второму;
  • LBCL задет вывод последнего бита данных на SCLK pin. Т.к. USART передает фрейм младшим битом вперед, то последним битом будет соответственно старший 8-й или 9-й бит данных, в зависимости от формата фрейма.

Использование USART1 в чипе STM8L051F3 (добавлено 31 августа 2016г.)

В L-серии UART модули лишены LIN и CAN интерфейсов, в остальном же соответствуют USART модулям в STM8S.

Струтура писывающая модуль USART в SPL идентична структуре в S-серии, за тем исключением, что она общаяя для всех модулей:

Поэтому во всех функциях SPL имеется дополнительный параметр: USART_TypeDef* USARTx — номер модуля USART:

Пример использования printf() для STM8L051F3 выглядит следующим образом:

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

Результат работы выглядит аналогично примеру для S-серии.

Скачать архив с полными исходниками можно здесь: скачать

  • Все
  • Тематические

    GPIO (General Purpose Input-Output) — это выводы общего назначения, ноги микроконтроллера, доступные для прямого управления. Это обычно довольно дефицитный ресурс во многих популярных МК, но с STM32 эта проблема теряет актуальность: в самом мелком корпусе (LQFP48) доступно 37 GPIO, а в самом большом (LQFP176) — 140 GPIO. И всё это богатство ещё и настраивается вдоль и поперёк. Но, обо всём по порядку.

    Для начала откроем руководство по STM32F100xx и взглянем на схему вывода порта:

    Сами МК питаются 3.3 В, но до сих пор ещё активно используются 5-вольтовые микросхемы и логика, а их нужно как-то подключать. Поэтому в STM32 большинство выводов «толерантны» к 5 В — уж не знаю, как ещё перевести термин «5 V tolerant». То есть, они могут принимать на вход 5 В без какой-либо угрозы их здоровью.

    Толерантный пин отличается от обычного только тем, что у него верхний защитный диод подключён к Vdd_ft вместо Vdd. Из этой схемы становится понятно, что хоть выводы и толерантны к 5 В на вход, но вот выдавать 5 В на выход не могут — тут уже нужен транзистор. Если нужно получить логическую единичку, то это не проблема — 3.3 В вполне распознаются 5-вольтовой логикой как 1, но если нужно именно 5 В, то есть решение — режим Open-drain у GPIO.

    Всего у STM32F10x режимов GPIO имеется 8.

    Выход общего назначения:

    • Push-pull, стандартный выход: выставляешь 0 в выходном регистре — получаешь низкий уровень на выходе, выставляешь 1 — получаешь высокий.
    • Open-drain (открытый сток, аналог открытого коллектора): вывод подключен к стоку N-MOS полевика в то время, как P-MOS полевик заперт, что позволяет управлять нагрузкой с большим напряжением, чем Vdd (3.3 В). Кому там нужно 5 В на выход? Ниже я расскажу, как их получить.

    Выход с альтернативной функцией (для периферии типа SPI, UART):

    • Push-pull
    • Open-drain

    Вход:

    • Analog, аналоговый высокоимпендансный: подтягивающие резисторы и триггер Шмитта отключены. Используется при работе с АЦП.
    • Floating, обычный высокоимпендансный: подтягивающие резисторы отключены, триггер Шмитта включен.
    • Pull-up, вход с подтяжкой к питанию.
    • Pull-down, вход с прижатием у к «земле».

    Как водится, линии GPIO объединены в порты, в STM32 — по 16 линий, поэтому нумеруются они с 0 по 15: PA0, PA1… PA15 — это линии порта A, например. Линии порта управляются программно с помощью нескольких регистров.

    GPIOx_CRL и GPIOx_CRH — регистры конфигурации, содержат настройки режима (вход/выход) и частоты GPIO. Доступны на чтение и запись.

    GPIOx_IDR и GPIOx_ODR — входной и выходной регистры: в первом хранится считанное со входов порта значение, во второй записывается новое состояние выводов. GPIOx_IDR доступен только на чтение, а GPIOx_ODR — на чтение и запись.

    GPIOx_BSRR и GPIOx_BRR — регистры атомарного изменения битов в GPIOx_ODR.
    Обычно, если нужно установить бит в регистре периферии, то его сначала нужно прочитать, потом применить побитовое ‘ИЛИ’ к считанному значению и битовой маске, после чего записать новое значение назад в регистр. То же и со сбросом битов, только маску нужно инвертировать и применить побитовое ‘И’. А вот запись значений в GPIOx_BSRR и GPIOx_BRR изменяет только те биты выходного регистра, которые были установлены в единицу, притом происходит это за 1 такт, так что прерывание не сможет ворваться и всё испортить. Проиллюстрирую кодом:

    Оба регистра доступны только на запись.

    Всё это я рассказал для общего развития, а мы пока абстрагируемся от этих деталей, и будем всё делать через библиотеку SPL — с регистрами возится на данном этапе не резон.

    В структуре GPIO_InitTypeDef из SPL, которую мы использовали в предыдущем уроке для инициализации GPIO, за режим отвечает поле GPIO_Mode, а константы для его заполнения имеют следующие имена:

    • GPIO_Mode_Out_PP — выход push-pull
    • GPIO_Mode_Out_OD — выход open-drain
    • GPIO_Mode_AF_PP — альтернативная функция, push-pull
    • GPIO_Mode_AF_OD — альтернативная функция, open-drain
    • GPIO_Mode_AIN — аналоговый высокоимпендансный вход
    • GPIO_Mode_IN_FLOATING — высокоимпендансный
    • GPIO_Mode_IPU — вход с подтяжкой к питанию
    • GPIO_Mode_IPD — вход с прижатием к земле

    Подсмотреть это и многое другое можно в заголовочном файле stm32f10x_gpio.h, а в руководстве можно узреть ещё много интересного, включая детальные описания режимов и таблицу с описанием режимов GPIO для разной периферии — UART, SPI, I2C и др.

    Пример инициализации GPIO для модуля USART1 и самого модуля на STM32VLDiscovery :

    Что касается режима Open-drain, тут всё не так прямолинейно, как с другими режимами. Так как устройство, которым предполагается управлять, подключено к открытому стоку, нужно чуть более сложное соединение, чем обычно, а управление будет инверсное: выставляешь выход в 1 — ток с верхнего резистора идёт на землю, устройство видит на линии 0; выставляешь 0 — полевик запирается, ток идёт на устройство, на линии уровень 1.

    Разработчики STM32 также позаботились об энергопотреблении и о снижении уровня помех, предусмотрев настройку частоты: по сути, входной и в ыходной регистры GPIO тактируются от отдельного источника, что позволяет задать свою частоту каждой ножке МК. Для STM32F10x доступны 3 частоты, которые представлены константами:

    • GPIO_Speed_10MHz
    • GPIO_Speed_2MHz
    • GPIO_Speed_50MHz

    Разумеется, частота GPIO не должна превышать частоту ядра (:

    Ещё одна и интересная функция — переназначение выводов. Она позволяет переназначить выводы периферии с обычных на альтернативные, тоже фиксированные — впрочем, это не умаляет ценности данной функции: например, для USART1 можно переназначить TX с PA9 на PB6, а RX с PA10 на PB7. Если взглянуть на распиновку МК, можно увидеть, что обычные и альтернативные выводы находятся на разных сторонах кристалла, так что в разводке платы это в любом случае поможет:

    А включается переназначение вот так:

    Если вы два часа разводили двустороннюю плату, а потом обнаружили, что не можете развести какую-то сторону без огромной тучи переходов и перемычек, возможно, что функция переназначения выводов спасёт вашу клавиатуру от нелепой смерти под кулаком.

    Есть у GPIO и довольно диковинная функция — блокирование выводов. Я так и не понял, зачем она может понадобится, но суть такова: можно заблокировать изменение состояния любого GPIO до следующей перезагрузки МК. Активируется тоже несложно:

    Несколько слов об электрических характеристиках
    В даташите по STM32F100xx встречаются рекомендации подключать не более 20 выводов с отдачей 8 мА через каждый или не более 8 выводов с 20 мА, но практически нереально найти информацию по максимальному току на вывод. Но есть таблица, где приведена максимальная рассеиваемая мощность для МК целиком, причём для разных корпусов эта мощность разная. Например, для LQFP64, в котором идёт STM32F100RBT6B на STM32VLDiscovery, эта мощность равна 444 мВт, что при напряжении питания 3.3 В даёт силу тока

    134 мА. В другой таблице указано, что максимальный ток, потребляемый МК в режиме выполнения кода со всей включенной периферией при 100℃, составляет 15.7 мА. Итого имеем 134 — 15.7 = 118.3 мА на все выходы. Это максимальный ток, который может пропустить через себя МК, что немного расходится с рекомендациями. Впрочем, питать что-либо кроме светодиодов от MК в любом случае — плохая идея, а 118.3 мА хватит на пару-тройку десятков обычных светодиодов, которые при номинальном токе в 20 мА выжигают глаза, а при 1 мА вполне годятся в индикаторы.

    STM32F10x SPL: модуль GPIO

    Введение

    В следующих разделах статьи будет представлено описание функций модуля GPIO и описание структуры GPIO_InitTypeDef .

    Содержание

    • Обзор функций
    • Подробное описаний функций
    • Описание структуры GPIO_InitTypeDef

    Обзор функций

    В этом разделе, кликнув на имя функции, можно перейти к её подробному описанию.

    void GPIO_AFIODeInit(void)
    Сбрасывает в начальное состояние регистры альтернативных функций

    void GPIO_DeInit(GPIO_TypeDef *GPIOx)
    Сбрасывает в начальное состояние регистры GPIOx

    void GPIO_ETH_MediaInterfaceConfig(uint32_t GPIO_ETH_MediaInterface)
    Выбирает Ethernet media interface

    void GPIO_EventOutputCmd(FunctionalState NewState)
    Разрешает или запрещает событийный выход (Event Output)

    void GPIO_EventOutputConfig(uint8_t GPIO_PortSource, uint8_t GPIO_PinSource)
    Выбирает вывод для событийного выхода

    void GPIO_EXTILineConfig(uint8_t GPIO_PortSource, uint8_t GPIO_PinSource)
    Назначает вывод GPIO_PinSource порта GPIO_PortSource источником внешнего прерывания

    void GPIO_Init(GPIO_TypeDef *GPIOx, GPIO_InitTypeDef *GPIO_InitStruct)
    Настраивает порт GPIOx в соответствии с параметрами из структуры GPIO_InitStruct

    void GPIO_StructInit(GPIO_InitTypeDef *GPIO_InitStruct)
    Заполняет поля структуры GPIO_InitStruct значениями по умолчанию

    void GPIO_PinLockConfig(GPIO_TypeDef *GPIOx, uint16_t GPIO_Pin)
    Защищает настройки выводов

    void GPIO_PinRemapConfig(uint32_t GPIO_Remap, FunctionalState NewState)
    Разрешает или запрещает переназначение GPIO_Remap

    uint16_t GPIO_ReadInputData(GPIO_TypeDef *GPIOx)
    Возвращает входные данные порта GPIOx

    uint8_t GPIO_ReadInputDataBit(GPIO_TypeDef *GPIOx, uint16_t GPIO_Pin)
    Возвращает входное состояние вывода GPIO_Pin порта GPIOx

    uint16_t GPIO_ReadOutputData(GPIO_TypeDef *GPIOx)
    Возвращает выходные данные порта GPIOx

    uint8_t GPIO_ReadOutputDataBit(GPIO_TypeDef *GPIOx, uint16_t GPIO_Pin)
    Возвращает выходное состояние вывода GPIO_Pin порта GPIOx

    void GPIO_ResetBits(GPIO_TypeDef *GPIOx, uint16_t GPIO_Pin)
    Присваивает лог. 0 выходному состоянию выводов GPIO_Pin порта GPIOx

    void GPIO_SetBits(GPIO_TypeDef *GPIOx, uint16_t GPIO_Pin)
    Присваивает лог. 1 выходному состоянию выводов GPIO_Pin порта GPIOx

    void GPIO_Write(GPIO_TypeDef *GPIOx, uint16_t PortVal)
    Присваивает значение PortVal выходным данным порта GPIOx

    void GPIO_WriteBit(GPIO_TypeDef *GPIOx, uint16_t GPIO_Pin, BitAction BitVal)
    Присваивает значение BitVal выходному состоянию вывода GPIO_Pin порта GPIOx

    Подробное описание функций

    void GPIO_AFIODeInit(void)
    Сбрасывает в начальное состояние регистры альтернативных функций порта

    void GPIO_DeInit(GPIO_TypeDef *GPIOx)
    Сбрасывает в начальное состояние регистры порта GPIOx
    Аргументы:

    • GPIOx : Порт. Варианты значений:
      • GPIOx : где x = (A…G)

    void GPIO_ETH_MediaInterfaceConfig(uint32_t GPIO_ETH_MediaInterface)
    Выбирает Ethernet media interface
    Аргументы:

    • GPIO_ETH_MediaInterface : Media Interface. Варианты значений:
      • GPIO_ETH_MediaInterface_MII : Режим MII
      • GPIO_ETH_MediaInterface_RMII : Режим RMII

    void GPIO_EventOutputCmd(FunctionalState NewState)
    Разрешает или запрещает событийный выход (Event Output)
    Аргументы:

    • NewState : Новое состояние событийного выхода. Варианты значений:
      • ENABLE : разрешен
      • DISABLE : запрещен

    void GPIO_EventOutputConfig(uint8_t GPIO_PortSource, u8 GPIO_PinSource)
    Выбирает вывод для событийного выхода
    Аргументы:

    • GPIO_PortSource : Порт. Варианты значений:
      • GPIO_PortSourceGPIOx : где x = (A…E)
    • GPIO_PinSource : Вывод порта. Варианты значений:
      • GPIO_PinSourceX : где X = (0…15)

    void GPIO_EXTILineConfig(uint8_t GPIO_PortSource, u8 GPIO_PinSource)
    Назначает вывод GPIO_PinSource порта GPIO_PortSource источником внешнего прерывания
    Аргументы:

    • GPIO_PortSource : Порт. Варианты значений:
      • GPIO_PortSourceGPIOx : где x = (A…G)
    • GPIO_PinSource : Вывод порта и одновременно номер X внешнего прерывания. Варианты значений:
      • GPIO_PinSourceX : где X = (0…15)

    void GPIO_Init(GPIO_TypeDef *GPIOx, GPIO_InitTypeDef *GPIO_InitStruct)
    Настраивает порт GPIOx в соответствии с параметры из структуры GPIO_InitStruct
    Аргументы:

    • GPIOx : Порт. Варианты значений:
      • GPIOx : где х = (A…G)
    • GPIO_InitStruct : Структуру типа GPIO_InitTypeDef , содержащая настройки порта.

    void GPIO_PinLockConfig(GPIO_TypeDef *GPIOx, uint16_t GPIO_Pin)
    Защищает настройки выводов
    Аргументы:

    • GPIOx : Порт. Варианты значений:
      • GPIOx : где х = (A…G)
    • GPIO_Pin : Выводы, одно значение или их комбинация (с помощью оператора или |):
      • GPIO_Pin_x : где x = (0…15)

    void GPIO_PinRemapConfig(uint32_t GPIO_Remap, FunctionalState NewState)
    Разрешает или запрещает переназначение GPIO_Remap
    Аргументы:

    • NewState : Состояние переназначения. Значения аргумента:
      • ENABLE : Разрешение
      • DISABLE : Запрет
    • GPIO_Remap : Переназначение. Значения аргумента:
      • GPIO_Remap_PPP , где PPP :
        • SPI1
        • SPI3
        • I2C1
        • USART1
        • USART2
        • USART3
        • PD01
        • TIM5CH4_LSI
        • ADC1_ETRGINJ
        • ADC1_ETRGREG
        • ADC2_ETRGINJ
        • ADC2_ETRGREG
        • ETH
        • CAN2
        • SWJ_NoJTRST
        • SWJ_JTAGDisable
        • SWJ_Disable
        • TIM2ITR1_PTP_SOF
        • PTP_PPS
        • CEC
        • TIM1_DMA
        • TIM4
        • TIM9
        • TIM10
        • TIM11
        • TIM13
        • TIM14
        • TIM15
        • TIM16
        • TIM17
        • FSMC_NADV
        • TIM67_DAC_DMA
        • TIM12 , MISC
      • GPIO_FullRemap_PPP , где PPP :
        • USART3
        • TIM1
        • TIM2
        • TIM3
      • GPIO_PartialRemap_PPP , где PPP :
        • TIM1
        • TIM3
      • GPIO_PartialRemap1_PPP , где PPP :
        • TIM2
        • CAN1
      • GPIO_PartialRemap2_PPP , где PPP :
        • TIM2
        • CAN1

    uint16_t GPIO_ReadInputData(GPIO_TypeDef *GPIOx)
    Возвращает входные данные порта GPIOx
    Аргументы:

    • GPIOx : Порт. Варианты значений:
      • GPIOx : где х = (A…G)

    uint8_t GPIO_ReadInputDataBit(GPIO_TypeDef *GPIOx, uint16_t GPIO_Pin)
    Возвращает входное состояние вывода GPIO_Pin порта GPIOx
    Аргументы:

    • GPIOx : Порт. Варианты значений:
      • GPIOx : где х = (A…G)
    • GPIO_Pin : Вывод порта. Значение:
      • GPIO_Pin_x : где x = (0…15)

    Возвращаемое значение: входное состояние вывода, (uint8_t)Bit_SET или (uint8_t)Bit_RESET .

    u16 GPIO_ReadOutputData(GPIO_TypeDef *GPIOx)
    Возвращает выходные данные порта GPIOx
    Аргументы:

    • GPIOx : Порт. Варианты значений:
      • GPIOx : где х = (A…G)

    Возвращаемое значение: выходные данные порта GPIOx .

    uint8_t GPIO_ReadOutputDataBit(GPIO_TypeDef *GPIOx, uint16_t GPIO_Pin)
    Возвращает выходное состояние вывода GPIO_Pin порта GPIOx
    Аргументы:

    • GPIOx : Порт. Варианты значений:
      • GPIOx : где х = (A…G)
    • GPIO_Pin : Вывод порта. Варианты значений:
      • GPIO_Pin_x : где x = (0…15)

    Возвращаемое значение: выходное состояние вывода, (uint8_t)Bit_SET или (uint8_t)Bit_RESET .

    void GPIO_ResetBits(GPIO_TypeDef *GPIOx, uint16_t GPIO_Pin)
    Присваивает лог. 0 выходному состоянию выводов GPIO_Pin порта GPIOx
    Аргументы:

    • GPIOx : Порт. Варианты значений:
      • GPIOx : где х = (A…G)
    • GPIO_Pin : Выводы, одно значение или их комбинация (с помощью оператора или |):
      • GPIO_Pin_x : где x = (0…15)

    void GPIO_SetBits(GPIO_TypeDef *GPIOx, uint16_t GPIO_Pin)
    Присваивает лог. 1 выходному состоянию выводов GPIO_Pin порта GPIOx
    Аргументы:

    • GPIOx : Порт. Варианты значений:
      • GPIOx : где х = (A…G)
    • GPIO_Pin : Выводы, одно значение или их комбинация (с помощью оператора или |):
      • GPIO_Pin_x : где x = (0…15)

    void GPIO_StructInit(GPIO_InitTypeDef *GPIO_InitStruct)
    Заполняет поля структуры GPIO_InitStruct значениями по-умолчанию:

    При вызове функции GPIO_Init() и передачи ей указателя на структуру, заполненную по-умолчанию, все выводы порта GPIOx , настроятся в режим плавающего входа с максимальной частотой 2 МГц.
    Аргументы:

    • GPIO_InitStruct : Структура типа GPIO_InitTypeDef , содержащая настройки порта

    void GPIO_Write(GPIO_TypeDef *GPIOx, uint16_t PortVal)
    Присваивает значение PortVal выходным данным порта GPIOx
    Аргументы:

    • GPIOx : Порт. Варианты значений:
      • GPIOx : где х = (A…G)
    • PortVal: Значение, записываемое в выходной регистр порта GPIOx

    void GPIO_WriteBit(GPIO_TypeDef *GPIOx, uint16_t GPIO_Pin, BitAction BitVal)
    Присваивает значение BitVal выходному состоянию вывода GPIO_Pin порта GPIOx
    Аргументы:

    • GPIOx : Порт. Варианты значений:
      • GPIOx : где х = (A…G)
    • GPIO_Pin : Вывод. Варианты значений:
      • GPIO_Pin_x : где x = (0…15)
    • BitVal : Значение, присваиваемое биту GPIO_Pin выходного регистра порта GPIOx . Варианты значений:
      • Bit_RESET : логический 0
      • Bit_SET : логическая 1

    Описание структуры GPIO_InitTypeDef

    GPIO_InitTypeDef — тип структуры данных для настройки выводов портов. Для настройки выводов порта необходимо вызвать функцию GPIO_Init() , передав ей указатель на переменную типа GPIO_InitTypeDef . На практике настройка выводов выглядит так:

    • GPIOMode_TypeDef GPIO_Mode : Режим работы порта. Варианты значений:
      • GPIO_Mode_AIN : Аналоговый вход
      • GPIO_Mode_IN_FLOATING : Плавающий вход
      • GPIO_Mode_IPD : Вход с подтяжкой к земле
      • GPIO_Mode_IPU : Вход с подтяжкой к питанию
      • GPIO_Mode_Out_OD : Выход с открытым стоком
      • GPIO_Mode_Out_PP : Двухтактный выход
      • GPIO_Mode_AF_OD : Альтернативный выход с открытым стоком
      • GPIO_Mode_AF_PP : Альтернативный двухтактный выход
    • uint16_t GPIO_Pin : Выводы порта. Поле может принимать одно из значений или их комбинацию (с помощью оператора или |):
      • GPIO_Pin_x : Вывод x, где x = (0…15)
      • GPIO_Pin_All : все выводы
    • GPIOSpeed_TypeDef GPIO_Speed : Максимальная частота выходного сигнала. Варианты значений:
      • GPIO_Speed_2MHz : 2 МГц
      • GPIO_Speed_10MHz : 10 МГц
      • GPIO_Speed_50MHz : 50 МГц