Начинаем изучать STM32: Что такое регистры? Как с ними работать?
В предыдущем уроке мы рассмотрели работу с битовыми операциями и двоичными числами, тем самым заложив основу для рассмотрения новой темы. В этом уроке мы с Вами рассмотрим очередной вопрос: что такое регистры и как с ними работать?

- Начинаем изучать STM32 или Управляем светом по-умному
- Начинаем изучать STM32: битовые операции
- Начинаем изучать STM32: Что такое регистры? Как с ними работать?
Память и регистры
Одним из самых важных навыков необходимых при работе с микроконтроллерами является умение взаимодействовать с регистрами. Давайте для себя разберемся, что же это такое?
В целом, регистр — это особый вид памяти внутри микроконтроллера, который используется для управления процессором и периферийными устройствами. Каждый регистр в архитектуре ARM представляет собой ячейку памяти и имеет длину в 32 бита, где каждый бит можно представить в виде крошечного выключателя с помощью которого осуществляется управление тем или иным параметром микроконтроллера.
Каждый из регистров имеет свой порядковый номер – адрес. Адрес регистра обозначается 32-битным числом представленным в шестнадцатеричной системе счисления. Путём записи по адресу регистра определённой комбинации единиц и нулей, которые обычно представлены в шестнадцатеричном виде, осуществляется настройка и управление тем или иным узлом в МК. Вспомним, что в программе для работы с битовыми операциями, мы могли представить в виде шестнадцатеричного числа произвольный набор единиц и нулей. В целом стоит отметить, что существует два вида регистров: регистры общего назначения и специальные регистры. Первые расположены внутри ядра МК, а вторые являются частью RAM-памяти.
Так же стоит отметить, что Reference Manual, который мы скачивали в первом уроке, это один большой справочник по регистрам, содержащимся в целевом микроконтроллере, а библиотека CMSIS позволяет нам оперировать символьными именами регистров вместо числовых адресов. Например, к регистру 0x40011018 мы можем обратиться просто, используя символьное имя GPIOC_BSSR. Конкретные примеры конфигурирования мы рассмотрим в ходе разбора нашей программы из первого занятия.
Итак, обычно структура регистра описывается в виде небольшой таблицы с указанием:
- Названия регистра и описания его назначения
- Адреса регистра или смещением относительно базового адреса
- Значения по умолчанию после сброса
- Типа доступа к ячейкам регистра (чтение, запись, чтение/запись)
- Значения и описания параметров записываемых битов
Разбор кода из первого занятия
Итак, давайте вспомним задачу, которую мы решили на первом уроке используя готовый код примера: нам было необходимо написать программу, которая бы обеспечила попеременное включение двух светодиодов на плате Discovery (возможно и не двух, если у вас другая версия платы Discovery) с временным интервалом.
Давайте еще разок взглянем на код программы, которую мы использовали для того, чтобы заставить наш МК дрыгать двумя ногами на которых расположены наши светодиоды:
Код main.c
/* Заголовочный файл для нашего семейства микроконтроллеров*/ #include "stm32f0xx.h" /* Тело основной программы */ int main(void) < /* Включаем тактирование на порту GPIO */ RCC->AHBENR |= RCC_AHBENR_GPIOCEN; /* Настраиваем режим работы портов PC8 и PC9 в Output*/ GPIOC ->MODER = 0x50000; /* Настраиваем Output type в режим Push-Pull */ GPIOC->OTYPER = 0; /* Настраиваем скорость работы порта в Low */ GPIOC->OSPEEDR = 0; while(1) < /* Зажигаем светодиод PC8, гасим PC9 */ GPIOC->ODR = 0x100; for (int i=0; i // Искусственная задержка /* Зажигаем светодиод PC9, гасим PC8 */ GPIOC->ODR = 0x200; for (int i=0; i // Искусственная задержка > >
Первым делом, при работе с STM32, даже для такой простой задачи как включение и выключение светодиода нам необходимо предварительно ответить на ряд вопросов:
- Куда подключены наши светодиоды? К какому выводу микроконтроллера?
- Как включить тактирование на нужный порт GPIO?
- Как настроить, нужные нам, пины порта GPIO для того чтобы можно было включить светодиод?
- Как включить и выключить светодиод?
Куда подключены наши светодиоды? К какому выводу микроконтроллера?
Для того, чтобы посмотреть где что находится на плате Discovery, а в частности, нужные нам светодиоды — нужно открыть Schematic-файл, либо тот который мы скачали с сайта ST, либо прямо из Keil:

Открыв Schematic мы увидим схему всего того, что есть на плате — схему ST-Link, обвязку всей периферии и многое другое. На текущий момент нас интересуют два светодиода, ищем их обозначение:

Как мы видим, наши светодиоды подключены к порту GPIOC на 8 и 9 пин.
Как включить тактирование на нужный порт GPIO?
В целом, любая работа с периферией в микроконтроллерах STM32 сводится к стандартной последовательности действий:
- Включение тактирования соответствующего периферийного модуля. Осуществляется это через регистр RCC путем подачи тактового сигнала напрямую с шины на которой находится данный модуль. По умолчанию тактирование всей периферии отключено для минимизации энергопотребления.
- Настройка через управляющие регистры, путем изменения параметров специфичных для конкретного периферийного устройства
- Непосредственный запуск и использование результатов работы модуля
Внимание! Вопрос касательно системы тактирования, её настройки и использования мы подробно рассмотрим в отдельной статье.
Найти к какой шине подключен наш порт GPIOC можно найти в Datasheet’е на наш МК в разделе Memory Mapping в Таблице 16. STM32F051xx peripheral register boundary addresses.

