任务函数的调用
硬件初始化
初始化与任务相关的列表
创建任务 xTaskCreateStatic
添加任务到就绪列表
启动调度器
for
循环让任务死循环
实现具体的函数
任务的定义与任务切换的实现 实现任务创建函数 任务的栈,任务的函数实体,实现任务控制块的创建和联系。
静态创建,configSUPPORT_STATIC_ALLOCATION
在 FreeRTOSConfig.h
中定义,配置为 1
。(静态创建)
xTaskCreateStatic()
函数1 2 3 4 5 6 7 8 TaskHandle_t xTaskCreateStatic ( TaskFunction_t xx, const char * const xx, const uint32_t xx, void * const xx, StackType_t * const xx, TCB_t * const xx ) ;
静态创建任务,内嵌 prvInitialiseNewTask
函数。
TaskFunction_t
:任务函数本身(在 projdefs.h
中重定义的空指针)。任务运行时执行此函数,任务函数必须符合 void*
类型。
运行传参 :将函数指针传递给调度器,许多任务的具体实现不同,调度器运行时只需调用不同的任务函数,编译不需要硬编码不同的函数,否则调度器需要知道函数的具体实现,将函数的实现拷贝到调度器中。指针容易被赋值。
tskTaskControlBlock
:任务的控制块,任务的状态和各种与调度相关的信息,是 FreeRTOS 调度器用来管理任务的核心结构 (tcb_t
)。
TCB
并不直接暴露给用户,而是通过 TaskHandle_t
来间接访问
TaskHandle_t
:任务句柄,在任务创建时获取,提供给用户,方便任务的挂起、恢复、删除等操作 (tcb_t
)。
TaskFunction_t
:void*
类型,任务函数类型。
prvInitialiseNewTask()
函数用于初始化新任务的 TCB
和相关数据结构。
参数设置
任务入口
任务名称
任务栈大小
任务形参
任务句柄
任务控制块指针
获取栈顶地址 (传入的 任务控制块指针
(此函数参数)内部的 栈起始地址
加上 栈大小
(此函数参数)减 1
作为栈顶地址(被重定义过的整型变量))
将任务的名字存储在 TCB
中
字符串长度小于 configMAX_TASK_NAME_LEN
的情况下递增循环
储存在 xTaskCreateStatic()
函数中控制块索引指针中
若出现 0x00
(即以 '/0'
结尾则退出)
强行给最大长度的前一位置 0
初始化 TCB
中的 xStateListItem
(任务节点)
使用 vListInitialiseItem
函数初始化链表项 xStateListItem
使用 listSET_LIST_ITEM_OWNER
配置 xStateListItem
的拥有者项
调用函数初始化任务栈,并更新栈顶指针
调用 pxPortInitialiseStack()
函数初始化任务栈,并更新栈顶指针
任务句柄指向任务控制块
pxPortInitialiseStack()
函数它的主要作用是为新创建的任务设置初始的栈状态(上文初始化栈状态时用到),以便任务能够正确地开始执行。确保栈的顶部包含正确的初始值。(存储的内容在异常发生时会自动加载到 CPU)
参数 1 2 3 StackType_t *pxTopOfStack, TaskFunction_t pxCode, void *pvParameters
初始化栈
xPSR
的 bit24
必须置 1
(thumb 模式)
任务的入口地址 (这个函数在内存中的地址)
当任务被创建时,FreeRTOS 会将任务入口地址(即任务函数的地址)保存到任务栈中,以便在任务切换时能够恢复这个地址并开始执行任务。
任务的返回地址
它是在任务执行过程中保存的,用于在任务切换时恢复任务的执行状态。不过 FreeRTOS 会将 PC
设置为 prvTaskExitError
,而不是返回到任务的调用位置。这是为了确保任务结束后不会继续执行不应执行的代码。 FreeRTOS 中的任务函数通常是一个无限循环。
R12
, R3
, R2
和 R1
默认初始化为 0
。