Исчезание кода при автогенерации
Когда вы работаете с проектами для STM32 в STM32CubeIDE, часто возникает ситуация, когда после выбора настроек в файле .ioc и генерации кода ваш собственный код может быть перезаписан. Это связано с тем, что генерация кода в CubeIDE обновляет файл main.c. Чтобы избежать потери своих изменений при дальнейших генерациях, существует специальный механизм для выделения вашего кода, который позволяют сохранить ваши изменения при повторной генерации. Эти комментарии выглядят следующим образом:
/* USER CODE BEGIN*/ Здесь будет ваш код /* USER CODE END */
Для генерации кода можно воспользоваться сочетанием клавиш alt + k либо значком на панели инструментов
Цикл while(1)
Прежде чем мы перейдём к разбору каждой отдельно взятой секции, скажем пару слов о цикле while. Этот цикл обеспечивает непрерывную работу программы, выполняя в нём все задачи, которые должны выполняться постоянно. Это может быть, например, управление периферией, обработка прерываний или выполнение основного алгоритма работы устройства. Цикл while (1) позволяет микроконтроллеру оставаться в рабочем состоянии, пока не будет выключен или перезагружен.В большинстве случаев лучше избегать бесконечного while(1), если можно использовать более эффективные методы, такие как прерывания. Цикл while(1) загружает процессор даже при отсутствии задач, затрудняет масштабируемость кода и мешает снижению энергопотребления. Вместо этого предпочтительно использовать прерывания, которые выполняют код только при необходимости, или ОСРВ (например, FreeRTOS) для управления задачами. Если же у вас простая задача то можете использовать только цикл while.
Назначение блоков кода в файле main.c
В CubeIDE при создании проекта есть специальная разметка для кода. И хоть вы можете писать свой код в любом пользовательском блоке, но правильное размещение кода в специально отведённых блоках не только упрощает его поддержку и отладку, но и предотвращает удаление при повторной генерации. Следование структуре проекта помогает сохранить читаемость, организованность и совместимость с инструментами автогенерации. Напишу максимально кратко, чтобы можно было после одного взгляда определить куда вам писать код.
/* USER CODE BEGIN Header */
Общая информацию о файле. Обычно сюда добавляют описание проекта, автора и лицензию.
/* USER CODE BEGIN Includes */
Дополнительные заголовочные файлы.
#include "my_library.h"
/* USER CODE BEGIN PTD */
Пользовательские типы данных (typedef, enum, struct).
typedef struct { int x; int y; } Point;
/* USER CODE BEGIN PD */
Параметры по умолчанию
#define UART_BAUDRATE 9600 #define LED_PIN GPIO_PIN_5
/* USER CODE BEGIN PM */
Пользовательские макроопределения, такие как пин и порт для светодиода и т.д.
#define LED_PIN GPIO_PIN_13 #define LED_PORT GPIOC
/* USER CODE BEGIN PV */
Глобальные переменные
uint8_t buttonPressed = 0; int sensorValue = 0;
/* USER CODE BEGIN PFP */
Название и сигнатуру функций (ее имя, параметры и возвращаемое значение), без их реализации.
void BlinkLED(void); int ReadSensorValue(void);
/* USER CODE BEGIN 0 */
Секция для добавления пользовательского кода, который выполняется до начальной системной инициализации и до инициализации HAL. Вызов пользовательских функций или присвоить значений переменных.
counter = 100; mode = 1;
/* USER CODE BEGIN 1 */
Секция похожая на предыдущую но уже выполняющаяся в теле main.
/* USER CODE BEGIN Init */
Инициализация устройств пользователя, настройка начальных параметров, передача им необходимых начальных данных.
midiNoteOn[0] = 0x09;
/* USER CODE BEGIN SysInit */
Общие настройки системы, место для работы с системными таймерами, прерываниями и т. д
NVIC_SetPriority(EXTI0_IRQn, 2);
/* USER CODE BEGIN 2 */
Любые действия после инициализации периферии. Хорошо подходит для отладочной информации перед основным циклом.
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_5, GPIO_PIN_SET);
/* USER CODE BEGIN WHILE */
Секция для выполнения задач основного цикла программы . Здесь может быть всё что угодно например чтение датчиков и работы с периферией, обработка событий и т.д.
HAL_GPIO_TogglePin(GPIOA, GPIO_PIN_5); HAL_Delay(500);
/* USER CODE BEGIN 3 */
Если есть задачи, которые должны выполняться после основной логики, но до следующей итерации цикла, сюда их можно вставлять. Удобно использовать для отладочной информации.
printf("Loop iteration complete\n");
/* USER CODE BEGIN 4 */
Место для тела пользовательских функций.
void Blink_LED(uint8_t times, uint16_t delay_ms) { for (uint8_t i = 0; i < times; i++) { HAL_GPIO_TogglePin(GPIOA, GPIO_PIN_5); HAL_Delay(delay_ms); HAL_GPIO_TogglePin(GPIOA, GPIO_PIN_5); HAL_Delay(delay_ms); } }
/* USER CODE BEGIN Error_Handler_Debug */
Секция для обработки ошибок. Сюда добавлять код отладки.
char *error_msg = "Error detected! System halted.\r\n"; HAL_UART_Transmit(&huart2, (uint8_t*)error_msg, strlen(error_msg), HAL_MAX_DELAY);
Правильное подключение пользовательской секции кода в STM32CubeIDE
Чтобы подключить свою секцию кода в проект STM32CubeIDE, наилучшим решением будет вынести её в отдельный файл. Это обеспечит модульность, удобство поддержки и защиту кода от удаления при повторной генерации. Для этого создаётся заголовочный файл (.h) с объявлениями функций и исходный файл (.c) с их реализацией. Затем заголовочный файл подключается в main.c, а компилятор автоматически связывает его с соответствующим .c файлом во время сборки.
Давайте сделаем по шагам. Например нам необходимо вынести функцию YourFunction в отдельный файл. Для этого.
- Создаём заголовочный файл your_section_file.h в папке Inc. В нём объявляем нашу функцию.
void YourFunction(void);
- Создаём отдельный файл your_section_file.c в папке Src. В нём подключаем наш заголовочный файл и пишем тело функции.
#include "your_section_file.h" void YourFunction(void) { HAL_GPIO_TogglePin(GPIOA, GPIO_PIN_5); HAL_Delay(500); }
- Подключаем наш файл в main.c
#include "your_section_file.h";
- Вызываем нашу функцию
#include "your_section_file.h";
В этой статье мы рассмотрели основные блоки файла main.c в STM32CubeIDE, а также разобрались с проблемой исчезновения пользовательского кода при повторной генерации. Выяснили в какие блоки добавлять ваш код чтобы он был более структурированным. Так же разобрались с добавлением своего блока кода.