写在最前
由于工作需要,需要开始学习freertos的相关知识,本专题主要记录freertos的相关内容
参考:
https://www.bilibili.com/video/BV19g411p7UT 正点原子视频
1. 简介
和一般的OS不同(linux/windows),在freertos中,每个执行线程都被称为任务,freertos任务创建和删除的本质就是调用相关的API函数去实现
API函数 | 描述 |
---|---|
xTaskCreate() | 动态方式创建任务 |
xTaskCreateStatic() | 静态方式创建任务 |
vTaskDelete() | 删除任务 |
2. 任务控制块TCB介绍
学过操作系统的都知道,进程有个PCB来存储进程的各种信息,这里的TCB类似,每个任务都有属于自己的任务控制块,类似于我们人的身份证,它是由一个c语言的结构体实现
typedef struct tskTaskControlBlock
{
volatile StackType_t * pxTopOfStack;
ListItem_t xStateListItem;
ListItem_t xEventListItem;
UBaseType_t uxPriority;
StackType_t * pxStack;
char pcTaskName[ configMAX_TASK_NAME_LEN ];
…
省略很多条件编译的成员
} tskTCB;
成员:
-
pxTopOfStack
:一个指针指向任务栈栈顶,必须为TCB的第一个成员,在任务切换时的任务上下文保存、任务恢复息息相关 -
xStateListItem
:任务状态列表项,你当前任务处于什么状态,就绪态/堵塞态/挂起态 -
xEventListItem
:任务事件列表项, -
uxPriority
:任务优先级,数值越大,优先级越大 -
pxStack
:指针指向任务栈起始地址 -
pcTaskName[ configMAX_TASK_NAME_LEN ];
:任务名字
3. 动态创建任务函数
3.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 /* 任务句柄,就是任务的任务控制块 */
)
参数:
pxTaskCode
:指向任务函数的指针pcName
:任务名字,最大长度configMAX_TASK_NAME_LEN
usStackDepth
:任务堆栈大小,注意字为单位,系统自动分配pvParameters
:传递给任务函数的参数,一般设置为NULLuxPriority
:任务优先级,范围:0 ~ configMAX_PRIORITIES - 1
pxCreatedTask
:任务句柄,就是任务的任务控制块
返回值:
- 成功:
pdPASS
- 失败:
errCOULD_NOT_ALLOCATE_REQUIRED_MEMORY
,可能是因为你申请的堆栈实在时太大了
3.2 动态任务创建
3.2.1 实践操作
- 将宏
configSUPPORT_DYNAMIC_ALLOCATION
配置为 1 - 定义函数入口参数
- 编写任务函数
此函数创建的任务会立刻进入就绪态,由任务调度器调度运行
3.2.2 内核实现流程
- 申请堆栈内存&任务控制块内存
- TCB结构体成员赋值
- 添加新任务到就绪列表中(就绪态)
4. 静态创建任务
3.1 函数介绍
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 /* 任务控制块指针,由用户分配 */
);
参数:
pxTaskCode
:指向任务函数的指针pcName
:任务名字,最大长度configMAX_TASK_NAME_LEN
usStackDepth
:任务堆栈大小,注意字为单位,系统自动分配pvParameters
:传递给任务函数的参数,一般设置为NULLuxPriority
:任务优先级,范围:0 ~ configMAX_PRIORITIES - 1
puxStackBuffer
:任务堆栈,一般为数组,由用户分配pxTaskBuffer
:任务控制块指针,由用户分配
返回值:
- 成功:
其他值
,任务句柄,任务创建成功 - 失败:
NULL
,用户没有提供相应的内存,任务创建失败
3.2 静态创建任务使用流程
3.2.1 实践操作
- 需将宏
configSUPPORT_STATIC_ALLOCATION
配置为 1 - 定义空闲任务&定时器任务的任务堆栈及TCB
- 实现两个接口函数(
vApplicationGetIdleTaskMemory( )
和vApplicationGetTimerTaskMemory ( )
) - 定义函数入口参数
- 编写任务函数
3.2.2 内核实现
- TCB结构体成员赋值
- 添加新任务到就绪列表中
此函数创建的任务会立刻进入就绪态,由任务调度器调度运行
5. 删除任务
5.1 任务删除函数
void vTaskDelete(TaskHandle_t xTaskToDelete);
作用:
用于删除已被创建的任务,被删除的任务将从就绪态任务列表、阻塞态任务列表、挂起态任务列表和事件列表中移除
参数:
xTaskToDelete
:待删除任务的任务句柄
注意:
- 当传入的参数为NULL,则代表删除任务自身(当前正在运行的任务)
- 当任务是
动态创建
空闲任务会负责释放被删除任务中由系统分配的内存, - 当任务是
静态创建
时则需要由用户在任务被删除前提前释放,否则将导致内存泄露
5.2 任务删除流程
5.2.1 实践操作
- 使用删除任务函数,需将宏
INCLUDE_vTaskDelete
配置为 1 - 入口参数输入需要删除的任务句柄(NULL代表删除本身)
5.2.2 内核实现流程
-
获取所要删除任务的控制块
:通过传入的任务句柄,判断所需要删除哪个任务,NULL代表删除自身 -
将被删除任务,移除所在列表
:将该任务在所在列表中移除,包括:就绪、阻塞、挂起、事件等列表 -
判断所需要删除的任务
:- 删除任务自身,需先添加到等待删除列表,内存释放将在空闲任务执行
- 删除其他任务,释放内存,任务数量–
-
更新下个任务的阻塞时间
:更新下一个任务的阻塞超时时间,以防被删除的任务就是下一个阻塞超时的任务
总结
本文主要简要介绍了freertos的任务的创建和删除的实现,包括实践和内核,以及TCB介绍,属于纯理论部分,并未涉及任何实践操作。