Как вы уже успели заметить, необходимая нам шина именуется как AHB2. Для того чтобы подробнее ознакомиться с регистром, в котором включается тактирование на нужный нам порт GPIO на шине AHB, надо перейти в соответствующий раздел в Reference Manual. По названию регистров мы можем определить тот, который нужен нам:

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

Смотрим на таблицу и видим нечто напоминающее опции включения тактирования на портах GPIO. Переходим к описанию и находим нужную нам опцию:

Соответственно если мы установим 19 бит в значение «1» то это обеспечит включение тактирования на порт I/O C – то есть на наш GPIOC. К тому же — нам нужно включить отдельно один бит из группы, не затрагивая остальные т.к. мы не должны мешать и изменять без надобности другие настройки.
Основываясь на материалах прошлого урока, мы знаем что для того чтобы выставить определенный бит нужно используя логическую операцию «ИЛИ» сложить текущее значение регистра с маской которая содержит те биты которые необходимо включить. Например, сложим значение регистра RCC->AHBENR по умолчанию, т.е. 0x14 и число 0x80000 тем самым включим тактирование GPIOC путем установки 19 бита:

Каким образом мы можем это сделать из программы? Всё достаточно просто. В данном случае у нас два варианта:
- Запись в регистр напрямую численного значения регистра напрямую через его адрес.
- Настройка с использованием библиотеки CMSIS
То есть, мы могли бы обращаться к адресам регистров напрямую по адресу и написать так:
__IO uint32_t * register_address = (uint32_t *) 0x40021014U; // Адрес нашего регистра в памяти *(__IO uint32_t *)register_address |= 0x80000; // Включаем 19 бит с нашим параметром
Второй вариант мне кажется наиболее привлекательным, т.к. библиотека CMSIS организована таким способом, что регистру можно обращаться, используя только его название. Препроцессор в ходе обработки текста программы перед компиляцией подставит все цифровые значения адреса регистра автоматически. Давайте разберем этот вопрос чуть подробнее.
Предлагаю открыть наш проект, который мы сделали в первом занятии, или скачайте предварительно подготовленый отсюда и удалите все содержимое программы оставив только подключенный заголовочный файл, функцию main() и инструкцию для включения тактирования (она нам понадобится для подробного разбора кода).
Наш код будет выглядеть следующим образом:
/* Заголовочный файл для нашего семейства микроконтроллеров*/ #include "stm32f0xx.h" /* Тело основной программы */ int main(void) < /* Включаем тактирование на порту GPIO */ RCC->AHBENR|=RCC_AHBENR_GPIOCEN; >
Давайте для ознакомления копнём вглубь библиотеки CMSIS.
Для того, чтобы быстро перейти к месту где объявлена та или иная константа или переменная в Keil реализована удобная функция. Кликаем правой кнопкой по необходимой нам константе, например, на RCC:

И мы переносимся в глубины библиотеки CMSIS, в которой увидим, что все регистры доступные для управления программным способом имеют вид TypeDef-структур, в том числе и наш RCC:

Провалившись подобным образом в RCC_TypeDef мы увидим структуру в которой описаны все поля нашего регистра:

Соответственно, мы можем спокойно обращаться к нужному нам регистру записью вида PERIPH_MODULE->REGISTER и присваивать ему определенное значение.
Помимо мнемонического обозначения регистров есть так же обозначения конкретных битов. Если мы провалимся к объявлению параметра RCC_AHBENR_GPIOCEN из нашей программы, то так же увидим объявление всех параметров:

Таким образом, используя библиотеку CMSIS у нас получается лаконичная читаемая запись нужного нам параметра в регистр, через установку которого мы запускаем тактирование на нужный нам порт:
/* Включаем тактирование на порту GPIO */ RCC->AHBENR|=RCC_AHBENR_GPIOCEN;
В качестве задания: определите используя возможности Keil, каким образом получился адрес регистра RCC->AHBENR как 0x40021014.
Как настроить нужные нам пины GPIO для того чтобы можно было включить светодиод?
Итак, мы знаем что нужные нам светодиоды подключены к порту GPIOC к пинам PC8 и PC9. Нам нужно настроить их в такой режим, чтобы загорался светодиод. Хотелось бы сразу же сделать оговорку, что порты GPIO мы рассмотрим подробнее в другой статье и тут мы сконцентрируемся именно на работе с регистрами.
Первым делом нам нужно перевести режим работы пинов PC8 и PC9 в режим Output. Остальные параметры порта можно оставить по умолчанию. Переходим в Reference Manual в раздел 9. General-purpose I/Os (GPIO) и открываем пункт отвечающий за режим работы пинов порта GPIO и видим что за этот параметр отвечает регистр MODER:

Судя по описанию, для установки пинов PC8 и PC9 в режим Output мы должны записать 01 в соответствующие поля регистра GPIOC.
Это можно сделать через прямую установку с помощью числовых значений:
-
Формируем число для записи:

/* Настраиваем режим работы портов PC8 и PC9 в Output*/ GPIOC->MODER |= 0x50000;
/* Включаем тактирование на порту GPIO */ GPIOC->MODER |= GPIO_MODER_MODER8_0 | GPIO_MODER_MODER9_0;
После данной инструкции наши пины PC8 и PC9 перейдут в режим Output.
Как включить светодиод?
Если мы обратим внимание на список доступных регистров для управления портом GPIO то можем увидеть регистр ODR:

Каждый из соответствующих битов отвечает за один из пинов порта. Его структуру вы можете увидеть ниже:

