Опубликован: 24.11.2024 | Доступ: свободный | Студентов: 1 / 0 | Длительность: 03:11:00
Лекция 9:

Лабораторная работа

< Лекция 8 || Лекция 9: 12

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, позволяя выполнится задаче с меньшим приоритетом.

< Лекция 8 || Лекция 9: 12