目录
前言:
一、任务创建与删除的API函数
二、任务挂起与恢复的API函数
总结:
前言:
博客笔记根据正点原子视频教程编辑,仅供学习交流使用!
一、任务创建与删除的API函数
任务的创建和删除的本质就是调用FreeRTOS的API函数,任务创建创建分动态创建和静态创建:
动态创建任务:任务的任务控制块以及任务的栈空间所需的内存,均由 FreeRTOS 从 FreeRTOS 管理的堆中自动分配,不需要人为操作。
静态创建任务:任务的任务控制块以及任务的栈空间所需的内存,需用户分配提供。
①动态创建任务函数
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 /* 任务句柄,就是任务的任务控制块 */
)
注意:任务堆栈大小以字为单位;传递给任务函数的参数通常是空NULL。
动态创建任务实际使用时只有三步:①将宏configSUPPORT_DYNAMIC_ALLOCATION配置为1。②定义函数入口参数。③编写任务函数。
创建之后,任务会立刻进入就绪态,由任务调度器调度运行!
动态创建任务函数内部机理:①申请堆栈内存&任务控制块内存。②TCB结构体成员赋值(TCB就是任务控制块,存储了任务的名字、优先级、状态等信息)。③添加新任务到就序列表。
TCB结构体成员介绍:
typedef struct tskTaskControlBlock
{
volatile StackType_t * pxTopOfStack; /* 任务栈栈顶,必须为TCB的第一个成员(与任务切换密切相关)*/
ListItem_t xStateListItem; /* 任务状态列表项 */
ListItem_t xEventListItem; /* 任务事件列表项 */
UBaseType_t uxPriority; /* 任务优先级,数值越大,优先级越大 */
StackType_t * pxStack; /* 任务栈起始地址 */
char pcTaskName[ configMAX_TASK_NAME_LEN ]; /* 任务名字 */
…
//省略很多条件编译的成员
} tskTCB;
任务栈栈顶,在任务切换时的任务上下文保存、任务恢复紧密相关,必须放在TCB第一个;每个任务都有自己的任务控制块(TCB),类似于身份证。
②静态创建任务函数
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 /* 任务控制块指针,由用户分配 */
);
注意:前五项与动态创建任务函数几乎一样,后两个参数与用户分配有关。
静态创建任务实际使用时只有五步:①将宏configSUPPORT_STATIC_ALLOCATION配置为1。②定义空闲任务&定时器任务的任务堆栈及TCB。③定义两个接口函数:空闲任务内存赋值vApplicationGetIdleTaskMemory( ) 和软件定时器内存赋值vApplicationGetTimerTaskMemory ()。④定义函数入口参数。⑤编写任务函数。
创建之后,任务会立刻进入就绪态,由任务调度器调度运行!
静态创建任务函数内部机理:①TCB结构体成员赋值。②添加新任务到就绪列表。
③删除任务函数
void vTaskDelete(TaskHandle_t xTaskToDelete); /*只有一个入口参数,待删除任务的任务句柄*/
只有创建成功的任务才可被删除,被删除的任务将从就绪态任务列表、阻塞态任务列表、挂起态任务列表和事件列表中移除。
注意:当传入的参数为NULL,则代表删除任务自身(当前正在运行的任务);空闲任务会负责释放被删除任务中由系统分配的内存(动态创建的),但是由用户在任务删除前申请的内存, 则需要由用户在任务被删除前提前释放,否则将导致内存泄露(静态创建的) 。
实际使用只有两步:①使用删除任务函数,需要将宏INCLUDE_vTaskDelete 配置为 1 。②入口参数输入需要删除的任务句柄(NULL代表删除本身)
内部机理:
①获取所要删除任务的控制块:通过传入的任务句柄,判断所需要删除哪个任务,NULL代表删除自身。
②将被删除任务移除所在列表:将该任务在所在列表中移除,包括:就绪、阻塞、挂起、事件等列表。
③判断所要删除的任务:如果删除任务自身,需先添加到等待删除列表,内存释放将在空闲任务执行;如果删除其他任务,释放内存,任务数量--。
④更新下一个任务的阻塞时间:更新下一个任务的阻塞超时时间,以防被删除的任务就是下一个阻塞超时的任务 。
二、任务挂起与恢复的API函数
挂起类似于暂停,可恢复;而删除任务,无法恢复。恢复就是恢复挂起的任务。带有“FromISR”后缀的是在中断函数中专用的API函数:
①任务挂起函数
void vTaskSuspend(TaskHandle_t xTaskToSuspend) /*也是一个参数,待挂起任务的任务句柄*/
注意:使用时需将宏 INCLUDE_vTaskSuspend 配置为 1;无论优先级如何,被挂起的任务都将不再被执行,直到任务被恢复;当传入的参数为NULL,则代表挂起任务自身(当前正在运行的任务)。
②任务恢复函数
void vTaskResume(TaskHandle_t xTaskToResume) /*也是只有一个参数,待恢复任务的任务句柄*/
注意:使用该函数注意宏INCLUDE_vTaskSuspend定义为 1;任务无论被 vTaskSuspend() 挂起多少次,只需在任务中调用 vTakResume() 恢复一次,就可以继续运行。且被恢复的任务会进入就绪态!
③中断中的任务恢复函数
BaseType_t xTaskResumeFromISR(TaskHandle_t xTaskToResume) /*也是一个参数,待恢复任务的任务句柄*/
返回值:(被恢复的任务优先级高于正在执行任务时返回pdTRUE)
注意:使用该函数注意宏INCLUDE_vTaskSuspend 和 INCLUDE_xTaskResumeFromISR 必须定义为 1,专用于中断服务函数中的恢复;中断服务程序中要想调用freeRTOS的API函数,则中断优先级不能高于FreeRTOS所管理(5-15)的最高优先级。
总结:
本段时间学习的实时操作系统都是基础知识,目的在于对于FreeRTOS有个整体的理论构架,暂且不涉及实操,后续实操会专门撰写记录笔记!
往期精彩:
电机应用控制——直流无刷电机
OpenCV机器视觉系列专栏
C语言进阶