Для того, чтобы обеспечить попеременную смену состояний светодиодов надо с определенным временным интервалом включать/выключать 8 и 9 биты. То есть попеременно присваивать регистру значение 0x100 и 0x200.
Сделать это мы можем через прямое присвоение значений регистру:
GPIOC->ODR = 0x100; // Зажигаем PC8, гасим PC9 GPIOC->ODR = 0x200; // Зажигаем PC9, гасим PC8
Можем через использование определений из библиотеки:
GPIOC->ODR = GPIO_ODR_8; // Зажигаем PC8, гасим PC9 GPIOC->ODR = GPIO_ODR_9; // Зажигаем PC9, гасим PC8
Но так как микроконтроллер работает очень быстро — мы не будем замечать смены состояний светодиодов и визуально будет казаться что они оба горят постоянно. Для того чтобы они действительно моргали попеременно мы внесем искусственную задержку в виде цикла который займет МК бесполезными вычислениями на некоторое время. Получится следующий код:
/* Зажигаем светодиод PC8, гасим PC9 */ GPIOC->ODR = GPIO_ODR_8; for (int i=0; i // Искусственная задержка /* Зажигаем светодиод PC9, гасим PC8 */ GPIOC->ODR = GPIO_ODR_9; for (int i=0; i // Искусственная задержка
На этом первоначальное знакомство с регистрами и методами работы с ними мы можем закончить.
Проверка результатов работы нашего кода
Небольшое приятное дополнение в конце статьи: в Keil имеется отличный Debug-инструмент с помощью которого мы можем пошагово выполнить нашу программу и просмотреть текущее состояние любого периферийного блока. Для этого после загрузки прошивки после компиляции мы можем нажать кнопку Start Debug Session:

Рабочая среда Keil переключится в режим отладки. Мы можем управлять ходом программы с помощью данных кнопок:

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

Если вы кликните по одному из пунктов данного меню, вы увидите адрес регистра и его краткое описание. Так же можно просмотреть описание к каждому отдельному параметру регистра:

Попробуйте самостоятельно пошагово выполнить программу, включить/выключить светодиоды не используя программу, а используя данный режим работы с микроконтроллером. Простор для фантазии тут обширный. Так же попробуйте поиграться с длительностями задержек, сделайте одновременное моргание обоими светодиодами. В общем экспериментируйте! )
- Начинаем изучать STM32 или Управляем светом по-умному
- Начинаем изучать STM32: битовые операции
- Начинаем изучать STM32: Что такое регистры? Как с ними работать?
Урок 14. Создание и использование библиотек для STM32. Библиотека Debounce.

В уроке научимся создавать пользовательские библиотеки на примере класса Debounce. Также я расскажу, как применять в проекте готовые библиотеки.
В предыдущем уроке мы разработали класс Debounce для обработки дискретных сигналов. С помощью него можно устранять дребезг контактов, фильтровать сигнал, ослаблять влияние электромагнитных помех и т.п.
Класс отлажен, проверен, закончен. Но использовать его в других программах достаточно неудобно. Главная проблема – необходимо копировать исходный код класса в новую программу. При этом можно ошибиться и долго отлаживать давно проверенный и забытый код. Ну и, конечно, ненужный код будет загромождать текст программы, ухудшать читаемость.
Выход очевиден – оформить класс библиотекой. Давайте этим и займемся.
Последовательность действий для создания библиотеки STM32.
Библиотека, по крайней мере, на нашем уровне программирования, это тот же класс, только размещенный в других файлах. В текст программы файлы библиотеки включаются директивой препроцессора #include . Таким образом, текст библиотеки в нашей программе мы не видим. А на этапе компиляции он “подсовывается” компилятору директивой #include . И благополучно транслируется вместе с остальным исходным кодом.
Я скопировал проект предыдущего урока Lesson13_1 в новую папку Lesson14.
Переименовал его в Lesson14_1.
Открыл в Atollic TrueStudio и переименовал его в IDE еще раз. Все это мы уже делали.

Получился проект с классом Debounce из предыдущего урока. Этот класс мы будем оформлять библиотекой.
Библиотека состоит как минимум из двух файлов:
- заголовочного файла, с расширением .h ;
- файла исходного текста, расширение .cpp.
Заголовочный файл должен содержать описание класса, объявление переменных, константы. Программный код в нем не размещают.
Второй файл (.cpp) содержит код методов класса.
Давайте создадим файлы библиотеки. Чтобы в структуре проекта не было путаницы, создадим для всех пользовательских библиотек папку Libraries. А в ней папку Debounce, уже для нашей библиотеки.
Правой кнопкой мыши нажимаем на имя проекта, New -> Folder.

Задаем имя папки Libraries.
Теперь нажимаем на Libraries, New -> Folder.
Создаем папку Debounce.
Теперь выбираем папку Debounce, New -> File.
Создаем в ней файлы Debounce.h и Debounce.cpp.

