FreeRTOS任务相关API简介
FreeRTOS任务相关API简介
- 前言
- 任务的创建和删除
- 动态创建任务(xTaskCreate)
- 参数说明
- 示例代码
- 特点
- 静态创建任务(xTaskCreateStatic)
- 参数说明
- 示例代码
- 特点
- 受MPU保护的任务(xTaskCreateRestricted)
- 参数说明
- 任务定义结构体 TaskParameters_t
- 示例代码
- 注意事项
- 删除任务(vTaskDelete)
- 参数说明
- 注意事项
- 函数执行流程
- 任务的挂起和恢复
- vTaskSuspend()
- vTaskResume()
- xTaskResumeFromISR()
- 使用场景示例
- 注意事项
前言
本文介绍了几个常用的FreeRTOS任务相关的API,列举了任务的创建、删除,挂起和恢复的API,并介绍了函数功能、入参等信息。专为初学者入门而写。希望可以给大家带来帮助。
任务的创建和删除
下面简介各种任务创建API和任务删除API:
函数 | 描述 |
---|---|
xTaskCreat() | 使用动态的方法创建一个任务 |
xTaskCreatStatic() | 使用静态的方法创建一个任务 |
xTaskCreatRestricted() | 创建一个使用MPU进行限制的任务,使用动态内存分配此任务使用的内存 |
vTaskDelet() | 删除一个任务 |
动态创建任务(xTaskCreate)
使用此API创建的任务,会自动从FreeRTOS的堆里面分配RAM空间,来存储任务控制块(TCB
)和任务堆栈。所以在使用之前要确保内存管理文件在工程中被使用,并且确保下面这个宏的值是1:
#define configSUPPORT_DYNAMIC_ALLOCATION 1
另外,此API创建的任务默认处于就绪态,所有处于就绪态的任务,按照优先级的高低以此执行。在惹怒我调度器启动前后都可以调用此API创建任务。函数原型如下:
BaseType_t xTaskCreate(TaskFunction_t pvTaskCode, // 任务函数指针const char * const pcName, // 任务名称unsigned short usStackDepth, // 任务栈大小(单位:字,4字节)void *pvParameters, // 传递给任务函数的参数UBaseType_t uxPriority, // 任务优先级TaskHandle_t * const pxCreatedTask // 任务句柄
);
参数说明
参数名 | 类型 | 说明 |
---|---|---|
pvTaskCode | TaskFunction_t | 任务的入口函数,即任务函数的地址。 |
pcName | const char * const | 任务的名称,用于调试时识别任务。最大长度由configMAX_TASK_NAME_LEN 定义。 |
usStackDepth | unsigned short | 任务栈的大小,单位为字(4字节)。建议根据任务需求合理设置。 |
pvParameters | void * | 传递给任务函数的参数,可以是任意类型的数据。 |
uxPriority | UBaseType_t | 任务的优先级,数值越小,优先级越高。 |
pxCreatedTask | TaskHandle_t * | 用于返回任务的句柄,以便后续操作任务。 |
示例代码
xTaskCreate((TaskFunction_t)start_task, // 任务函数"start_task", // 任务名称1024, // 任务栈大小NULL, // 任务参数tskIDLE_PRIORITY, // 任务优先级&StartTask_Handler); // 任务句柄
特点
- 适用于大多数应用场景,系统自动管理内存。
- 任务创建后,内存可以被系统回收。
- 适合任务数量较多或内存动态分配的场景。
静态创建任务(xTaskCreateStatic)
静态创建任务需要用户手动分配任务栈空间和任务控制块(TCB),通常用于对内存使用有严格要求的嵌入式系统。该函数的原型如下:
BaseType_t xTaskCreateStatic(TaskFunction_t pvTaskCode, // 任务函数指针const char * const pcName, // 任务名称uint16_t usStackDepth, // 任务栈大小void *pvParameters, // 任务参数UBaseType_t uxPriority, // 任务优先级StaticTask_t *pxTaskBuffer, // 任务控制块StackType_t *pxStackBuffer, // 任务栈TaskHandle_t * const pxCreatedTask // 任务句柄
);
参数说明
参数名 | 类型 | 说明 |
---|---|---|
pvTaskCode | TaskFunction_t | 任务的入口函数。 |
pcName | const char * const | 任务名称,用于调试。 |
usStackDepth | uint16_t | 任务栈的大小,单位为字(4字节)。 |
pvParameters | void * | 传递给任务函数的参数。 |
uxPriority | UBaseType_t | 任务的优先级。 |
pxTaskBuffer | StaticTask_t * | 任务控制块的地址,用于存储任务的TCB信息。 |
pxStackBuffer | StackType_t * | 任务栈的地址,用于存储任务的运行上下文。 |
pxCreatedTask | TaskHandle_t * | 任务句柄,用于返回任务的句柄。 |
示例代码
StaticTask_t xTaskBuffer;
StackType_t xStack[1024];xTaskCreateStatic((TaskFunction_t)start_task, // 任务函数"start_task", // 任务名称1024, // 任务栈大小NULL, // 任务参数tskIDLE_PRIORITY, // 任务优先级&xTaskBuffer, // 任务控制块xStack, // 任务栈&StartTask_Handler); // 任务句柄
特点
- 需要用户手动分配任务栈和控制块,适合对内存使用有严格要求的场景。
- 任务创建后,内存不会被系统回收,需手动管理。
- 适合任务数量较少或内存有限的嵌入式系统。
在实际开发中,动态创建任务是最常用的方式,因为它简化了内存管理,而静态创建任务则适用于对内存使用有严格要求的嵌入式系统。根据具体需求选择合适的任务创建方式,可以提高系统的效率和稳定性。
受MPU保护的任务(xTaskCreateRestricted)
xTaskCreateRestricted
是 FreeRTOS 提供的一个用于创建受内存保护单元(MPU)保护的任务的函数。它允许在具有 MPU 的 MCU 上创建任务,并对任务的内存访问进行限制。该函数的功能与 xTaskCreate()
类似,但增加了对 MPU 的支持,适用于需要保护任务内存的场景。函数原型如下:
BaseType_t xTaskCreateRestricted(const TaskParameters_t * const pxTaskDefinition,TaskHandle_t * const pxCreatedTask
);
参数说明
参数名 | 类型 | 说明 |
---|---|---|
pxTaskDefinition | const TaskParameters_t * const | 指向任务定义结构体的指针,包含任务的函数、名称、堆栈大小、参数、优先级等信息。 |
pxCreatedTask | TaskHandle_t * const | 用于返回创建任务的句柄,以便后续操作任务。 |
任务定义结构体 TaskParameters_t
TaskParameters_t
是一个包含任务所有必要信息的结构体,通常包括以下字段:
pvTaskCode
:任务函数指针。pcName
:任务名称。usStackDepth
:任务栈大小。pvParameters
:传递给任务的参数。uxPriority
:任务优先级。xRegions
:内存区域定义,用于 MPU 保护。
示例代码
以下是一个使用 xTaskCreateRestricted
创建受 MPU 保护任务的示例代码:
#include "FreeRTOS.h"
#include "task.h"// 定义任务参数结构体
typedef struct {TaskFunction_t pvTaskCode;const char * const pcName;unsigned short usStackDepth;void *pvParameters;UBaseType_t uxPriority;const MemoryRegion_t * const xRegions;
} TaskParameters_t;// 任务函数
void vMyTask(void *pvParameters) {// 任务代码while (1) {// 任务逻辑}
}// 任务定义
TaskParameters_t xTaskDefinition = {.pvTaskCode = vMyTask,.pcName = "MyTask",.usStackDepth = 1024,.pvParameters = NULL,.uxPriority = tskIDLE_PRIORITY,.xRegions = NULL // 可以定义 MPU 保护区域
};// 创建任务
TaskHandle_t xTaskHandle;int main() {// 创建任务if (xTaskCreateRestricted(&xTaskDefinition, &xTaskHandle) != pdPASS) {// 任务创建失败}// 启动调度器vTaskStartScheduler();// 任务创建成功后,进入死循环for (;;);
}
注意事项
- MPU 支持:
xTaskCreateRestricted
仅在 FreeRTOS-MPU 环境下可用,因此需要在FreeRTOSConfig.h
中启用configSUPPORT_DYNAMIC_ALLOCATION
。 - 内存分配:该函数使用动态内存分配来创建任务的控制块和栈空间。
- 任务删除:使用
vTaskDelete()
删除任务时,需要提供任务的句柄和任务控制块的地址。
vTaskDelete
是 FreeRTOS 中用于删除任务的函数,其主要功能是将指定任务从系统中移除,并释放其占用的资源。以下是关于该函数的详细说明:
删除任务(vTaskDelete)
vTaskDelete
用于删除一个已创建的任务。该函数会从任务的就绪列表、阻塞列表、挂起列表和事件列表中移除该任务,并释放其任务控制块(TCB)和堆栈内存。需要注意的是,空闲任务(Idle Task)负责释放由系统分配的内存,而用户分配的内存需要在任务删除前手动释放,否则可能导致内存泄漏 。
void vTaskDelete(TaskHandle_t xTaskToDelete);
参数说明
xTaskToDelete
:要删除的任务的句柄。若传入NULL
,则表示删除当前正在运行的任务(即调用该函数的任务)。
注意事项
- 必须在
FreeRTOSConfig.h
中启用INCLUDE_vTaskDelete
,否则该函数不可用。 - 删除任务时,需确保空闲任务有足够时间执行内存释放。通常,将空闲任务的优先级设置为最低,以避免内存泄漏 。
- 删除任务后,系统会将该任务添加到“待删除列表” ,由空闲任务在下次运行时进行清理 。
函数执行流程
- 检查任务句柄:若
xTaskToDelete
为NULL
,则删除当前任务。 - 从任务列表中移除:将任务从就绪、阻塞、挂起和事件列表中移除。
- 更新任务状态:更新任务优先级记录,并递增
uxTaskNumber
以通知内核调试器重新生成任务列表。 - 释放内存:
- 若删除的是当前任务,将其插入“待删除列表”,并增加
uxDeletedTasksWaitingCleanUp
变量。 - 若删除的是其他任务,调用
prvDeleteTCB()
函数释放任务的 TCB 和堆栈内存。
- 若删除的是当前任务,将其插入“待删除列表”,并增加
- 强制任务切换:若删除的是当前任务,调用
portPRE_TASK_DELETE_HOOK
钩子函数,并执行任务切换 。
任务的挂起和恢复
在 FreeRTOS 中,任务的挂起和恢复是通过一系列 API 函数实现的。这些函数允许开发人员在需要暂停任务执行时将其挂起,并在需要时恢复任务的运行。以下是主要的挂起和恢复 API 函数及其功能说明:
API 函数 | 功能描述 | 说明 |
---|---|---|
vTaskSuspend(TaskHandle_t xTaskToSuspend) | 挂起指定任务 | 将任务设置为挂起状态,任务将永远处于挂起状态,除非调用 vTaskResume() 或 xTaskResumeFromISR() 。 |
vTaskResume(TaskHandle_t xTaskToResume) | 恢复挂起任务 | 将任务从挂起状态恢复到就绪状态,如果此时被恢复任务的优先级高于正在运行任务的优先级,则会发生任务切换 。 |
xTaskResumeFromISR(TaskHandle_t xTaskToResume) | 在中断服务函数中恢复任务 | 用于在中断服务函数中恢复任务,返回值指示是否需要进行上下文切换 。 |
vTaskSuspend()
- 功能:将指定任务设置为挂起状态。
- 参数:
xTaskToSuspend
是要挂起的任务句柄。如果传入NULL
,则表示挂起当前任务。 - 特点:一旦任务被挂起,它将永远处于挂起状态,直到被显式恢复。
vTaskResume()
- 功能:将挂起的任务恢复到就绪状态。
- 参数:
xTaskToResume
是要恢复的任务句柄。 - 特点:恢复任务后,任务将重新加入就绪队列,等待调度器调度。如果恢复任务的优先级高于当前运行任务,则会发生任务切换。
xTaskResumeFromISR()
- 功能:在中断服务函数中恢复任务。
- 参数:
xTaskToResume
是要恢复的任务句柄。 - 特点:该函数用于在中断上下文中恢复任务,返回值
pdTRUE
表示需要进行上下文切换,pdFALSE
表示不需要。
使用场景示例
以下是一个简单的示例,展示了如何在按键中断中挂起和恢复任务:
#include "FreeRTOS.h"
#include "task.h"// 任务函数
void vTaskFunction(void *pvParameters) {while (1) {printf("Task is running\n");vTaskDelay(pdMS_TO_TICKS(1000));}
}int main() {TaskHandle_t xTaskHandle = NULL;// 创建任务xTaskCreate(vTaskFunction, "Task", 1024, NULL, tskIDLE_PRIORITY, &xTaskHandle);// 启动调度器vTaskStartScheduler();// 任务创建成功后,进入死循环for (;;);
}
在中断服务函数中,可以使用 vTaskSuspend()
和 xTaskResumeFromISR()
来控制任务的挂起和恢复:
void EXTI0_IRQHandler(void) {if (EXTI_GetITStatus(EXTI_LINE0) != RESET) {printf("Suspend task\n");vTaskSuspend(xTaskHandle); // 挂起任务EXTI_ClearITPendingBit(EXTI_LINE0);}
}void EXTI1_IRQHandler(void) {if (EXTI_GetITStatus(EXTI_LINE1) != RESET) {printf("Resume task\n");xTaskResumeFromISR(xTaskHandle); // 恢复任务EXTI_ClearITPendingBit(EXTI_LINE1);}
}
注意事项
- 任务挂起和恢复的顺序:必须确保在恢复任务之前,任务已经被正确挂起。
- 中断优先级:在中断服务函数中调用
xTaskResumeFromISR()
时,中断优先级不能高于 FreeRTOS 管理的最高优先级,否则可能导致程序异常 。 - 任务状态:挂起的任务不会参与调度,也不会执行任何代码,直到被显式恢复 。
通过合理使用 vTaskSuspend()
、vTaskResume()
和 xTaskResumeFromISR()
,可以有效地管理任务的执行流程,确保任务在需要时暂停或恢复。
本文到此结束,欢迎点赞、转发、收藏!