FreeRTOS#6——任务API
任务API
任务控制块
typedef struct tskTaskControlBlock
{
volatile StackType_t * pxTopOfStack; //任务栈顶,必须为TCB第一成员,栈顶存放当前任务的所有内核寄存器值,任务切换时,将栈顶的内核寄存器加载到内核中 即恢复执行,上下文切换时会更新栈顶指针
#if ( portUSING_MPU_WRAPPERS == 1 )
xMPU_SETTINGS xMPUSettings; //MPU保护设置
#endif
ListItem_t xStateListItem; //任务状态列表,当前任务处于什么状态
ListItem_t xEventListItem; //任务事件列表,当前任务在等待什么事件
UBaseType_t uxPriority; //任务优先级 数值越大 优先级越大
StackType_t * pxStack; //任务栈起始地址 从高地址往低地址生长
char pcTaskName[ configMAX_TASK_NAME_LEN ]; //任务名称
#if ( ( portSTACK_GROWTH > 0 ) || ( configRECORD_STACK_HIGH_ADDRESS == 1 ) )
StackType_t *pxEndOfStack; // 堆栈结束地址 用于堆栈溢出检测
#endif
#if ( portCRITICAL_NESTING_IN_TCB == 1 )
UBaseType_t uxCriticalNesting; // 临界区 嵌套次数
#endif
#if ( configUSE_TRACE_FACILITY == 1 )
UBaseType_t uxTCBNumber; // TCB创建序号 用于区分 删除后重新创建的同名任务
UBaseType_t uxTaskNumber; // 任务编号
#endif
#if ( configUSE_MUTEXES == 1 )
UBaseType_t uxBasePriority; // 基础优先级
UBaseType_t uxMutexesHeld; //持有的互斥数量
#endif
#if ( configUSE_APPLICATION_TASK_TAG == 1 )
TaskHookFunction_t pxTaskTag; //任务标签
#endif
#if( configNUM_THREAD_LOCAL_STORAGE_POINTERS > 0 )
void *pvThreadLocalStoragePointers[ configNUM_THREAD_LOCAL_STORAGE_POINTERS ]; // 线程本地存储 任务私有数据指针数组
#endif
#if( configGENERATE_RUN_TIME_STATS == 1 )
uint32_t ulRunTimeCounter; // 运行时间统计
#endif
#if ( configUSE_NEWLIB_REENTRANT == 1 )
struct _reent xNewLib_reent; //NewLib 可重入结构
#endif
#if( configUSE_TASK_NOTIFICATIONS == 1 )
volatile uint32_t ulNotifiedValue; //任务通知值
volatile uint8_t ucNotifyState; //任务通知状态
#endif
#if( tskSTATIC_AND_DYNAMIC_ALLOCATION_POSSIBLE != 0 )
uint8_t ucStaticallyAllocated; //静态分配标记 标识任务是否时静态分配的
#endif
#if( INCLUDE_xTaskAbortDelay == 1 )
uint8_t ucDelayAborted; // 延迟是否被中止 标记任务的延迟是否被xTaskAbortDelay()中止
#endif
#if( configUSE_POSIX_ERRNO == 1 )
int iTaskErrno; // 为每个任务提供独立的 errno 变量
#endif
} tskTCB;
任务创建
动态创建
-
任务控制块、任务栈空间由系统从管理的堆中分配
-
创建完成后 立即进入就绪态
-
BaseType_t xTaskCreate( TaskFunction_t pxTaskCode, //任务函数指针 const char * const pcName, //任务名称,最大长度 const configSTACK_DEPTH_TYPE usStackDepth, //任务堆栈大小 字 为单位 void * const pvParameters, //参数 UBaseType_t uxPriority, //任务优先级 TaskHandle_t * const pxCreatedTask //任务句柄指针,就是任务控制块 ) //返回值 pdPASS-成功,其他-失败
动态创建函数解析
-
申请堆栈内存,返回首地址
-
申请任务控制块内存,返回首地址
-
把申请到的堆栈地址,赋值给控制块的 pxStack
-
调用prvInitialiseNewTask 初始化任务控制块中的成员
- 把整个任务堆栈初始化为0xA5,方便计算最小剩余空间,不为A5则被使用过
- 获取栈顶地址,向下依次 8字节对齐
- 初始化状态列表项、事件列表项
- pxPortInitialiseStack 函数 将xPSR、PC、LR 等所有内核寄存器 存入栈顶,当任务切换时 将内核中的寄存器值保存到任务栈顶,恢复任务时 读取栈顶的寄存器值 再顺序执行
- 任务句柄 等于 任务TCB
-
调用prvAddNewTaskToReadyList 添加新创建任务到就绪列表中
-
任务数量计数器加一 uxCurrentNumberOfTasks++
-
判断新创建的任务是否为第一个任务 (pxCurrentTCB指向当前优先级最高的任务 即正在执行的任务)
- 如果创建的是第一个任务,初始化各个任务列表 prvInitaliseTaskLists()
- 如果创建的不是第一个任务 并且调度器还未开始启动,比较新任务与正在执行的任务优先级大小,新任务优先级大的话,将pxCurrentTCB 重新指向新的控制块
-
将新的TCB添加到就绪列表中,使用 prvAddTackToReadyList 函数
- 32个优先级,每一位一个列表,当前优先级有任务就绪则 这一位置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 //任务控制 块指针 ) //返回值 NULL-失败,其他-任务句柄
静态创建函数解析
- 打开 configSUPPORT_STATIC_ALLOCATION 宏
- 定义空闲任务、定时器任务的任务堆栈及TCB
- 实现两个空间申请接口函数
- vApplicationGetIdleTaskMemory()
- vApplicationGetTimerTaskMemory()
- 定义任务创建函数入口参数
- 编写任务函数
任务删除
void vTaskDelete( TaskHandle_t xTaskToDelete ); //参数为 任务句柄
- 空闲任务会负责释放被删除任务中由系统分配的内存
- 由用户分配的空间删除任务前需手动释放 否则会内存泄漏
- 使用前需要开启配置文件中宏定义
删除函数解析
- 获取要删除任务的TCB
- 通过任务句柄 判断要删除哪个任务,NULL删除自身
- 将被删除任务 移除所在列表
- 将该任务在 所在所有列表中移除
- 判断要删除的任务
- 删除自身,先添加到等待删除列表 内存释放在空任务执行
- 删除其他 当前任务数量减一,更新下一任务的阻塞超时时间,以防被删除的任务就是下一阻塞超时的任务
- 删除的任务为其他任务则直接释放内存prvDeleteTCB()
- 调度器正在运行且删除任务自身,则需要进行一次任务切换
任务挂起
void vTaskSuspend( TaskHandle_t xTaskToSuspend ); //任务句柄
- 使用前 INCLUDE_vTaskSuspend 宏置1
挂起函数解析
- 根据任务句柄获取TCB,如果为NULL 则挂起任务本身
- 将要挂起的任务从相应列表和事件中移除
- 将该任务的任务状态列表项插入到挂起状态列表末尾
- 判断任务调度器是否运行,若在运行,更新下一次阻塞时间,防止被挂起任务为下一次阻塞超时任务
- 如果挂起的是任务本身
- 调度器在运行,强制进行一次任务切换
- 调度器没有运行,判断挂起任务数是否等于任务总数
- 是,表示所有任务被挂起,则 pxCurrentTCB 赋值为NULL
- 否,通过函数vTaskSwitchContext 寻找下一个最高优先级任务
任务恢复
void vTaskResume( TaskHandle_t xTaskToResume );//任务句柄
- 使用前 INCLUDE_vTaskSuspend 宏置1
- 恢复后就 进入就绪态
恢复函数解析
- 恢复任务不能是正在运行的任务且不能为NULL
- 判断任务是否被挂起
- 是,将任务从挂起列表中移除,并添加进就绪列表中
- 判断恢复的任务的优先级是否大于当前正在执行的任务,是则执行任务切换
BaseType_t xTaskResumeFromISR( TaskHandle_t xTaskToResume );//中断中恢复
//返回值 pdRTUE-任务恢复后需要进行任务切换,pdFALSE-任务恢复后不需要进行任务切换
- 在中断中使用,需要该中断优先级不能高于FreeRTOS 所管理的中断的最高优先级
- 使用前 INCLUDE_vTaskSuspend 、INCLUDE_xTaskResumeFromISR宏置1
中断中恢复函数解析
- 函数portASSERT_IF_INTERRUPT_PRIORITY_INVALID(),用于检测调用FREERTOS的API函数的中断优先级是否在管理范围内 及 是否全部设置为抢占式优先级位
- 关闭freeRTOS可管理中断,防止被其他的中断打断,并 返回关闭前 basepri寄存器 的值
- 判断是否有挂起任务
- 有,则检查调度器是否被挂起
- 未挂起
- 判断恢复的这个任务优先级 是否大于正在执行的任务
- 是 则将xYieldRequired标记位pdTRUE,表示需要进行一次任务切换
- 将被恢复的任务从挂起列表移除
- 插入就绪列表
- 判断恢复的这个任务优先级 是否大于正在执行的任务
- 被挂起
- 恢复的任务插入等待就绪列表xPendingReadyList 直到调度器被恢复再进行任务的处理
- 未挂起
- 无,则不操作
- 有,则检查调度器是否被挂起
- 将前面保存的basepri的值 恢复
- 返回xYieldRequired 的值,用于决定是否需要进行任务切换
任务状态查询
uxTaskPriorityGet()
- 获取任务优先级
vTaskPrioritySet()
- 设置任务优先级
uxTaskGetSystemState()
- 获取所有任务的状态信息
vTaskGetInfo()
- 获取单个任务的状态信息
xTaskGetApplicationTaskTag()
- 获取任务 Tag
xTaskGetCurrentTaskHandle()
- 获取当前任务的任务句柄
xTaskGetHandle()
- 获取指定任务的任务句柄
xTaskGetIdleTaskHandle()
- 获取空闲任务的任务句柄
uxTaskGetStackHighWaterMark()
- 获取任务的任务栈历史剩余最小值
eTaskGetState()
- 获取任务状态
pcTaskGetName
- 获取任务名
xTaskGetTickCount()
- 获取系统时钟节拍计数器的值
xTaskGetTickCountFromISR()
- 中断中获取系统使用节拍计数器的值
xTaskGetSchedulerState()
- 获取任务调度器状态
uxTaskGetNumberOfTasks()
- 获取系统中任务的数量
vTaskList()
- 以“表格”形式获取所有任务的信息
vTaskGetRunTimeStats()
- 获取任务的运行时间等信息
vTaskSetApplicationTaskTag()
- 设置任务 Tag
SetThreadLocalStoragePointer()
- 设置任务的独有数据记录数组指针
GetThreadLocalStoragePointer()
- 获取任务的独有数据记录数组指针
任务运行时间统计
vTaskGetRunTimeStats()
- 用于获取指定任务的运行时间、状态等信息
更多推荐

所有评论(0)