前言
在第7章我们知道在创建任务并启动任务调度器后,当前任务控制块是指向第一个任务(即pxCurrentTCB = &Task1TCB),然后会产生SVC中断,将pxCurrentTCB出栈至CPU寄存器切换至任务1。
在任务1函数的最后会执行taskYield,taskYield会产生PendSVC中断,先将任务1入栈,然后将当前任务控制块指向第二个任务(即pxCurrentTCB = &Task2TCB),再将pxCurrentTCB出栈至CPU寄存器切换至任务2。在任务2函数的最后也是如此切换至任务1。
本章知识点
在本章,在启动任务调度器时,还会同时把空闲任务创建起来,并启动滴答定时器及其中断,然后在产生的SVC中断中切换至任务1。在滴答定时器中断中会先将所有任务的倒计时个数减1,再调用taskYield完成任务切换,如下图:
在任务1函数中,会通过vTaskDelay函数来给当前任务赋以倒计时个数(即延时时长)并调用taskYield完成任务切换,如下图:
注意这里taskYield产生PendSVC中断中的任务切换不再是任务1时切任务2这样简单了,而是会通过一个复杂一些的算法来切换,如下代码:
void vTaskSwitchContext( void )
{
if ( pxCurrentTCB == &IdleTaskTCB ) //当前为空闲任务时
{
if (Task1TCB.xTicksToDelay == 0)//任务1延时倒计时结束了
{
pxCurrentTCB =&Task1TCB;
}
else if (Task2TCB.xTicksToDelay == 0)//任务2延时倒计时结束了
{
pxCurrentTCB =&Task2TCB;
}
else //任务延时均没有到期则返回,继续执行空闲任务
{return;}
}
else //当前不是空闲任务
{
if (pxCurrentTCB == &Task1TCB)//当前为任务1时
{
if (Task2TCB.xTicksToDelay == 0)
{
pxCurrentTCB =&Task2TCB;
}
else if (pxCurrentTCB->xTicksToDelay != 0)//任务1延时倒计时没结束
{
pxCurrentTCB = &IdleTaskTCB;
}
else //返回,不进行切换,因为两个任务都处于延时中
{return;}
}
else if (pxCurrentTCB == &Task2TCB)//当前为任务2时
{
if (Task1TCB.xTicksToDelay == 0)
{
pxCurrentTCB =&Task1TCB;
}
else if (pxCurrentTCB->xTicksToDelay != 0)//任务2延时倒计时没结束
{
pxCurrentTCB = &IdleTaskTCB;
}
else //返回,不进行切换,因为两个任务都处于延时中
{return;}
}
}//end of当前不是空闲任务
}
举例
最后的波形应该是这样的,如下: