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(), сама задача удаляется, и освобождается соответствующее пространство стека , который необходимо освободить во время выполнения бездействующей задачи.
Примечание. Независимо от того, в каком состоянии находится удаленная задача, после выполнения функции удаления она сразу исчезнет из очереди.