STM Урок 114. FreeRTOS. Продвинутая задержка DelayUntil

 

 

 

До сих пор мы с вами пользовались только одним типом задержки, что в FreeRTOS, что в обычной жизни. Обычная задержка откладывает выполнение дальнейшего кода на определённое количество времени, а в случае использования операционной системы FreeRTOS она также на данное количество времени ещё и переводит задачу, в которой вызывается, в блокированное состояние, давая остальным задачам работать, причём даже с более низким приоритетом. Нас как-то это вполне устраивало.

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

Вот тут то нам и приходит на помощь другая задержка, которая учитывает и время основного кода.

В операционной системе FreeRTOS для этого используется функция vTaskDelayUntil. Прежде чем вызвать данную функцию, мы до выполнения основного кода сначала заносим в переменную количество системных квантов, затем выполняем весь код, время выполнения которого должно быть учтено в задержке, а затем уже вызываем данную функцию (за счёт того, что у нас порт, она будет выглядеть немного по-другому), передавая в одном из входящих аргументов значение переменной. Причём каждый цикл вычислять системные кванты не нужно, функция это сделает за нас сама.

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

Поэтому давайте начнём.

Проект мы создадим из проекта урока 108 по параметрам PARAM01 и назовём его DELAY_UNTIL.

Откроем наш проект в Cube MX, зайдём в раздел Configuration, откроем настройки FreeRTOS, откроем вкладку Include parameters и включим возможность использовать наши задержки

 

 

Сохраним настройки, сгенерируем проект, откроем его в System Workbench, настроим уровень оптимизации в 1, а также уберём отладочную настройку при её наличии.

Закомментируем строки в настройках DMA2D, которые System Workbench считает ошибочными, попробуем собрать наш проект. Если проект нормально собрался, то в функции main() немного подправим время задержек для наших задач, чтобы легче было отследить их время срабатывания

 

arg01.delay_per = 1000;

arg02.delay_per = 500;

arg03.delay_per = 400;

 

Также исправим шапку на дисплее

 

TFT_DisplayString(0, 10, (uint8_t *)"Delay Until", CENTER_MODE);

 

Если мы сейчас соберём и прошьём код, то у нас задержки будут работать нормально, так как у нас в цикле задач кода мало или он такой, что очень быстро выполняется и в милисекундах мы это сразу не оценим. Поэтому давайте перейдём в функцию задач Task01 и помимо вывода на дисплей нашей информации передадим ещё что-нибудь в USART, так как данная передача происходит не очень быстро. Только сначала мы немного исправим код вывода информации на дисплей, объединив всё в один вызов функции. Бесконечный цикл в данной функции теперь станет вот таким

 

for(;;)

{

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

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

  osDelay(arg->delay_per);

}

 

Теперь передадим нашу строку ещё и в порт USART

 

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

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

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

 

Пока мы оставляем обычную задержку.

Соберём код, прошьём контроллер.

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

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

 

 

А вот в терминальной программе мы это можем заметить отчётливо

 

 

Я специально выделил строки только первой задачи для наглядности. Мы видим, что период между выводами информациями у нас составляет не 1000 милисекунд, а примерно 1002.

А вот теперь мы попробуем использовать нашу продвинутую задержку.

Перед бесконечным циклом мы занесём в переменную количество прошедших системных квантов

 

TFT_SetTextColor(LCD_COLOR_BLUE);

uint32_t tickcount = osKernelSysTick();

for(;;)

 

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

 

//osDelay(arg->delay_per);

osDelayUntil(&tickcount, arg->delay_per);

 

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

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

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

 

 

Красиво! Не правда ли?

Теперь циклы задач у нас работают через строго определённые периоды.

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

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

 

Предыдущий урок Программирование МК STM32 Следующий урок

 

Исходный код

 

 

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

 

 

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

 

STM FreeRTOS. Продвинутая задержка DelayUntil

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

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

*