Заголовочный файл Debounce.h.
Неплохо в начале файла поместить краткую информацию о библиотеке. У кого, на что хватит фантазии. Естественно, надо оформить этот блок комментариями.
/*
* Debounce.h — библиотека обработки дискретных сигналов STM32.
*
* Может быть использована для устранения дребезга контактов, цифровой фильтрации сигналов от помех.
*
* Работает в фоновом режиме.
*
* В параллельном процессе регулярно должен вызываться один из методов обработки:
*
* void scanStability(void); // метод ожидания стабильного состояния сигнала
* void scanAverage(void); // метод фильтрации сигнала по среднему значению
*
* В результате формируются признаки состояния сигнала:
*
* uint8_t flagLow; // признак СИГНАЛ В НИЗКОМ УРОВНЕ
* uint8_t flagRising; // признак БЫЛ ПОЛОЖИТЕЛЬНЫЙ ФРОНТ
* uint8_t flagFalling; // признак БЫЛ ОТРИЦАТЕЛЬНЫЙ ФРОНТ
*
* Признаки могут быть прочитаны функциями:
*
* uint8_t readFlagLow(void); // чтение признака СИГНАЛ В НИЗКОМ УРОВНЕ
* uint8_t readFlagRising(void); // чтение признака БЫЛ ПОЛОЖИТЕЛЬНЫЙ ФРОНТ
* uint8_t readFlagFalling(void); // чтение признака БЫЛ ОТРИЦАТЕЛЬНЫЙ ФРОНТ
*
* Пример создания объекта:
* Debounce button(GPIOC, 1
*
* Подробно описана http://mypractic.ru/uroki-stm32 в уроках 12, 13, 14
*
* Разработана Калининым Эдуардом.
*
* http://mypractic.ru
*/
Дальше следует объявление класса, которое надо заключить в конструкцию.
/* Проверка, что библиотека не подключена */
#ifndef DEBOUNCE_H
#define DEBOUNCE_H
#endif /* DEBOUNCE_H */
Это предотвратит повторное подключение библиотеки.
И еще необходимо подключить файл stm32f103xb.h. В нем содержатся CMSIS-имена регистров.
/* Проверка, что библиотека не подключена */
#ifndef DEBOUNCE_H
#define DEBOUNCE_H
#include «stm32f103xb.h»
class Debounce
#endif /* DEBOUNCE_H */
В файл Debounce.cpp мы копируем код методов. И в самом начале подключаем заголовочный файл. В нем содержится определение класса.
#include «Debounce.h»
Все библиотека создана. Теперь необходимо подключить ее.
Прежде всего, удаляем из main.cpp все то, что мы переместили в библиотечные файлы. А именно: объявление класса и код методов.
Подключаем нашу библиотеку.
#include «../Libraries/Debounce/Debounce.h»
Мы указали полный путь к папке библиотеки.
Можно написать короче:
#include «Debounce.h»
Но тогда путь к папке необходимо сообщить компилятору:
Project -> Build Settings -> Tool Settings -> C++ Compiler -> Directories -> Add (зеленый плюсик сверху).

В списке появится путь к нашей библиотеке
../Inc
../Libraries/Debounce
../Drivers/STM32F1xx_HAL_Driver/Inc
../Drivers/STM32F1xx_HAL_Driver/Inc/Legacy
../Drivers/CMSIS/Device/ST/STM32F1xx/Include
../Drivers/CMSIS/Include
Еще вариант той же операции:
Правой кнопкой мыши нажимаем на папку Debounce в проекте, Add/Remove Include Path -> OK
В списке путей для include появится
Транслируем проект. Получаем сообщения об ошибках компиляции.

Компилятор не нашел коды для методов класса. Мы не сообщили ему, где находится файл Debounce.cpp.
Можно поместить этот файл в папку Src. Компилятор привык там искать исходные тексты. Но мы не будем ломать стройности проекта.
Сделаем так: Project -> Build Settings -> C/C++ General -> Paths and Symbols -> Source Location -> Add Folder -> Libraries -> OK

