STM Урок 108. FreeRTOS. Параметры

Продолжаем работу с операционной системой реального времени FreeRTOS.

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

Оказывается, есть такой механизм — это механизм передачи параметров в функцию, которые мы туда передаём в момент создания задачи.

До сих пор мы входной параметр функции создания задачи, предназначенный для передачи параметров назначали как NULL. То есть мы вообще не передавали никаких параметров в задачи.

Можно передать один, два, одним словом сколько угодно параметров. Если нам нужно передать только один параметр, то мы создаём переменную любого типа, присваиваем её значение и передаём разименованный указатель типа void на эту переменную в качестве параметра. А если мы хотим передать несколько параметров, пусть даже различного типа, то тогда мы создаём структуру с разными переменными, также создаём переменную типа данной структуры, затем каждой переменной, которая станет уже полем структуры, присваиваем какие-либо значения и передаём уже указатель на данную структуру.

Так как работать мы будем с той же платой — STM32F746G-DISCOVERY, то для того, чтобы поработать с параметрами, мы создадим проект из проекта прошлого занятия CREATE_TASKS с именем PARAM01, откроем его в проектогенераторе Cube MX, и, вообще ничего не трогая сгенерируем проект для SystemWorkbench, откроем его там, настроим оптимизацию 1 и уберём отладочную конфигурацию, если та будет иметь место в проекте.

Попробуем собрать и прошить данный проект, если всё нормально, то двигаемся дальше.

Для параметров в файле main.c создадим глобальную структуру и три переменных её типа, так как у нас будет три задачи

 

osThreadId Task01Handle,Task02Handle,Task03Handle;

typedef struct struct_arg_t {

  char str_name[10];

  uint16_t y_pos;

  uint32_t delay_per;

} struct_arg;

struct_arg arg01, arg02, arg03;

 

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

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

 

/* USER CODE BEGIN 5 */

osThreadList((unsigned char *)str_buf);

HAL_UART_Transmit(&huart1,(uint8_t*)str_buf,strlen(str_buf),0x1000);

HAL_UART_Transmit(&huart1,(uint8_t*)"\r\n",2,0x1000);

/* Infinite loop */

for(;;)

{

  osDelay(1);

}

 

 

А инициализацию нашей памяти и дисплея, а также вывод шапки на дисплей, мы добавим опять в функцию main()

 

/* USER CODE BEGIN 2 */

MT48LC4M32B2_init(&hsdram1);

HAL_LTDC_SetAddress(&hltdc,LCD_FRAME_BUFFER,0);

TFT_FillScreen(LCD_COLOR_BLACK);

TFT_SetFont(&Font24);

TFT_SetTextColor(LCD_COLOR_LIGHTGREEN);

TFT_DisplayString(0, 10, (uint8_t *)"Create tasks", CENTER_MODE);

TFT_SetTextColor(LCD_COLOR_MAGENTA);

TFT_DisplayString(14, 60, (uint8_t *)"Task1:", LEFT_MODE);

TFT_DisplayString(14, 110, (uint8_t *)"Task2:", LEFT_MODE);

TFT_DisplayString(14, 160, (uint8_t *)"Task3:", LEFT_MODE);

/* USER CODE END 2 */

 

Если мы теперь соберём и прошьём проект, то мы в терминальной программе теперь не увидим вновь созданных задач, так как мы удалили код их создания. Мы увидим лишь задачи, добавленные в Cube MX и задачу «Бездействие»

 

 

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

В функции main() после создания уже существующих задач, но до вызова планировщика, создадим пока одну задачу и пока без параметров

 

/* USER CODE BEGIN RTOS_THREADS */

/* add threads, ... */

osThreadDef(tsk01, Task01, osPriorityIdle, 0, 128);

Task01Handle = osThreadCreate(osThread(tsk01), NULL);

