Урок 3

Сегодня мы с вами продолжим работу с библиотекой 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_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);
>

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

Вообщем, научились мы управлять ножками портов на выход. Теперь попробуем отследить состояние порта, которое будет зависеть от подключенной на плате синей кноки. Данная кнопка подключена к ножке 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);
>

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

Добрый день. Решил написать ещё одну статейку по 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…
Я в самом начале документа нашёл вот такую интересную информацию

Список статей который поможет изучить микроконтроллер STM32 даже начинающему. Подробно обо всем с примерами начиная от мигания светодиодом до управления бесколлекторным двигателем. В примерах используется стандартная библиотека SPL (Standard Peripheral Library).

1. STM32. Программирование STM32F103. Тестовая плата. Прошивка через последовательный порт и через ST-Link программатор

Тестовая плата STM32F103, ST-Link программатор, и программное обеспечение для прошивки под Windows и Ubuntu.

2. STM32. Программирование. IDE для STM32

Установка и настройка IDE CooCox для разработки программ для микроконтроллеров STM32

Keil uVision5 – IDE для STM32

Установка и настройка Keil uVision5

IAR Workbench – IDE для STM32

Установка и настройка IAR Workbench

3. STM32. Программирование STM32F103. GPIO

Работа с GPIO выводами микроконтроллера. Вход / выход

4. STM32. Программирование STM32F103. Тактирование

Схема тактирования STM32. Настройка тактирования микроконтроллера и периферии.

5. STM32. Программирование STM32F103. USART

Использование последовательного порта USART. Прием и передача данных, обработка команд.

6. STM32. Программирование STM32F103. NVIC

VIC (Nested vectored interrupt controller) – модуль контроля прерываний. Настройка и использование прерываний. Приоритеты прерываний. Вложенные прерывания.

7. STM32. Программирование STM32F103. ADC

АЦП (аналого-цифровой преобразователь). Схема питания и примеры использования АЦП в различных режимах. Regular и Injected каналы. Использование АЦП вместе с DMA. Внутренний термометр. Аналоговый watchdog.

8. STM32. Программирование STM32F103. DMA

DMA (Direct Memory Access) контроллер прямого доступа к памяти. Пример USART через DMA.

9. STM32. Программирование STM32F103. TIMER

Таймеры общего назначения. Генерирование прерывания через равные промежутки времени. Измерение времени между двумя событиями.

10. STM32. Программирование STM32F103. TIMER. Захват сигнала

Захвата сигнала таймером на примере работы с ультразвуковым датчиком HC-SR04

11. STM32. Программирование STM32F103. TIMER. Encoder

Использование таймера для работы с энкодером.

12. STM32. Программирование STM32F103. TIMER. PWM

Генерация ШИМ. Управление яркостью светодиода. Управление сервоприводом (сервомашинками). Генерация звука.

13. STM32. Программирование STM32F103. EXTI

Внешние прерывания. Interrupt / Event.

14. STM32. Программирование STM32F103. RTC

Часы реального времени (RTC). Battery backup domain.

15. STM32. Программирование STM32F103. BKP

Backup registers (BKP). Использование BKP регистров для хранения данных.

16. STM32. Программирование STM32F103. Flash

Работа с Flash памятью. Пример хранения настроек.

17. STM32. Программирование STM32F103. Watchdog

IWDG – Independent Watchdog и WWDG – Window Watchdog. Примеры использования Watchdog.

18. STM32. Программирование STM32F103. Remap

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

19. STM32. Программирование STM32F103. I2C Master

Использование шины I 2 C (IIC) (TWI) на примере работы с датчиком атмосферного давления BMP280

20. STM32. Программирование STM32F103. I2C Slave

Микроконтроллер в качестве IIC устройства (Slave).

21. STM32. Программирование STM32F103. USB

Библиотека STM32 USB FS Device Lib. Виртуальный последовательный порт. Эмуляция клавиатуры и мышки. USB Mass Srorage.

22. STM32. Программирование STM32F103. PWR

Схема питания. Домены питания. Режимы пониженного энергопотребления Sleep, Stop, Standby. Выход из режима пониженного энергопотребления с помощью RTC.

23. STM32. Программирование STM32F103. Option bytes

Option bytes, защита прошивки от чтения / записи.

24. STM32. Программирование STM32F103. Bootloader

Собственный Bootloader. Bootloader в режиме USB Mass Storage.

STM32 – BLDC Motor Control

Управление бесколлекторным двигателем постоянного тока (BLDC) с помощью STM32. Демонстрация возможностей таймеру TIM1 (advanced-control timer)

STM32 – PMSM Control

Управление PMSM с помощью STM32. Демонстрация возможностей таймеру TIM1 (advanced-control timer)

STM32. Скачать ВСЕ примеры