Другой способ, немного проще:
Правой кнопкой по Libraries, Properties -> C/C++ General -> Paths and Symbols -> Source Location -> Add Folder -> Apply
Свершилось. Теперь компилируется без ошибок.
Вот ссылка на полный проект:
Зарегистрируйтесь и оплатите . Всего 60 руб. в месяц за доступ ко всем ресурсам сайта!
Применение библиотеки.
Давайте в этом разделе научимся использовать готовые библиотеки. Повторим часть действий из первой половины урока.
Нам надо реализовать задачу – на каждое нажатие кнопки светодиод меняет свое состояние.
Мы собираемся воспользоваться готовой библиотекой Debounce.
Загружаем ее архив.
Зарегистрируйтесь и оплатите . Всего 60 руб. в месяц за доступ ко всем ресурсам сайта!
В нем 2 файла в папке Debounce.
С помощью STM32CubeMX создаем проект Lesson14_2.
- Устанавливаем конфигурацию системы тактирования.
- Вывод PB13 конфигурируем на активный выход.
- Вывод PB12 (кнопка) не трогаем.
Конвертируем проект в C++.
Создаем папку Libraries и копируем в нее папку Debounce с файлами библиотеки.
Задаем в IDE путь к библиотеке. Правой кнопкой по Libraries, Properties -> C/C++ General -> Paths and Symbols -> Source Location -> Add Folder -> Apply
Подключаем библиотеку Debounce.
#include «../Libraries/Debounce/Debounce.h»
Создаем объект button.
Лучше запустить компиляцию, убедиться, что ошибок нет.
Теперь мы можем использовать объект button.
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
if(button.readFlagFalling() != 0)
HAL_GPIO_TogglePin(GPIOB, GPIO_PIN_13);
Все. Компилируем, загружаем в плату, проверяем.
Вот ссылка на проект:
Зарегистрируйтесь и оплатите . Всего 60 руб. в месяц за доступ ко всем ресурсам сайта!
Папку Libraries со своим библиотеками удобно копировать в проект целиком, а не выбирать нужные библиотеки. Не подключенные директивой #include файлы компилироваться не будут.
В следующем уроке будем работать с прерываниями по таймеру. Поговорим о параллельных процессах.
Библиотека HAL. STM32 CUBE MX. Светодиоды и кнопка
Сегодня мы познакомимся с библиотекой HAL. Данная библиотека, в отличие от SPL, широко используется и поддерживается.
Также для более комфортного использования данной библиотеки мы будем пользоваться программой для первоначальной настройки и генерации кода для среды программирования — STM32CubeMX.
Скачиваем STM32CubeMX с st.com (для этого нужно заполнить форму и ссылочка придет на электронную почту.
Устанавливаем его (может потребоваться установка Java)
Запускаем куб, выбираем контроллер.
Настраиваем порты PA0, PD12, PD13, PD14, PD15
Включаем шину rcc->HSE
Переходим в Clock Configuration, включаем HSE
Применим следующие настройки:
Input Frequency 8
AHB Prescaler 1
APB1 Prescaler 8
APB2 Prescaler 8
А можно и так как на рисунке (нажмите на картинку для увеличения размера)

Следующая вкладка Configuration.
Смотрим тут GPIO и ничего там не трогаем
Дальше идём в меню Project -> Generate Code
Настраиваем Toolchain IDE – MDK-ARM V5
Задаем имя проекта и расположение
Если нужно загрузить библиотеки, то загружаем.
Смотрим функции для управления портами в STM32F4HAL_User_manual.pdf, найти который можно введя на st.com в строке поиска «STM32F4xx»
Функции находятся HAL GPIO Generic Driver –> GPIO Firmware driver API description -> IO operation functions. Щелкаем по ссылке нужной функции и смотрим ее описание.
Добавляем в бесконечный цикл код
Затем задействуем кнопку следующим образом меняя код
else HAL_GPIO_WritePin(GPIOD, GPIO_PIN_12|GPIO_PIN_13|GPIO_PIN_14|GPIO_PIN_15, GPIO_PIN_RESET);
Прошиваем контроллер и смотрим результат.

Post Views: 13 941
33 комментария на “ STM Урок 4. Библиотека HAL. STM32 CUBE MX. Светодиоды и кнопка ”
Добрый день. Первым делом хочу сказать вам спасибо за ваш титанический труд. Написать такую уйму уроков за короткий срок — это нечто. Надеюсь, вы не бросите проект, как большинство авторов. Теперь «ближе к телу, как говорил Ги Де Мопассан» (с) Подскажите пожалуйста, почему при использовании HAL в Кейле в отладке не виден ни один периферийный блок. В SPL все доступно, а тут нет. Хоть в четвертом Кейле, хоть в пятом. Спасибо.
Вам также спасибо за оценку ресурса!
С этим делом не заморачивался. Тем более не знаю, какой именно блок не виден. И кейл у Вас лицензионный или бесплатный?
Не понятно зачем показывать «Хитрости» с копированием прошлого урока. Можно просто сохранить прошлый урок под другим именем в другой папке и модифицировать копию для следующего урока.
Четвертый Кейл крякнутый, пятый бесплатный. Поначалу в четвертом на SPL кое-что пописывал, отладка работала. Как перешел на Cube, отладки не стало. Ну, думаю, ST сейчас все примеры для пятого Кейла пишет, надо его попробовать. Попробовал — то же самое. Не видится вся периферия. Таймеры, GPIO и т. д.
Вот написал «Поначалу в четвертом на SPL кое-что пописывал», а потом подумал, что надо было написать «пытался кое-что пописывать». Ибо на Си раньше не писал, много встрчается всяких непонятных вещей, которые редко где описываются. Еще хочу вас попросить писать в статьях чуть поподробнее, что откуда берется. И, если можно, в каждой статье начинать проект заново. Процессоры, которые вы используете, есть не у каждого, поэтому приходится переделывать код под свой процессор. А если проект потом снова переделывать под новый проект, то можно совсем запутаться.
Если такая просьба приобретёт массовый характер, то так и буду делать, хотя мне это будет раз в 50 сложнее. А пока в каждой последней части урока выкладываю полный проект, который можно скачать. Хотя я также был противником выкладывания проекта. Иначе люди сами перестают думать и пользуются готовым проектом. Видимо, скоро надо будет и это прекращать. Так как, оказывается, на всех не угодить. Здесь ещё встречались такие, которые просили в каждой части промежуточные проекты выкладывать. Но хорошо, что их очень мало.
Эта просьба увеличилась на 1. Конечно немного подробнее можно объяснять. И проект выкладывать надо. Иначе вообще неинформативно у вас получится. А то «это берем здесь, это сюда, это на ум пошло…»
, более инженерным языком нужно. Но пока и на том неплохо.
где скачать STM32F4HAL_User_manual.pd?
Извините за дилетантский вопрос Где физически располагается файл main.h? Почему его видно в Кейле и не видно, если просто открыть папку и смотреть проводником Windows? Я скачал Keil 5 3 дня назад, до этого были AVRки, там AVR Studio да Proteus.
Заголовчные файлы обычно располагаются в папке Inc проекта.
У меня nucleo F401RE. Написал все как сказо в уроке, но светодиоды просто в итоге мигаю по очереди. Светодиоды как и кнопка вынесены на макетку. Единственное что тактировал от внутреннего так как кварца на плате нет. Можете подсказать в чем проблема?
Не знаю даже в чём проблема, но кварц у Вас есть. Настраивайте так же как и у меня генератор. В подобных платаг тактирование используется от генератора ST-Link, в конечном счёте от кварцевого резонатора, подключенного к ST-Link на 8МГц
Всем привет. Подскажите что не так . Светодиоды моргают, в программе добовляю или убираю светодиоды программа работает. А вот кнопка не работает . При том что при компиляции ошибок нет . Все сделал как у Вас .
Всем привет . Разобрался в чем дело . У меня есть маленькая плата stm32f303 к ней я приобрел добавочную плату open32f3. А там стояла перемычка на замыкание. Убрал её и кнопка стала работать. Начало есть двигаюсь дальше .
Как дрыгать ногой понятно, WritePin, TogglePin, ResetPin. А вот как сделать выбор ножки в цикле, нигде найти не могу. Допустим, что-то подобное:
for(i=0; i HAL_GPIO_TogglePin(GPIOD, GPIO_PIN_i);
HAL_Delay(500);
> И как бы сдвинуть регистр, описывающий состояние ног? К примеру, для того, чтобы прогнать горящий светодиодик по всем ножкам регистра последовательно, хочется просто сдвигать регистр в цикле целиком, но вот инструкцию для этого никак не могу найти. Реализовал просто удвоением значения, заносимого в порт, но чувствую, что это не самое правильное решение: char i=0;
char c=1; for(i=0; i HAL_GPIO_WritePin(GPIOA, c, GPIO_PIN_SET);
HAL_Delay(100);
HAL_GPIO_WritePin(GPIOA, c, GPIO_PIN_RESET);
c=c*2;
>
Огромное спасибо за ваш труд.
ElectronHD :
Пожалуйста подскажите где взять библиотеку. 2)Почему исходный код под 103 стмку
1) Все библиотеки подгрузятся из шаблонов при генерации проекта.
2) Простите, перепутал, спасибо! Пока убрал исходник, со временем попробую воспроизвести урок, пересобрать и выложить.
demetrodon :
Здравствуйте, что делать если на моей отладочной плате нет кнопки? чем можно ее заменить?
Здравствуйте!
Подключить внешнюю кнопку.
Не очень понял, как именно нужно настроить порты PA0, PD12, PD13, PD14, PD15. Когда их выбираешь на схеме мк справа, там куча вариантов их использования
Выбираем обычный выход.
Спасибо за ответ. Я в итоге открыл видео и сделал все по примеру, но странная штука: когда я начинаю генерировать код, вываливается окно: «the code is successfully generated under but mdk-arm v5project generation have a problem» Если попробовать его перегенерировать, то окно будет уже с успешным завершением.
При попытке сбилдить проект в uVision, компиляция валится с ошибкой «error: L6236E: No section matches selector — no section to be FIRST/LAST.» Я погуглил ее и вышел на то, что в проекте необходимо подключить Device-Startup.
Но если попробовать добавить этот файл, то валится 8 ошибок о множественном объявлении, например: Error: L6200E: Symbol SystemInit multiply defined (by system_stm32f4xx_1.o and system_stm32f4xx.o). Как я понял, надо где-то убрать какие-то инклюды, но вот дальше так и не понял, где именно.
Вообще, не будете ли вы против, если я свяжусь с вами как-то иначе, нежели через комментарии?
Мои контактные данные:
email: voultboy@yandex.ru
vk: vk.com/voulty
telegram: @hepoh
У меня такое было когда в пути проекта были кириллические символы.
У меня такая же проблема. Никак не удается решить.
На 20-й минуте, вы добавляете файл main.h из старого проекта в новый проект, а именно в папку Inc. Но в ней у меня уже есть этот файл весом 4КБ. Его заменить нужно, чтобы дальше выполнять урок?
Нет, теперь немного не так. Если есть main.h, то его лучше не трогать, а добавить в него необходимые файлы из старого проекта, и в следующий раз при создании проекта из прошлого не перезаписывать main.h.
Я так и сделал, добавил в него необходимые вещи согласно уроку. Но проект не собирается, он не может определить переменную tim6_counter.
Поэтому я вернул main.h в исходное состояние, и добавил в папку Inc файл maink.h (добавил букву всего лишь) и внёс все то, что вы вписывали в своем уроке в файл main.h (мой maink.h соответствовал вашему main.h), после этого все заработало.
Вопрос в том, не повлияет ли это на дальнейшие уроки, я к ним еще не приступал? приведу, внизу содержимое моего main.h, который я не стал трогать (может в него нельзя что-либо вносить)… * Define to prevent recursive inclusion ————————————-*/
#ifndef __MAIN_H__
#define __MAIN_H__ /* Includes ——————————————————————*/ /* USER CODE BEGIN Includes */ /* USER CODE END Includes */ /* Private define ————————————————————*/ /* ########################## Assert Selection ############################## */
/**
* @brief Uncomment the line below to expanse the «assert_param» macro in the
* HAL drivers code
*/
/* #define USE_FULL_ASSERT 1U */ /* USER CODE BEGIN Private defines */ /* USER CODE END Private defines */ #ifdef __cplusplus
extern «C» #endif
void _Error_Handler(char *, int); #define Error_Handler() _Error_Handler(__FILE__, __LINE__)
#ifdef __cplusplus
>
#endif #endif /* __MAIN_H__ */
Здравствуйте!
Начинаю работать с STM32, решил для простоты использовать что-то готовое: NUCLEO-L452RE-P. Задался создать примитив, что-то вроде мигания встроенного светодиода от встроенной кнопки. Запустил CubeMX, всё по мануалам, но при команде GENERATE CODE получил по фейсу следующее:
«The Firmware Package (STM32Cube BW_L4 V1.14.0) or one of its dependencies required by the Project is not available in your STM32CubeMX Repository. Do you want to download this now?»
Соглашаюсь на доунлад. Но дальше опять в торец:
«Error downloading the following files: stm32cube_fw_v1140.zip (Not available). For unavailable files, you can load them manually with the «From Local» button».
Где искать эту секретную локаль буттон?
Что посоветуете? Где спрятан выход, и как его найти?
Спасибо
Если ещё актуально, то посмотрите в следующей папке:
«C:\Users\»Имя пользователя»\STM32Cube\Repository»
Там должен быть скачанный архив (с именем что-то вроде «STM32Cube_FW_F0_V1.11.0»), который система не смогла разархивировать. Разархивируйте его вручную. Папка с библиотеками должна иметь имя «STM32Cube_FW_F0_V1.11.0».
У вас для задержки в 500 мс вызывается HAL_Delay(500), а у меня приходится делать примерно HAL_Delay(128000) для той же задержки. При частоте SYSCLK 216 МГц. Почему так может быть, не подскажете?
Отбой. Работает нормально после нажатия на кнопку Reset на плате. Хотя галка «Reset and Run» стоит в настройках.
Добрый день поскажите возможно ли в КубМХ поменять процессор с тем же колличеством ног но разной памятью в готовом проекте. Допустим STM32f103c8 на STM32f103cb или нужно создавать новый проект и туда переносить код.
STM32 fast start. Часть 1 ПО, материалы, Cube MX
В последнее время все чаще сталкиваюсь с холиварами на тему Cube MX и HAL, применительно к контроллерам STM32.
С одной стороны — стоят защитники, которым нравится удобство конфигурирования и читаемость кода.
С другой — приверженцы писать все руками, которым важна скорость работы и бережное использование ресурсов.
Для того, чтобы расставить все точки над i — попробуем написать «Hello world» тремя наиболее часто используемыми путями CMSIS, LL, HAL. Оценим затраты (ресурсы контроллера, объем исполняемого файла, и конечно же время работы разработчика).
Статья будет состоять из нескольких частей:
STM32 fast start. Часть 1 ПО, материалы, Cube MX.
STM32 fast start. Часть 2 Hello World на HAL, настройка отладки в Atollic TrueSTUDIO
STM32 fast start. Часть 3 Hello World на LL
STM32 fast start. Часть 4 Hello World на CMSIS
STM32 fast start. Часть 5 Подведение итогов, сравнение HAL, LL, CMSIS.
Сначала давайте определимся с тем, что же мы собственно будем программировать, то есть найдем подходящее железо.
Идеальным вариантом будет бюджетная плата на STM32F103C8T6 микроконтроллере.

