1.任务创建和删除的API函数
任务的创建和删除本质就是调用FreeRTOS的API函数
- 动态方式创建任务——xTaskCreate()
- 静态方式创建任务——xTaskCreateStatic()
- 删除任务——vTaskDelete()
动态创建任务:任务的任务控制块以及任务的栈空间所需的内存,均由 FreeRTOS 从 FreeRTOS 管理的堆中分配
静态创建任务:任务的任务控制块以及任务的栈空间所需的内存,需用户分配提供
1.1.任务控制块TCB
FreeRTOS中的每一个已创建任务都包含一个任务控制块,任务控制块是一个结构体变量,FreeRTOS用任务控制块结构体存储任务的属性。FreeRTOS的任务控制块结构体中包含了很多成员变量,但是,大部分的成员变量都是可以通过FreeRTOSConfig.h 配置文件中的配置项宏定义进行裁剪的。
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;
1.2.动态创建任务xTaskCreate()
typedef struct tskTaskControlBlock * TaskHandle_t;
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 /* 任务句柄,就是任务的任务控制块 */
)
【注意:在动态创建任务时,任务句柄是指向TCB的指针】
返回类型:BaseType_t
返回pdPASS:任务创建成功
返回errCOULD_NOT_ALLOCATE_REQUIRED_MEMORY:任务创建失败
实现动态创建任务的流程
此函数创建的任务会立刻进入就绪态,由任务调度器调度运行
- 将宏configSUPPORT_DYNAMIC_ALLOCATION 配置为 1
- 定义函数入口参数
- 编写任务函数
动态创建任务的内部实现
- 申请堆栈内存&任务控制块内存
- TCB结构体成员赋值
- 添加新任务到就绪列表中
详细流程如下图:
1.3.静态创建任务函数xTaskCreateStatic()
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 /* 任务控制块指针,由用户分配 */
);
【注意:在静态创建任务时,TCB空间由用户申请,其结构与动态TCB类似,任务句柄与TCB关系没有直接关系】
返回类型:TaskHandle_t(任务句柄)
返回NULL:用户没有提供相应的内存,任务创建失败
返回其他:任务句柄,任务创建成功
实现静态创建任务的流程
此函数创建的任务会立刻进入就绪态,由任务调度器调度运行
- 需将宏configSUPPORT_STATIC_ALLOCATION 配置为 1
- 定义空闲任务&定时器任务(可选)的任务堆栈及TCB
- 实现空闲任务和定时器任务(可选)接口函数:vApplicationGetIdleTaskMemory( ) 、vApplicationGetTimerTaskMemory ( )
- 定义函数入口参数
- 编写任务函数
静态创建任务的内部实现
- TCB结构体成员赋值
- 添加新任务到就绪列表中
1.4.任务删除函数vTaskDelete()
void vTaskDelete(TaskHandle_t xTaskToDelete); //参数为待删除任务的任务句柄
- 被删除的任务将从就绪态任务列表、阻塞态任务列表、挂起态任务列表和事件列表中移除
- 当传入的参数为NULL,则代表删除任务自身(当前正在运行的任务)
- 空闲任务会负责释放被删除任务中由系统分配的内存(动态),但是由用户在任务删除前申请的内存(静态), 则需要由用户在任务被删除前提前释放,否则将导致内存泄露
【注意:动态创建时,删除任务不是自己,直接释放内存,删除任务是自己,在空闲任务释放内存;静态创建的内存需由用户释放】
实现删除任务的流程
- 使用删除任务函数,需将宏INCLUDE_vTaskDelete 配置为 1
- 入口参数输入需要删除的任务句柄(NULL代表删除本身)
删除任务的内部实现
- 获取所要删除任务的控制块:通过传入的任务句柄,判断所需要删除哪个任务,NULL代表删除自身
- 将被删除任务移除所在列表:将该任务在所在列表中移除,包括:就绪、阻塞、挂起、事件等列表
- 判断所需要删除的任务
删除任务自身,需先添加到等待删除列表,内存释放将在空闲任务执行
删除其他任务,释放内存,任务数量– - 更新下个任务的阻塞时间:更新下一个任务的阻塞超时时间,以防被删除的任务就是下一个阻塞超时的任务
- 调度器正在运行且删除任务自身,则需要进行一次任务切换
2.任务创建和删除(动态方法)
- 实验目的:学会 xTaskCreate( ) 和 vTaskDelete( ) 的使用
- 实验设计:将设计四个任务:start_task、task1、task2、task3
start_task:用来创建其他的三个任务
task1:实现LED0每500ms闪烁一次
task2:实现LED1每500ms闪烁一次
task3:判断按键KEY0是否按下,按下则删掉task1
3.任务创建和删除(静态方法)
- 实验目的:学会 xTaskCreateStatic( ) 和 vTaskDelete( ) 的使用
- 实验设计:将设计四个任务:start_task、task1、task2、task3
start_task:用来创建其他的三个任务
task1:实现LED0每500ms闪烁一次
task2:实现LED1每500ms闪烁一次
task3:判断按键KEY0是否按下,按下则删掉task1
4.总结
- 在实际的应用中,动态方式创建任务是比较常用的,除非有特殊的需求,一般都会使用动态方式创建任务
- 静态创建:可将任务堆栈放置在特定的内存位置,并且无需关心对内存分配失败的处理
- 临界区保护,保护那些不想被打断的程序段,关闭freertos所管理的中断,中断无法打断,滴答中断和PendSV中断无法进行不能实现任务调度
以下是动态创建任务和静态创建任务的区别
动态创建 | 静态创建 | |
---|---|---|
TCB与堆栈内存 | 自动分配 | 手动分配 |
TCB与任务句柄的关系 | 句柄是动态TCB的指针 | 与静态TCB无特定关系 |
返回值 | BaseType_t | TaskHandle_t(句柄) |
创建流程 | - | 额外定义空闲任务与定时器任务(可选) |
任务删除 | NULL空闲任务删除 非NULL直接删除 | 手动删除 |
其他 | - | 不用担心内存分配失败 |