自学内容网 自学内容网

FreeRTOS——任务创建(静态、动态创建)、任务删除以及内部实现剖析

任务创建和删除的API函数

任务的创建和删除本质就是调用FreeRTOS的API函数

API函数描述
xTaskCreate()动态方式创建任务
xTaskCreateStatic()静态方式创建任务
vTaskDelete()删除任务

 动态创建任务:任务的任务控制块以及任务的栈空间所需的内存,均有FreeRTOS从FreeRTOS管理的堆中分配

静态创建任务:任务的任务控制块以及任务的栈空间所需的内存,需用户分配提供

动态创建任务函数

BaseType_t xTaskCreate( TaskFunction_t pxTaskCode, // 函数指针, 任务函数
                        const char * const pcName, // 任务的名字
                        const configSTACK_DEPTH_TYPE usStackDepth, // 栈大小,单位为word,10表示40字节
                        void * const pvParameters, // 调用任务函数时传入的参数
                        UBaseType_t uxPriority,    // 优先级
                        TaskHandle_t * const pxCreatedTask ); // 任务句柄, 以后使用它来操作这个任务

注意:pcName的长度根据在FreeRTOSConfig.h中不同定义而不同

对于32位计算机,1字=32位=4字节

返回值描述
pdPASS任务创建成功
errCOULD_NOT_ALLOCATE_REQUIRED_MEMORY任务创建失败

实现动态创建任务流程

1、将宏configSUPPORT_DYNAMIC_ALLOCATION 配置为 1

2、定义函数入口参数

3、编写任务函数

此函数创建的任务会立刻进入就绪态,由任务调度器调度运行

静态创建任务函数

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用户没有提供相应的内存,任务创建失败
其他值任务句柄,任务创建成功

实现静态创建任务流程

1、将宏configSUPPORT_STATIC_ALLOCATION配置为1

2、定义空闲任务&定时器任务的任务堆栈及TCB

3、实现两个接口函数(vApplicationGetIdle TaskMemory()、vApplicationGetTimerTaskMemory())空闲任务和软件定时器的内存赋值

4、定义函数入口参数

5、编写任务函数

此函数创建的任务会立刻进入就绪态,由任务调度器调度运行

 任务删除函数

void vTaskDelete(TaskHandle_t xTaskToDelete);

形参描述
xTaskToDelete待删除任务的任务句柄

用于删除已经被创建的任务。

被删除的任务从就绪任务列表、阻塞态任务列表、挂起态任务列表和事件列表中删除

注意:

1、当传入的参数为NULL,则代表删除任务自身(当前正在运行的任务)自杀。

2、空闲任务会负责释放被删除任务中由系统分配的内存,但是由用户在任务删除前申请的内存,则需要由用户在任务被删除前提前释放,否则将其导致内存泄漏。

例如:我们动态创建了两个任务Task1和Task2,在Task1中调用删除函数,参数为Task2,则系统给Task2分配的内存在Task1中释放;如果参数为NULL,系统为Task1分配的内存在空闲任务中释放;

而静态创建的任务,用户自己申请的内存需要在任务删除前用户自己去提前释放,否则会导致内存泄漏。

删除任务流程

1、使用删除任务函数,需将宏INCLUDE_vTaskDelete配置为1

2、入口参数输入需要删除的任务句柄(NULL代表删除本身)

内部实现过程:

1)获取所要删除的任务控制块,(通过传入的任务句柄,判断所需要删除拿个任务,NULL代表删除本身,任务句柄是指向任务控制块的指针)

2)将被删除任务,移除所在列表(将该任务在所在列表中移除,包括:就绪、阻塞、挂起、事件等列表)

3)判断所需要删除的任务(将任务自身,需先添加到等待删除列表、内存释放将在空闲任务执行;删除其他任务,释放内存,任务数量--)

4)更新下个任务的阻塞时间(更新下一个任务的阻塞超时时间,以防被删除的任务就是下一个阻塞超时的任务)

实战编程

 1、实验目的:学会xTaskCreate()和vTaskDelete()的使用

2、实验设计:将设计四个任务:start task、task1、task2、task3

四个任务的功能如下:

start_task:用来创建其他的三个任务,只执行一次,执行完毕后调用vTaskDelete()自杀

task1:实现LED0每500ms闪烁一次

task2:实现LED1每500ms闪烁一次

task3:判断按键KEY0是否按下,按下删除task1

步骤:

(1)将支持动态创建任务的宏置1

(2)创建任务入口

(3)在main函数前进行一些宏定义以及函数声明

 (4)编写start_task的任务函数

 (5)宏定义三个任务的优先级、栈深度、定义任务句柄以及任务函数的声明

(6)编写三个任务的任务函数

 

 优先级数字越大,优先级越高。

但是执行的顺序却是task1、task2、task3,为什么呢?

start_task创建之后开始调度,开始执行,创建task1此时task1的优先级比start高,创建完之后执行task1,task1延时阻塞之后,返回低优先级任务start执行,创建task2,task2优先级高于start,执行task2,task2延时阻塞后,返回低优先级任务start执行,创建task3,task3阻塞之后返回低优先级任务start,start创建完三个task之后自杀。

 taskENTER_CRITICAL();           //进入临界区

这句代码的作用是关闭中断,任务切换是在中断里面进行,这时我们关闭中断,任务切换就不会再进行。

 创建任务其内部实现

1、申请堆栈内存(返回首地址)

2、申请任务控制块内存(返回首地址)

3、把前面申请的堆栈地址,赋值给控制块的堆栈成员

4、调用prvInitialiseNewTask初始化任务控制块里面的成员

5、调用prvAddNewTaskToReadyList添加新创建任务到就绪列表中

动态创建时定义任务句柄指向该任务TCB结构体,在prvInitialiseNewTask中,TCB结构体中存储对应任务的状态、优先级等信息,存储完信息之后就将该TCB任务控制块作为参数传递给prvAddNewTaskToReadyList

剖析 prvInitialiseNewTask

 

 

 然后就初始化任务栈

步骤总结:

 

 剖析prvAddNewTaskToReadyList

私有函数初始化列表prvInitialiseTaskLists()

 接下来的操作:

步骤总结: 

 

 删除任务内部实现

 

 如果要删除的任务是当前正在执行的任务,则其分配的空间不能直接释放,需要在空闲函数执行的时候进行释放,空闲任务的创建在开启调度的函数中可以找到,然后通过任务创建函数可以跳转到空闲任务函数,在函数体中找到下面的函数,就可以看到删除自身函数的具体过程:

步骤总结: 

 


原文地址:https://blog.csdn.net/weixin_74209413/article/details/142768917

免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!