В интернете очень много информации, но по теме ООП + STM32 я её встречал мало. В серии статей я попытаюсь рассказать, как я пришёл к ООП ни как к таковому, а именно на микроконтроллерах от фирмы ST. Это не моё НоуХау. Это то, что я сумел собрать для себя и то, чем я пользуюсь для облегчения программирования в своих разработках.
Примечание: Предусматривается, что компьютер знают все и рассказывать, где какая кнопка находится, я не буду.
Среда разработки: CubeMX, CubeIDE. Всегда последней версии.
Микроконтроллеры: Серия STM32
Для начала я покажу, как у меня организовано дисковое пространство. Это не догма. Просто мне так удобнее. Каждый сам для себя должен решить, как ему удобнее. Но последующие статьи я буду писать со ссылкой именно на такую организацию:
Все свои проекты я храню в каталоге WorkDevel. Он содержит подкаталоги:
- AltiumLib - библиотеки Altium Designer;
- Datasheet - даташиты на электронные компоненты;
- Developer - каталог, хранящий все проекты;
- Examples - примеры не привязанные к МК. Могу наполнять этот каталог без описания в статьях. Будет время заглядывайте, может найдёте что то интересное;
- Project_Lesson_01 - это тот первый каталог, в котором мы с вами будем работать;
- Code_CPP - здесь будут подкаталоги с нашим кодом. На больших проектах там может быть не один каталог.
- Output - сюда я вывожу Gerber файлы для заказа их в Китае;
- Pcad - здесь хранятся проекты схем и плат. Так же как и в Code_CPP, на больших проектах может содержать несколько подкаталогов;
- Source - сюда складываю первичную информацию. Техзадания, даташиты на элементы, участвующие именно в этом проекте. И так далее;
- Tests MK - здесь храним примеры для разных МК, которые будут описаны в последующих статьях;
- STM32Lib - каталог, где хранятся библиотеки и программные ядра на каждый тип микроконтроллера.
- Device - библиотеки, зависимые от типа ядра МикроКонтроллера (МК);
- Library - библиотеки, независимые от типа MK.
Так как я работаю на разных компьютерах, данная структура позволяет мне переносить проекты с компьютера на компьютер без потери данных и не заморачиваться каждый раз, где что лежит, и не важно, какая буква присвоена диску. Даже на те, которые не подключены к интернету.
Вот теперь можно приступить.
Примечание: То, что я буду давать, будет применимо к любому ядру МК. В случае, если есть какие-то отличия между ядрами в инициализации периферии, я постараюсь на этом заострять внимание.
Вы можете проделать показанные мною операции для любого ядра МК. Я же покажу всю цепочку на STM32F407VET6. Так как для него у меня более полные библиотеки. Но никто не мешает вам, взяв его библиотеки за пример, дописать свои.
Создание проекта.
Загружаем CubeMX и выбираем нужный нам МК:
Никакую периферию мы не инициализируем, а сразу идём на закладку Project Manager:
Здесь нас интересуют только три поля:
- Project Name - имя проекта. Вводим имя, по которому будем идентифицировать проект.
- Project Location - выбираем каталог, в котором будет храниться наш проект. В данном случае С:\WorkDevel\Developer\Project_Lesson_01\Code_CPP
- Toolchain\IDE - выбираем STM32CubeIDE.
Затем слева выбираем Code Generator и ставим галку напротив первого пункта в разделе Generated files:
В данном проекте нам она погоды не сделает, но привычка позволит в более сложных проектах разбивать функции инициализации периферии по отдельным файлам. Что весьма удобно. Почему-то не все это любят. Есть такие, что пишут портянки по 5000 строк в одном файле. А можно было разбить код на отдельные логически блоки и раскидать их по файлам.
Подготовка закончена, генерируем код (кнопка справа вверху Generate Code):
Нам предлагается или открыть каталог с проектом, или открыть его сразу в IDE, или всё на этом. Выберем открытие проекта. Загружается выбранная IDE, в нашем случае CubeIDE. После загрузки проекта открываем main.c:
Пробуем компилить, никаких ошибок быть не должно:
Теперь начинаем методично уничтожать HAL. В каталоге Inc удаляем все файлы, в каталоге Src оставляем только те файлы, которые на картинке, в каталоге Drivers удаляем весь подкаталог STM32F4xx_HAL_Driver:
В main.c удаляем всё, кроме указанного на картинке:
Идём в меню Project>Properties>C/C++ Build>Settings, закладка Tool Settings, MCU GCC Compiler>Preprocessor. Вверху выбираем All Configurations и грохаем USE_HAL_DRIVER:
Нажимаем Apply. Идём в Include Paths, там удаляем всё упоминание о HAL:
Нажимаем Apply и Apply and Close. Пытаемся компилить и получаем одно предупреждение. Необходимо эту строку закомментировать. Не удалять ни в коем случае, она позже вам пригодится:
Нажимаем правой кнопкой на проекте и выбираем конвертацию в С++:
Вроде визуально ничего не изменилось. Но если посмотреть здесь:
У нас появился новый пункт: MCU G++ Compiler. Переименовываем main.c в main.cpp и пробуем компилить:
Выдаётся такая ошибка:
Ничего страшного. Идём сюда и выбираем Clean Project:
Компилируем снова и получаем 0 ошибок:
На этом пока всё. Позже покажу как подключать библиотеки находящиеся в STM32Lib.
Тема на форуме - перейти.
Спасибо, интересно, буду ждать следующие части.
Да, да, да, как раз это я и искал в такой доступной форме. Жду продолжения
Раз форма считается доступной, придётся продолжать.
🙂
Все равно продолжает выскакивать ошибка error: '__disable_irq' was not declared in this scope
16 | __disable_irq();
Закомментируйте её. Когда выполните следующие шаги из последующих статей, ошибка пропадёт.
Кроме всего прочего, библиотеки развиваются дальше, что может вызывать ошибки при компиляции в предыдущих статьях.
Нужна статья как этого избежать.
Спасибо за раскрытие этой темы! Очень интересно! Тоже жду следующие части.)
Где сейчас можно скачать cube ide или mx, свежие версии?
st.com сейчас совсем не дают скачивать.
https://disk.yandex.ru/d/Sqb3kIEuMv2MoQ
CubeMX 6.4 и 6.5 глючные
Доброго времени ) Подскажите пожалуйста, только заинтересовался темой . С чего начать, чтобы было понятнее содержание статей по STM & с++. Если у меня никакого HAL не было то я могу начать с этой статьи, пренебрегая действиями с HAL? спасибо.
Добрый день. Начинать нужно с этой статьи. Хоть здесь и в нескольких последующих нет С++, без понимания с чего это всё началось будет сложно разобраться в последующих статьях.
Наконец то нашёл дельную статью, может поможет наконец то пересесть с Microchip IDE.
А чем Вам не нравится MPLABX?
Очень мощная среда сразработки. Мощнее CubeIDE.
Я от PIC ушёл из за того, что какие то невнятные у них микроконтроллеры.
Д всем устраевает, кроме того, что досталось мне очень много stm32f100. и жало их выбрасывать, пущай в дело идут.
Если что, свистите. Помогу чем смогу.
Вот и добрался я до экспериментов. И тут же впёрся в синтаксис HAL.
Думаю нужен вашь совет, не пойму что не так с простейшим кодом.
Написал 2 карианта управления пином, оба компилируются и загружаются в чип без ошибок. Но диод на макетке молчит.
{
/* USER CODE END WHILE */
HAL_GPIO_WritePin(13_GPIOC_Port,13_Pin,1); //1
HAL_GPIO_WritePin(GPIOС, GPIO_PIN_13, GPIO_PIN_SET); //2
HAL_Delay(60);
HAL_GPIO_WritePin(GPIOC, GPIO_PIN_13, GPIO_PIN_RESET); //2
HAL_GPIO_WritePin(13_GPIOC_Port,13_Pin,0); //1
HAL_Delay(100);
/* USER CODE BEGIN 3 */
}
Где я что то не догоняю?
Макетка простенькая - STM32F103C8 (Blue Pill)
за ранее спасибо!
Всё, терпения моего на HAL не хватило, убил я его по инфе в вашей статье.
Если не трудно, не мешала бы статья для перешедших на классы по конфигурированию контроллера, желательно на примере какой нибудь простенькой мигалки диодом.
Что то пока тяжело CUBE даётся, но мы не сдаёмся!
Попробуй как здесь, один в один сделать - https://microtechnics.ru/stm32cube-ispolzovanie-portov-vvoda-vyvoda-gpio/. Ну вывод другой только соответственно.
К сожалению времени на изучение более не осталось!
Срочно нужен продукт.
К счастью пробный код проглотил и превосходно отработал в Platformio. Осталось почитать про активацию и настройку встроенных часов с внешним кварцем на 32.768.
Но, после, я продолжу добивать CUBE.
В любом случае спасибо за помощь!!!
#include "STM32.h"
#include "IO_Digital.h"
// На моей плате светодиоды здесь. Правьте в соответствии со схемой своей плыты
#define LED_GPIO GPIOC
#define LED_PIN GPIO_PIN_0
IO_Digital Led(LED_GPIO, LED_PIN, Output, No_Pull);
int main(void)
{
SystemClock_Config(Quartz_8); // Инициализируем тактовый генератор
while(1)
{
Led.digitalWrite(High); // Устанавливаем выход в высокое состояние
delay(500);
Led.digitalWrite(Low); // Устанавливаем выход в низкое состояние
delay(500);
// Можно ещё так
// Устанавливаем выход в противоположное состояние. Так как предыдущая команда установила его в "0",
// эта команда переведёт его в противоположное состояние, т.е. "1"
Led.digitalTogglePin();
delay(200);
// Устанавливаем выход в противоположное состояние. Так как предыдущая команда установила его в "1",
// эта команда переведёт его в противоположное состояние, т.е. "0"
Led.digitalTogglePin();
delay(200);
}
}
void Error_Handler(void)
{
/* USER CODE BEGIN Error_Handler_Debug */
/* User can add his own implementation to report the HAL error return state */
// __disable_irq();
while (1)
{
}
/* USER CODE END Error_Handler_Debug */
}
#ifdef USE_FULL_ASSERT
/**
* @brief Reports the name of the source file and the source line number
* where the assert_param error has occurred.
* @param file: pointer to the source file name
* @param line: assert_param error line source number
* @retval None
*/
void assert_failed(uint8_t *file, uint32_t line)
{
/* USER CODE BEGIN 6 */
/* User can add his own implementation to report the file name and line number,
ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */
/* USER CODE END 6 */
}
#endif /* USE_FULL_ASSERT */
Привет. Если на моих библиотеках, по моим статьям.
Моргание диодом на классах.
Для RTC код то же есть.
А в примере с HAL задержки короткие, можно не увидеть как моргает.