Данную плату можно найти на всем известном сайте по цене от 100 российских рублей.
Искать по ключевым словам: STM32F103C8T6 ARM STM32 Minimum
Для того, чтобы залить прошивку и поиграть с отладкой — так же потребуется программатор
Для начала, да и для дальнейшего использования идеально подойдет китайский клон программатора ST-LINK V2.
Купить можно на том же сайте по цене от 120 российских рублей.

Искать по ключевым словам ST LINK Stlink ST 252dLink V2 Mini STM8 STM32:
Для разработки ПО под STM32 можно использовать различные IDE.
Самые популярные — IAR, Keil, Coocox (Eclipse).
Мы же пойдем по пути, который с недавних пор абсолютно бесплатно и в полном объеме предоставляет сама ST.
Будем использовать Atollic TrueSTUDIO for STM32 или в простонародии «Толик».
Какие плюсы у данного ПО: абсолютно бесплатно, нет ограничения по размеру кода, есть неплохой отладчик, простая установка и настройка.
Минусы: нет авто дополнения кода.
Доступны версии под windows и linux.
Качаем здесь https://atollic.com/resources/download/
С установкой данного ПО проблем возникнуть не должно, все интуитивно понятно, выбираем куда ставить и жмем все время «далее».
После установки можно не запускать, так как помимо самой IDE нужно еще кое что.
Если все таки запустили — просто закрываем.
Так как TrueSTUDIO — это средство разработки и отладки, хотелось бы не собирать проект руками (подключая требуемые библиотеки и прописывая пути), а получить некий преднастроенный файл, в котором можно без лишних заморочек сразу же писать код.
Для этого применяется программа генератор кода Cube MX или в простонародии «Калокуб».
Данное ПО является первым камнем преткновения в холиварах на чем же писать под STM: на регистрах и CMSIS или на HAL.
Защитники первой идеологии приводят такие аргументы: Cube MX генерирует огромный, ненужный объем кода, который к тому же замедляет работу МК.
Защитники второй — заявляют, что автоматически сгенерированный код сокращает время разработки, позволяя разработчику быстрее переключится к сутевой части устройства (к основной логике), отдав рутинную настройку периферии на откуп специализированному ПО (Cube MX).
Как ни странно — обе эти идеологии правдивы и применимы на практике, но только каждая в своих условиях.
Давайте рассмотрим пару примеров:
Пример №1: Требуется разработать устройство, максимально дешевое, так как планируется производство партиями по 100500 шт ежегодно. Естественно, каждый лишний рубль цены устройства — выльется в сотни тысяч рублей затрат на финальном устройстве. При этом в планируемой разработке есть пара тяжелых расчетов и работа с периферией (ADC, SPI, UART) на максимальных скоростях.
Устройство является полностью автономным продуктом, в дальнейшем планируется минимальные изменения за весь срок производства данного оборудования. Срок разработки до получения готового образца — 1-2 года.
Пример №2: Требуется прототип устройства, который возможно заинтересует заказчика и он закажет 100 шт аналогичных устройств для переоборудования своего объекта. Первая планируемая партия должна быть отгружена заказчику через 2 месяца. Размер первой тестовой партии 10 шт.
Точное ТЗ будет корректироваться в процессе работы над проектом, но известно, что в дальнейшем планируется несколько переработок аппаратной части, под которую необходимо оперативно подстраивать всю прикладную логику.
В первом примере идеальным вариантом будет выбор максимально дешевого контроллера и написание аппаратно зависимого, но оптимального кода, где работа с периферией будет организована через обращение к соответствующим регистрам (CMSIS). Разработчик, который занимается данным проектом — должен обладать хорошими или отличными знаниями периферии конкретного семейства МК. В идеале — при попытке разбудить его ночью — должен сразу же назвать адрес требуемого вектора из таблицы векторов прерываний.
Во втором примере — выбор контроллера обусловлен имеющимся в наличии железом, а так же затратами времени для написания функционала требуемого заказчиком. Поэтому скорость работы и оптимизированность самого ПО отходит на второй план. Времени на ручную инициализацию нет, как нет времени и на проработку аппаратных зависимостей.
В таком случае выбирается контроллер, который можно быстро поставить в производство в текущем регионе, на нем делается инициализация с помощью Cube MX, пишется прикладная логика на HAL и прототип передается заказчику для тестирования. Такой проект может вести любой средний разработчик, который постиг навыки работы с целевым языком программирования. Вникание в тонкости работы периферии — практически не требуются.
Как бы это не печально звучало — в реалиях современной разработки устройств в России — пример №1 встречается все реже, передавая эстафету примеру №2.
К обсуждению примеров №1 и №2 вернемся в самом конце цикла статей, а сейчас продолжим с подготовкой рабочего пространства.
На данном этапе сделаем небольшую паузу, зайдем на сайт my.st.com и зарегистрируем на нем учетную запись, так как политика компании ST не позволяет скачивать необходимые материалы без регистрации.
После того, как у нас появился доступ к сайту — скачиваем STM32 Cube MX.
В самом низу страницы есть кнопка выбора версии, нам нужна версия 5.0.0