/* USER CODE END RTOS_THREADS *

 

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

 

void Task01(void const * argument)

{

  TFT_SetTextColor(LCD_COLOR_BLUE);

  for(;;)

  {

    sprintf(str1,"%lu ", osKernelSysTick());

    TFT_DisplayString(280, 60, (uint8_t *)str1, RIGHT_MODE);

    osDelay(1000);

  }

}

 

Можно на данном этапе собрать код и прошить контроллер, в верхней строке у нас будут считаться системные кванты, как обычно

 

 

Пока у нас всё работает безо всяких параметров.

 

 

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

 

/* add threads, … */

strcpy(arg01.str_name,"task1");

strcpy(arg02.str_name,"task2");

strcpy(arg03.str_name,"task3");

arg01.y_pos = 60;

arg02.y_pos = 110;

arg03.y_pos = 160;

arg01.delay_per = 1000;

arg02.delay_per = 677;

arg03.delay_per = 439;

osThreadDef(tsk01, Task01, osPriorityIdle, 0, 128);

 

Мы здесь занесли значения во все поля наших структур — имена задач, позиции по вертикали, и значение задержки в милисекундах.

Теперь давайте при создании нашей первой задачи передадим в неё указатель на структуру с параметрами

 

Task01Handle = osThreadCreate(osThread(tsk01), (void*)&arg01);

 

Теперь у нас в задачу передан указатель на три параметра.

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

 

void Task01(void const * argument)

{

  volatile struct_arg *arg;

  arg = (struct_arg*) argument;

  TFT_SetTextColor(LCD_COLOR_BLUE);

 

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

 

for(;;)

{

  sprintf(str1,"%lu ", osKernelSysTick());

  TFT_DisplayString(280, arg->y_pos, (uint8_t *)str1, RIGHT_MODE);

  sprintf(str1,"  %s   ", arg->str_name);

  TFT_DisplayString(275, arg->y_pos, (uint8_t *)str1, LEFT_MODE);

  osDelay(arg->delay_per);

}

 

Первый параметр мы использовали для позиции по вертикали, второй — для вывода на дисплей имени задачи, а третий — для значения задержки.

Соберём код, прошьём контроллер и проверим работоспособность наших параметров

 

 

Отлично! Параметры передались, всё спозиционировалось, задержка срабатывает через заданное время и строка выводится.

Давайте аналогичным образом в функции main() создадим остальные две задачи и передадим им указатели на параметры, предназначенные для них

 

Task01Handle = osThreadCreate(osThread(tsk01), (void*)&arg01);

osThreadDef(tsk02, Task01, osPriorityIdle, 0, 128);

Task02Handle = osThreadCreate(osThread(tsk02), (void*)&arg02);

osThreadDef(tsk03, Task01, osPriorityIdle, 0, 128);

Task03Handle = osThreadCreate(osThread(tsk03), (void*)&arg03);

/* USER CODE END RTOS_THREADS */

 

Соберём код, прошьём контроллер и посмотрим результат на нашем дисплее

 

 

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

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

 

 

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

Всем спасибо за внимание!

 

 

 

Исходный код

 

 

Отладочную плату можно приобрести здесь STM32F746G-DISCOVERY

 

 

Смотреть ВИДЕОУРОК в RuTube (нажмите на картинку)

STM FreeRTOS. Параметры

 

Смотреть ВИДЕОУРОК в YouTube (нажмите на картинку)

STM FreeRTOS. Параметры

1 комментарий к “STM Урок 108. FreeRTOS. Параметры

  1. Добрый день.
    Пробую использовать FreeRTOS в STM32F103.
    Настраивал и создавал задачи в CubeMX.
    После сборки проекта в Keil выдало ошибку:
    «no source»: Error: #5: cannot open source input file «../Middlewares/Third_Party/FreeRTOS/Source/stream_buffer.c»: No such file or directory
    Подскажите с чем может быть связана ошибка? Что не активировал или не верно установил?
    Спасибо.

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *

*