FreeRTOS (1) ---- Динамическое и статическое создание задач, удаление задач

1. Статическое создание задач

1. Создайте задачу бездействия

Задача бездействия: она автоматически генерируется ядром при включении планировщика задач freertos , гарантируя, что в системе выполняется хотя бы одна задача.

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

После завершения функции удаления задачи бездействующая задача автоматически освобождает место в памяти, выделенное задачей удаления . Объяснение: Когда другие запущенные задачи выполняются с помощью vTaskDelay(); эта функция, простаивающая задача может быть отключена, а пространство памяти, выделенное задачей удаления, может быть освобождено.

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

static StackType_t  IdleTaskStack[configMINIMAL_STACK_SIZE];        /* 空闲任务任务堆栈 */
static StaticTask_t IdleTaskTCB;                                    /* 空闲任务控制块 */


/**
 * @brief       获取空闲任务地任务堆栈和任务控制块内存,因为本例程使用的
                静态内存,因此空闲任务的任务堆栈和任务控制块的内存就应该
                有用户来提供,FreeRTOS提供了接口函数vApplicationGetIdleTaskMemory()
                实现此函数即可。
 * @param       ppxIdleTaskTCBBuffer:任务控制块内存
                ppxIdleTaskStackBuffer:任务堆栈内存
                pulIdleTaskStackSize:任务堆栈大小
 * @retval      无
 */
void vApplicationGetIdleTaskMemory(StaticTask_t **ppxIdleTaskTCBBuffer, 
                                   StackType_t  **ppxIdleTaskStackBuffer, 
                                   uint32_t     *pulIdleTaskStackSize)
{
    *ppxIdleTaskTCBBuffer   = &IdleTaskTCB;
    *ppxIdleTaskStackBuffer = IdleTaskStack;
    *pulIdleTaskStackSize   = configMINIMAL_STACK_SIZE;
}

2. Системные настройки

Должен находиться в файле FreeRTOSconfig.h 

#define configSUPPORT_STATIC_ALLOCATION                 1                       
/* 1: 支持静态申请内存, 默认: 0 */

3. Создавайте задачи

/* START_TASK 任务 配置
 * 包括: 任务句柄 任务优先级 堆栈大小 创建任务
 */
#define START_TASK_PRIO 1                   /* 任务优先级 */
#define START_STK_SIZE  128                 /* 任务堆栈大小 */
StackType_t StartTaskStack[START_STK_SIZE]; /* 任务堆栈 */
StaticTask_t            StartTaskTCB;       /* 任务控制块 */
TaskHandle_t            StartTask_Handler;  /* 任务句柄 */
void start_task(void *pvParameters);        /* 任务函数 */

Приоритет задачи: есть пять типов приоритета в freertos 0-4, но общий выбор - группа 4, всего 2^4-1, потому что не нужно учитывать подприоритет, это намного удобнее ,просто нужно вытеснить приоритет Размер уровня напрямую определяет вытеснение задачи.Чем меньше значение приоритета задачи фриртоса,тем ниже приоритет задачи.

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

Блок управления задачей (TCB): в нем хранится вся информация, соответствующая задаче (указатель стека, имя задачи, формальные параметры задачи и т. д.), а блок управления задачей эквивалентен идентификационной карте задачи. Когда происходит прерывание, TCB сохраняет в это время различную информацию, такую ​​как прерывание, регистры и указатели.Когда прерывание заканчивается и задача выполняется снова, она начинает выполнение непосредственно с информации, хранящейся в TCB.

Дескриптор задачи: это вторичный указатель, который указывает на первый адрес соответствующего созданного TCB.Если это сама операция, вход может быть NULL.

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

