目录
注意:使用时间片调度需把宏 configUSE_TIME_SLICING 和 configUSE_PREEMPTION 置1
前言
其实在网上已经有很多相关的博文了,不过我还是决定自己动手来记录一下。按照之前的经验,需要达到的目的为切题,详细。否则回看的时候不清楚。好多,整理的好累。
动态创建任务函数原型
BaseType_t xTaskCreate
( TaskFunction_t pxTaskCode, /* 指向任务函数的指针 */
const char * const pcName, /* 任务名字,最大长度configMAX_TASK_NAME_LEN */
const configSTACK_DEPTH_TYPE usStackDepth, /* 任务堆栈大小,注意字为单位 */
void * const pvParameters, /* 传递给任务函数的参数 */
UBaseType_t uxPriority, /* 任务优先级,范围:0 ~ configMAX_PRIORITIES - 1 */
TaskHandle_t * const pxCreatedTask /* 任务句柄,就是任务的任务控制块 */
)
返回值 | 描述 |
pdPASS | 任务创建成功 |
errCOULD_NOT_ALLOCATE_REQUIRED_MEMORY | 任务创建失败 |
动态创建任务函数使用范例
将宏configSUPPORT_DYNAMIC_ALLOCATION 配置为 1
//任务优先级
#define START_TASK_PRIO 1
//任务堆栈大小
#define START_STK_SIZE 128
//任务句柄
TaskHandle_t StartTask_Handler;
//任务函数
void start_task(void *pvParameters);
//创建开始任务
xTaskCreate((TaskFunction_t )start_task, //任务函数
(const char* )"start_task", //任务名称
(uint16_t )START_STK_SIZE, //任务堆栈大小
(void* )NULL, //传递给任务函数的参数
(UBaseType_t )START_TASK_PRIO, //任务优先级
(TaskHandle_t* )&StartTask_Handler); //任务句柄
//开始任务任务函数
void start_task(void *pvParameters)
{
taskEXIT_CRITICAL(); //退出临界区
//代码执行逻辑
taskENTER_CRITICAL(); //进入临界区
}
静态创建函数原型
TaskHandle_t xTaskCreateStatic(
TaskFunction_t pxTaskCode, /* 指向任务函数的指针 */
const char *const pcName, /* 任务函数名 */
const uint32_t ulStackDepth, /* 任务堆栈大小注意字为单位 */
void *const pvParameters, /* 传递的任务函数参数 */
UBaseType_t uxPriority, /* 任务优先级 */
StackType_t *const puxStackBuffer, /* 任务堆栈,一般为数组,由用户分配 */
StaticTask_t *const pxTaskBuffer /* 任务控制块指针,由用户分配 */
);
返回值 | 描述 |
NULL | 用户没有提供相应的内存,任务创建失败 |
其他值 | 任务句柄,任务创建成功 |
静态创建任务函数使用范例
不全,有点多,先放着静态的
#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); // 任务函数
// 创建开始任务
StartTask_Handler = xTaskCreateStatic((TaskFunction_t)start_task, // 任务函数
(const char *)"start_task", // 任务名称
(uint32_t)START_STK_SIZE, // 任务堆栈大小
(void *)NULL, // 传递给任务函数的参数
(UBaseType_t)START_TASK_PRIO, // 任务优先级
(StackType_t *)StartTaskStack, // 任务堆栈
(StaticTask_t *)&StartTaskTCB); // 任务控制块 // 开启任务调度
// 开始任务任务函数
void start_task(void *pvParameters)
{
taskENTER_CRITICAL(); // 进入临界区
// 创建TASK1任务
taskEXIT_CRITICAL(); // 退出临界区
}
任务删除函数原型
void vTaskDelete(TaskHandle_t xTaskToDelete);
形参 | 描述 |
xTaskToDelete | 待删除任务的任务句柄 |
任务删除函数使用范例
vTaskDelete(Task2Task_Handler);
这里调用这个函数的话,只需要传入需要删除的函数句柄就好了。这里的Task2Task_Handler只是为了进行演示使用的,大家可以根据自己的实际情况调整。以后这种只需要传入单个参数且参数为任务句柄同时无返回值时就不再写使用范例了,大家看到这里应该都是有基础的。
2、任务挂起和恢复函数
任务挂起函数原型
void vTaskSuspend(TaskHandle_t xTaskToSuspend)
形参 | 描述 |
xTaskToSuspend | 待挂起任务的任务句柄 |
此函数用于挂起任务,使用时需将宏 INCLUDE_vTaskSuspend 配置为 1。
无论优先级如何,被挂起的任务都将不再被执行,直到任务被恢复 。
注意:当传入的参数为NULL,则代表挂起任务自身(当前正在运行的任务)
任务恢复函数(任务中恢复)原型
void vTaskResume(TaskHandle_t xTaskToResume)
形参 | 描述 |
xTaskToResume | 待恢复任务的任务句柄 |
使用该函数注意宏:INCLUDE_vTaskSuspend必须定义为 1
注意:任务无论被 vTaskSuspend() 挂起多少次,只需在任务中调用 vTakResume() 恢复一次,就可以继续运行。且被恢复的任务会进入就绪态!
任务恢复函数(中断中恢复)原型
BaseType_t xTaskResumeFromISR(TaskHandle_t xTaskToResume)
形参 | 描述 |
xTaskToResume | 待恢复任务的任务句柄 |
函数:xTaskResumeFromISR返回值描述如下:
返回值 | 描述 |
pdTRUE | 任务恢复后需要进行任务切换 |
pdFALSE | 任务恢复后不需要进行任务切换 |
使用该函数注意宏:INCLUDE_vTaskSuspend 和 INCLUDE_xTaskResumeFromISR 必须定义为 1
该函数专用于中断服务函数中,用于解挂被挂起任务
注意:中断服务程序中要调用freeRTOS的API函数则中断优先级不能高于FreeRTOS所管理的最高优先级
任务恢复函数(中断中恢复)使用范例
#include <Arduino_FreeRTOS.h>
TaskHandle_t xTaskToResume = NULL;
void MyInterruptHandler(void)
{
BaseType_t xHigherPriorityTaskWoken = pdFALSE;
// 尝试从 ISR 中恢复任务,这里注入的参数为函数句柄就可以了
xHigherPriorityTaskWoken = xTaskResumeFromISR(xTaskToResume);
// 如果需要,请求上下文切换,因为这个时候被恢复的任务优先级可能比正在执行地任务优先级更高。
portYIELD_FROM_ISR(xHigherPriorityTaskWoken);
}
void setup()
{
// 初始化任务、中断等
// 将中断处理函数与相应的中断连接
attachInterrupt(digitalPinToInterrupt(2), MyInterruptHandler, RISING);
}
void loop()
{
// Empty. Things are done in tasks.
}
任务恢复和挂起函数总结
3、临界区的代码保护函数
应用场景:FreeRTOS在进入临界段代码的时候需要关闭中断,当处理完临界段代码以后再打开中断
任务级进入和退出临界段函数原型
函数 | 描述 |
taskENTER_CRITICAL() | 任务级进入临界段 |
taskEXIT_CRITICAL() | 任务级退出临界段 |
任务级进入和退出临界段函数使用范例
taskENTER_CRITICAL() ;
{
… … /* 临界区 */
}
taskEXIT_CRITICAL() ;
中断级进入和退出临界段函数原型
函数 | 描述 |
taskENTER_CRITICAL_FROM_ISR() | 中断级进入临界段 |
taskEXIT_CRITICAL_FROM_ISR() | 中断级退出临界段 |
中断级进入和退出临界段函数使用范例
uint32_t save_status;
save_status = taskENTER_CRITICAL_FROM_ISR();
{
… … /* 临界区 */
}
taskEXIT_CRITICAL_FROM_ISR(save_status );
4、任务调度器的挂起和恢复
挂起任务调度器, 调用此函数仅仅只是防止了任务间的资源争夺,中断照样可以响应。挂起调度器的防止,适用于临界区位于任务与任务之间。这样既不会延时中断,又可以做到临界区安全。
任务调度器的挂起和恢复函数原型
函数 | 描述 |
vTaskSuspendAll() | 挂起任务调度器 |
xTaskResumeAll() | 恢复任务调度器 |
任务调度器的挂起和恢复函数的使用范例
vTaskSuspendAll() ;
{
… … /* 内容 */
}
xTaskResumeAll() ;
5、列表
6、任务调度器的开启
开启任务调度器函数原型
vTaskStartScheduler()
prvStartFirstTask () /* 开启第一个任务 */
vPortSVCHandler () /* SVC中断服务函数 */
7、时间片调度配置
注意:使用时间片调度需把宏 configUSE_TIME_SLICING 和 configUSE_PREEMPTION 置1
8、Freertos任务相关API函数
获取任务优先级的函数原型
UBaseType_t uxTaskPriorityGet( const TaskHandle_t xTask )
此函数用于获取指定任务的任务优先级,使用该函数需将宏 INCLUDE_uxTaskPriorityGet 置 1
形参 | 描述 |
xTask | 要查找的任务句柄,NULL代表任务自身 |
返回值 | 描述 |
整数 | 任务优先级数值 |
获取任务优先级函数优先级的函数使用范例
// 创建任务并获取任务句柄
xTaskCreate(Task1, "Task1", 100, NULL, 1, &xTaskHandle);
// 获取任务的优先级并输出
UBaseType_t priority = uxTaskPriorityGet(xTaskHandle);
改变某个任务的任务优先级函数原型
void vTaskPrioritySet( TaskHandle_t xTask , UBaseType_t uxNewPriority )
此函数用于改变某个任务的任务优先级,使用该函数需将宏 INCLUDE_vTaskPrioritySet 为 1
xTask | 任务句柄,NULL代表任务自身 |
uxNewPriority | 需要设置的任务优先级 |
改变某个任务的任务优先级函数原型的使用范例
// 定义任务句柄
TaskHandle_t xTask1Handle, xTask2Handle;
// 创建任务2
xTaskCreate(vTask2, "Task 2", configMINIMAL_STACK_SIZE, NULL, 2, &xTask2Handle);
vTaskPrioritySet(xTask2Handle, 3); // 将任务2的优先级设置为3
获取系统中任务数量的API函数原型
UBaseType_t uxTaskGetNumberOfTasks( void )
形参 | 描述 |
xTask | 任务句柄,NULL代表任务自身 |
uxNewPriority | 需要设置的任务优先级 |
获取系统中任务数量的API函数使用范例
// 获取当前活动任务的数量并输出
UBaseType_t numTasks = uxTaskGetNumberOfTasks();
获取所有任务状态信息函数原型
UBaseType_t uxTaskGetSystemState( TaskStatus_t * const pxTaskStatusArray,
const UBaseType_t uxArraySize,
configRUN_TIME_COUNTER_TYPE * const pulTotalRunTime )
此函数用于获取系统中所有任务的任务状态信息,使用该函数需将宏 configUSE_TRACE_FACILITY 置 1
形参 | 描述 |
xTaskStatusArray | 指向TaskStatus_t 结构体数组首地址 |
uxArraySize | 接收信息的数组大小 |
pulTotalRunTime | 系统总运行时间,为NULL 则省略总运行时间值 |
形参 | 描述 |
xTaskStatusArray | 指向TaskStatus_t 结构体数组首地址 |
获取所有任务状态信息函数原型使用范例
#include <FreeRTOS.h>
#include <task.h>
#define TASKS_ARRAY_SIZE 10
TaskHandle_t xTask1Handle, xTask2Handle;
void vTask1(void *pvParameters) {
// 任务1的代码
while(1) {
// 执行任务1的操作
}
}
void vTask2(void *pvParameters) {
// 任务2的代码
while(1) {
// 执行任务2的操作
}
}
void main(void) {
TaskStatus_t xTaskStatusArray[TASKS_ARRAY_SIZE];
UBaseType_t uxArraySize;
// 创建任务1
xTaskCreate(vTask1, "Task 1", configMINIMAL_STACK_SIZE, NULL, 1, &xTask1Handle);
// 创建任务2
xTaskCreate(vTask2, "Task 2", configMINIMAL_STACK_SIZE, NULL, 2, &xTask2Handle);
// 启动任务调度器
vTaskStartScheduler();
// 获取系统中所有任务的状态信息
uxArraySize = uxTaskGetSystemState(xTaskStatusArray, TASKS_ARRAY_SIZE, NULL);
// 打印任务状态信息
for (UBaseType_t i = 0; i < uxArraySize; i++) {
printf("Task Name: %s, Priority: %d, State: %d\n",
xTaskStatusArray[i].pcTaskName,
xTaskStatusArray[i].uxCurrentPriority,
xTaskStatusArray[i].eCurrentState);
}
// 任务调度器不会返回,除非发生错误
for(;;);
}
这里想要提取哪些信息的话需要根据结构体的成员变量改变
typedef struct xTASK_STATUS
{
TaskHandle_t xHandle; //任务句柄
const char * pcTaskName; //任务名字
UBaseType_t xTaskNumber; //任务编号
eTaskState eCurrentState; //当前任务壮态, eTaskState 是一个枚举类型
UBaseType_t uxCurrentPriority; //任务当前的优先级
UBaseType_t uxBasePriority; //任务基础优先级
uint32_t ulRunTimeCounter;//任务运行的总时间
StackType_t * pxStackBase; //堆栈基地址
uint16_t usStackHighWaterMark;//从任务创建以来任务堆栈剩余的最小大小,此
//值如果太小的话说明堆栈有溢出的风险。
} TaskStatus_t;
获取单个任务的状态信息原型
void vTaskGetInfo(
FTaskHandle_t xTask,
TaskStatus_t *pxTaskStatus,
BaseType_t xGetFreeStackSpace,
eTaskState eState)
形参 | 描述 |
xTask | 指定获取信息的任务的句柄 |
pxTaskStatus | 接收任务信息的变量 |
xGetFreeStackSpace | 任务栈历史剩余最小值, 当为“pdFALSE” 则跳过这个步骤, 当为“pdTRUE”则检查历史剩余最小堆栈 |
eState | 任务状态,可直接赋值,如想获取代入“eInvalid” |
获取单个任务的状态信息使用范例
TaskStatus_t xTaskStatus;
// 创建一个任务
TaskHandle_t xTaskHandle;
xTaskCreate(vTaskFunction, "Task", configMINIMAL_STACK_SIZE, NULL, 1, &xTaskHandle);
// 获取任务的信息
vTaskGetInfo(xTaskHandle, &xTaskStatus, pdFALSE, eRunning);
// 打印任务的状态信息
printf("Task Name: %s\n", xTaskStatus.pcTaskName);
printf("Task Priority: %d\n", xTaskStatus.uxCurrentPriority);
printf("Task State: %d\n", xTaskStatus.eCurrentState);
直接获取当前任务的任务句柄函数原型
TaskHandle_t xTaskGetCurrentTaskHandle( void )
此函数用于获取当前任务的任务句柄, 使用该函数需将INCLUDE_xTaskGetCurrentTaskHandle 置 1
返回值 | 描述 |
TaskHandle_t | 当前任务的任务句柄 |
直接获取当前任务的任务句柄函数使用范例
TaskHandle_t xTaskHandle;
// 获取当前任务的句柄
xTaskHandle = xTaskGetCurrentTaskHandle();
// 打印当前任务的句柄
printf("Current Task Handle: %p\n", xTaskHandle);
通过任务名获取任务句柄函数原型
TaskHandle_t xTaskGetHandle(const char * pcNameToQuery);
通过任务名获取任务句柄函数使用范例
void main(void) {
TaskHandle_t xTaskHandle;
// 创建一个任务
xTaskCreate(vTaskFunction, "Task1", configMINIMAL_STACK_SIZE, NULL, 1, &xTaskHandle);
// 获取任务句柄
TaskHandle_t xTaskHandle2 = xTaskGetHandle("Task1");
// 检查句柄是否有效
if (xTaskHandle2 != NULL) {
printf("Task1 handle: %p\n", xTaskHandle2);
} else {
printf("Task1 not found!\n");
}
for (;;) {
// 主循环
}
}
标签:优先级,函数,FreeRTOS,句柄,void,特特特,任务,API,原型
From: https://blog.csdn.net/qq_51519091/article/details/137223338