Лабораторная работа
example.c
#include <FreeRTOS.h> #include <task.h> #include <queue.h> #include <stdio.h> #include "riscv-virt.h" #include "ns16550.h" #define mainDELAY_LOOP_COUNT ( 10000000 ) #define exampleTASK_PRIORITY ( tskIDLE_PRIORITY + 1 ) void vTask1( void *pvParameters ) { const char *pcMessage = "Task 1 is running"; volatile unsigned long ul; for( ;; ) { vSendString( pcMessage ); for( ul = 0; ul < mainDELAY_LOOP_COUNT; ul++ ) { } } } void vTask2( void *pvParameters ) { const char *pcMessage = "Task 2 is running"; volatile unsigned long ul; for( ;; ) { vSendString( pcMessage ); for( ul = 0; ul < mainDELAY_LOOP_COUNT; ul++ ) { } } } int main_example( void ) { xTaskCreate( vTask1, "Task 1", configMINIMAL_STACK_SIZE * 2U, NULL, exampleTASK_PRIORITY, NULL ); xTaskCreate( vTask2, "Task 2", configMINIMAL_STACK_SIZE * 2U, NULL, exampleTASK_PRIORITY + 1, NULL ); vTaskStartScheduler(); return 0; }
Для запуска примера, измените следующие строки в файле main.c:
- 33 - #define DEMO_EXAMPLE 1
- добавьте объявление int main_example( void );
-
в функции main замените
#if defined(DEMO_BLINKY) ret = main_blinky(); #else #error "Please add or select demo." #endif
на
#if defined(DEMO_BLINKY) ret = main_blinky(); #elif defined(DEMO_EXAMPLE) ret = main_example(); #else #error "Please add or select demo." #endif
В файле Makefile в 35 строку добавьте example.c:
SRCS = main.c main_blinky.c example.c riscv-virt.c ns16550.c \
Теперь приложение можно собрать и запустить аналогично предыдущему.
Вывод
Task 1 is running Task 2 is running Task 2 is running Task 1 is running Task 1 is running Task 2 is running Task 2 is running Task 1 is running Task 2 is running Task 1 is running Task 2 is running Task 1 is running Task 2 is running Task 1 is running Task 2 is running Task 1 is running Task 2 is running Task 1 is running Task 1 is running Task 2 is running
Задание приоритетов
Посмотрите, что получится, если задачам задать разные приоритеты. Это можно сделать, поменяв в 47 строке exampleTASK_PRIORITY на exampleTASK_PRIORITY + 1.
При изменении приоритетов можно получить следующий вывод программы:
Task 2 is running Task 2 is running Task 2 is running Task 2 is running Task 2 is running Task 2 is running Task 2 is running Task 2 is running Task 2 is running Task 2 is running Task 2 is running Task 2 is running Task 2 is running Task 2 is running Task 2 is running Task 2 is running Task 2 is running Task 2 is running Task 2 is running Task 2 is running
Всё время выполняется задача с большим приоритетом.
Изменим реализацию задержки в задачах:
Изменённый example.c
#include <FreeRTOS.h> #include <task.h> #include <queue.h> #include <stdio.h> #include "riscv-virt.h" #include "ns16550.h" #define exampleDELAY pdMS_TO_TICKS( 1000 ) #define exampleTASK_PRIORITY ( tskIDLE_PRIORITY + 1 ) void vTask1( void *pvParameters ) { const char *pcMessage = "Task 1 is running"; TickType_t xNextWakeTime; xNextWakeTime = xTaskGetTickCount(); for( ;; ) { vSendString( pcMessage ); vTaskDelayUntil( &xNextWakeTime, exampleDELAY ); } } void vTask2( void *pvParameters ) { const char *pcMessage = "Task 2 is running"; volatile unsigned long ul; TickType_t xNextWakeTime; xNextWakeTime = xTaskGetTickCount(); for( ;; ) { vSendString( pcMessage ); vTaskDelayUntil( &xNextWakeTime, exampleDELAY ); } } int main_example( void ) { xTaskCreate( vTask1, "Task 1", configMINIMAL_STACK_SIZE * 2U, NULL, exampleTASK_PRIORITY, NULL ); xTaskCreate( vTask2, "Task 2", configMINIMAL_STACK_SIZE * 2U, NULL, exampleTASK_PRIORITY + 1, NULL ); vTaskStartScheduler(); return 0; }
Запустив изменённую версию, получим следующий вывод:
Task 2 is running Task 1 is running Task 2 is running Task 1 is running Task 2 is running Task 1 is running Task 2 is running Task 1 is running Task 2 is running Task 1 is running Task 2 is running Task 1 is running Task 2 is running Task 1 is running Task 2 is running Task 1 is running Task 2 is running Task 1 is running Task 2 is running Task 1 is running Task 2 is running Task 1 is running
Теперь задачи выполняются поочерёдно. Что изменилось?
Дело в том, что в первом случае задержка активная, то есть задача остаётся в состоянии running. При завершении цикла Task2 переходит в состояние ready, как и задача с меньшим приоритетом, и планировщик снова выбирает для выполнения задачу с большим приоритетом.
Во втором случае для задержки вызывается функция vTaskDelayUntil, переводящая задачу в состояние blocked, позволяя выполнится задаче с меньшим приоритетом.