void start_task(void *pvParameters)
{
    taskENTER_CRITICAL();           /* 进入临界区 */
    /* 创建任务1 */
    Task1Task_Handler = xTaskCreateStatic((TaskFunction_t   )task1,         /* 任务函数 */
                                          (const char*      )"task1",       /* 任务名称 */
                                          (uint32_t         )TASK1_STK_SIZE,/* 任务堆栈大小 */
                                          (void*            )NULL,          /* 传递给任务函数的参数 */
                                          (UBaseType_t      )TASK1_PRIO,    /* 任务优先级 */
                                          (StackType_t*     )Task1TaskStack,/* 任务堆栈 */
                                          (StaticTask_t*    )&Task1TaskTCB);/* 任务控制块 */
    /* 创建任务2 */
    Task2Task_Handler = xTaskCreateStatic((TaskFunction_t   )task2,         /* 任务函数 */
                                          (const char*      )"task2",       /* 任务名称 */
                                          (uint32_t         )TASK2_STK_SIZE,/* 任务堆栈大小 */
                                          (void*            )NULL,          /* 传递给任务函数的参数 */
                                          (UBaseType_t      )TASK2_PRIO,    /* 任务优先级 */
                                          (StackType_t*     )Task2TaskStack,/* 任务堆栈 */
                                          (StaticTask_t*    )&Task2TaskTCB);/* 任务控制块 */
    /* 创建任务3 */
    Task3Task_Handler = xTaskCreateStatic((TaskFunction_t   )task3,         /* 任务函数 */
                                          (const char*      )"task3",       /* 任务名称 */
                                          (uint32_t         )TASK3_STK_SIZE,/* 任务堆栈大小 */
                                          (void*            )NULL,          /* 传递给任务函数的参数 */
                                          (UBaseType_t      )TASK3_PRIO,    /* 任务优先级 */
                                          (StackType_t*     )Task3TaskStack,/* 任务堆栈 */
                                          (StaticTask_t*    )&Task3TaskTCB);/* 任务控制块 */
    vTaskDelete(StartTask_Handler); /* 删除开始任务 */
    taskEXIT_CRITICAL();            /* 退出临界区 */
}

4. Планирование задач 

vTaskStartScheduler();

Freertos — это не что иное, как четыре состояния: рабочее состояние, состояние готовности, заблокированное состояние, приостановленное состояние.

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

Состояние готовности: задача может быть выполнена и готова к выполнению, но текущий ЦП выполняет другие задачи, а эта задача еще не выполнена.

Заблокированное состояние: задача переходит в заблокированное состояние из-за задержки или прерывания.

Состояние приостановки: приостановить выполнение текущей функции. Чтобы вызвать функцию vTaskSuspend() для входа в состояние приостановки, вызовите vTaskResume() для отмены приостановки и перехода в состояние готовности.

Два метода планирования для freertos:

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

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

5. Критическая секция

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

2. Создавайте задачи динамически

1. Конфигурация системы

#define configSUPPORT_STATIC_ALLOCATION                 0                       /* 1: 支持静态申请内存, 默认: 0 */
#define configSUPPORT_DYNAMIC_ALLOCATION                1                       /* 1: 支持动态申请内存, 默认: 1 */

Отличие: поскольку задача создается динамически, пространство стека выделяется ядром freertos, поэтому вам нужно только установить дескриптор задачи так, чтобы он указывал на первый адрес блока управления задачей TCB.

 xTaskCreate((TaskFunction_t )task1,                 /* 任务函数 */
 (const char*    )"task1",               /* 任务名称 */
 (uint16_t       )TASK1_STK_SIZE,        /* 任务堆栈大小 */
 (void*          )NULL,                  /* 传入给任务函数的参数 */
 (UBaseType_t    )TASK1_PRIO,            /* 任务优先级 */
 (TaskHandle_t*  )&Task1Task_Handler);   /* 任务句柄 */

Остальная конфигурация такая же, как и у статически назначенных задач.

3. Удалить задачу

#define INCLUDE_vTaskDelete                             1                       /* 删除任务 */

Чтобы удалить задачу, вам нужно только удалить дескриптор задачи соответствующей задачи.Как упоминалось выше, TCB представляет собой указатель первого уровня и выделенное пространство памяти, в котором хранится вся информация, такая как положение указателя и регистры каждой задачи. Дескриптор задачи — это вторичный указатель, указывающий на первый адрес TCB. Таким образом, соответствующую задачу можно найти через дескриптор задачи.

vTaskDelete(задача)

Когда вам нужно удалить другие задачи в задаче, непосредственно задача == дескриптор задачи соответствующей задачи, удалить себя, задача == NULL, при выполнении vTaskDelete(), сама задача удаляется, и освобождается соответствующее пространство стека , который необходимо освободить во время выполнения бездействующей задачи.

Примечание. Независимо от того, в каком состоянии находится удаленная задача, после выполнения функции удаления она сразу исчезнет из очереди.

Guess you like

Origin blog.csdn.net/weixin_63032791/article/details/130675692