Попутно, пока мы не ушли отсюда, качаем еще две вещи, которые пригодятся в дальнейшем
https://www.st.com/en/development-tools/stsw-link008.html
Драйвер ST-LINK V2


Установка драйвера, прошивальщика и самого Cub’a не вызывают затруднений, просто соглашаемся со всем и жмем далее.
После полной установки необходимого ПО — можем приступать к созданию проекта.
Для этого запустим Cube MX.
В появившемся окне нажмем на кнопку «ACCESS TO MCU SELECTOR».

На нашей целевой плате установлен микроконтроллер STM32F103C8T6.
Введем его название в строке поиска и двойным щелчком выберем единственный найденный вариант.
В этой же таблице видно основную начинку нашего МК (64 килобайт флеша, 20 килобайт оперативы и пр).

Перед нами появился схематически изображенный корпус контроллера с разведенными в разные стороны ножками.
На данном этапе необходимо обязательно выбрать способ подключения отладчика.
Для этого на вкладке Pinout & Configuration в левом меню выбираем пункт SYS а в нем в выпадающем списке под названием «Debug» устанавливаем значение Serial Wire.
При этом краем глаза замечаем, что программа зарезервировала для отладочных целей два пина на мнемосхеме контроллера.

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

или более красочная и простая для понимания распиновка платы

