上一文链接:FreeRTOS笔记(八)任务切换
01 - 任务相关的过渡
1.1 - get和set函数
了解到任务、列表和调度器后,关于任务的核心内容应该比较清晰,FreeRTOS还有很多任务的辅助函数,比如一些必要的get
和set
函数,用于获取和设置任务的状态和信息,比如常见的如下
函数 | 功能 |
---|---|
xTaskGetCurrentTaskHandle() | 获取运行态任务的句柄 |
uxTaskGetNumberOfTasks() | 获取当前所有任务的数量 |
vTaskGetRunTimeStats() | 获取任务的运行时间 |
eTaskGetState() | 获取任务状态 |
vTaskPrioritySet() | 设置任务优先级 |
vTaskSetTimeOutState() | 设置任务溢出时间 |
这些辅助函数在工作进度调整的时候需要用到,比如vTaskGetRunTimeStats()
用于获取任务占用CPU的时间,在工作进度开始之前可以先测试每个任务的CPU占用率,再去调整任务的优先级。关于这些函数应该要根据实际去使用。
1.2 - delay延迟函数
为了验证自己了解的任务基本内容,现在我们可以分析一下常用的延迟函数,FreeRTOS提供了两种延迟方式,vTaskDelay()
相对延迟和vTaskDelayUntil()
绝对延迟,不同点是时间计算的起点不同,相同点是都会进入阻塞状态,相对延迟是每次都从调用处的时刻为起点,而绝对延迟是根据上一次的结束点为起点,绝对延迟用于周期性任务的设置。
跟踪vTaskDelay()
函数,可以得到常见延迟的调用层次如下
vTaskDelay()
prvAddCurrentTaskToDelayedList()
xTimeToWake = xConstTickCount + xTicksToWait; #以当前值为起点计算唤醒时间xTimeToWake
listSET_LIST_ITEM_VALUE() #把xTimeToWake插入任务列表项的列表值
vListInsert() #任务插入延迟列表
可以尝试下面的追朔
这样,唤醒任务的时间就加入任务的列表项中了,同时任务也加入延迟列表
pxDelayedTaskList
,那么是谁唤醒的,要唤醒任务,必须把任务从延迟列表中移到就绪列表,于是追朔延迟列表的调用者,可以其中一个调用者是listGET_OWNER_OF_HEAD_ENTRY()
,继续追朔,调用者是xTaskIncrementTick()
,继续追朔,调用者是xPortSysTickHandler()
,到此追朔完成,上一文已经提及,xPortSysTickHandler()
是SysTick
中断的服务函数,周期性地进行工作。
下面是唤醒的调用层次,唤醒的核心代码在xTaskIncrementTick()
中
xPortSysTickHandler() #中断服务函数
xTaskIncrementTick() #更新xTickCount计数
pxTCB = listGET_OWNER_OF_HEAD_ENTRY() #获取延迟列表项
xItemValue = listGET_LIST_ITEM_VALUE() #获取唤醒时间
if( xConstTickCount < xItemValue ) #如果到达唤醒时间
uxListRemove() #把任务从延迟列表移除
prvAddTaskToReadyList( pxTCB ); #任务插入就绪列表
以上简单总结为:调用vTaskDelay()
后,计算唤醒时间并加入任务属性中,然后任务加入延迟列表,每个SysTick
中断周期内就会检查延迟列表中的任务是否到达唤醒时间,如果是,就从延迟列表中移到就绪列表,唤醒完成。
可以用同样的方式追朔vTaskDelayUntil()
绝对延迟,它只是计算唤醒时间的方式不同,以上一次唤醒的时间为起点,如果是第一次调用,那么起点就是任务函数的执行时刻,区别可以用下图表达
除了延迟函数,还可以去分析挂起函数xTaskSuspend()
等等,任务函数相关API就过渡到这里。
02 - 总结
- 任务有非常多的get和set函数,可以在任务运行期间获取和设置任务的状态和属性
- 延迟函数分为相对和绝对,相对延迟一般用于短暂的等待,绝对延迟一般用于周期性工作
- 任务还有很多辅助API函数