Искомый светодиод находится на ножке PC13.
Соответственно, необходимо настроить данный вывод для работы в режиме выхода.

- Находим вывод на мнемосхеме
- Нажимаем на него правой кнопкой мыши, из выпадающего меню выбираем пункт «GPIO_Output»
- Переходим в меню GPIO,
- В списке выбираем PC13
- Заполняем таблицу PC13-TAMPER-RTC Configuration в соответствии со скриншотом, особенно нас интересуют параметры GPIO mode и User Label
Продолжаем настройку проекта, переходим к вкладке Clock Configuration.
На самом деле это одна из важнейших вкладок, которая позволяет настроить параметры тактирования периферии, но пока не будем здесь ничего трогать, так как главная цель на данный момент не в этом.

Переходим к вкладке Project Manager, под вкладка Project.
Обязательно заполняем следующие параметры:

- Имя проекта (лучше использовать только латинские буквы)
- Директорию, в которой будет создан проект (так же лучше использовать только латиницу)
- IDE, в которой планируется работа над проектом (мы планируем использовать TrueSTUDIO)
Спускаемся ниже, под вкладка Code Generator.
Здесь обязательно отмечаем опцию Generate peripheral initialization as pair…
Таким образом получим более структурированный проект, в котором для каждого типа периферии имеется своя пара C и H файлов.

Остался последний шаг. Подвкладка Advanced Settings.

- Выбираем тип библиотеки HAL для всех периферийных модулей
- Собираем проект с текущими настройками
При первоначальном запуске возможно потребуется загрузить актуальную версию библиотеки для выбранного семейства МК.
Даем свое согласие на скачивание файлов:

Идем греть чайник или готовить кофе:

После окончания работы кодо-генератора — сразу же открываем его:

Выбираем любую папку, где Atollic будет хранить рабочее пространство:

При успешном открытии — перед нами предстанет главное окно Atollic TrueSTUDIO for STM.
Общая информация нас мало интересует, поэтому сразу перейдем к дереву файлов.

Найдем там файл main.c и функцию int main(void):

Для самопроверки — попробуем собрать пустой проект

- В меню Project -> Rebuild Project
- Внизу выбрать вкладку Console
- При успешной сборке — должны получить надпись Build Finished
Продолжение — в следующей части.
P.S.: Ранее статью публиковал в своем личном блоге .