上QQ阅读APP看书,第一时间看更新
5.2 实现阻塞延时
阻塞延时的阻塞是指任务调用该延时函数后,会被剥夺CPU使用权,然后进入阻塞状态,直到延时结束,任务重新获取CPU使用权才可以继续运行。在任务阻塞的这段时间,CPU可以执行其他任务,如果其他任务也处于延时状态,那么CPU就将运行空闲任务。阻塞延时函数在os_time.c中定义,具体代码实现参见代码清单5-9。
代码清单5-9 阻塞延时
1 /* 阻塞延时 */ 2 void OSTimeDly(OS_TICK dly) 3 { 4 /* 设置延时时间 */ 5 OSTCBCurPtr->TaskDelayTicks = dly;(1) 6 7 /* 进行任务调度 */ 8 OSSched();(2) 9 }
代码清单5-9(1):TaskDelayTicks是任务控制块的一个成员,用于记录任务需要延时的时间,单位为SysTick的中断周期。比如我们设置的SysTick的中断周期为10ms,调用OSTimeDly(2)则完成2*10ms的延时。TaskDelayTicks的定义具体参见代码清单5-10。
代码清单5-10 TaskDelayTicks定义
1 struct os_tcb { 2 CPU_STK *StkPtr; 3 CPU_STK_SIZE StkSize; 4 5 /* 任务延时周期个数 */ 6 OS_TICK TaskDelayTicks; 7 };
代码清单5-9(2):任务调度。这时的任务调度与第4章的不一样,具体参见代码清单5-11,其中加粗部分为第4章的代码,现已用条件编译屏蔽掉。
代码清单5-11 任务调度
1 void OSSched(void) 2 { 3 #if 0/* 非常简单的任务调度:两个任务轮流执行 */ 4 if ( OSTCBCurPtr == OSRdyList[0].HeadPtr ) { 5 OSTCBHighRdyPtr = OSRdyList[1].HeadPtr; 6 } else { 7 OSTCBHighRdyPtr = OSRdyList[0].HeadPtr; 8 } 9 #endif 10 11 /* 如果当前任务是空闲任务,那么尝试执行任务1或者任务2, 12 *看看其延时时间是否结束,如果任务的延时时间均没有到期, 13 *就返回继续执行空闲任务 */ 14 if ( OSTCBCurPtr == &OSIdleTaskTCB ) {(1) 15 if (OSRdyList[0].HeadPtr->TaskDelayTicks == 0) { 16 OSTCBHighRdyPtr = OSRdyList[0].HeadPtr; 17 } else if (OSRdyList[1].HeadPtr->TaskDelayTicks == 0) { 18 OSTCBHighRdyPtr = OSRdyList[1].HeadPtr; 19 } else { 20 /* 任务延时均没有到期则返回,继续执行空闲任务 */ 21 return; 22 } 23 } else {(2) 24 /*如果是task1或者task2,则检查另外一个任务, 25 *如果另外的任务不在延时中,则切换到该任务 26 *否则,判断当前任务是否应该进入延时状态, 27 *如果是,则切换到空闲任务,否则就不进行任何切换 */ 28 if (OSTCBCurPtr == OSRdyList[0].HeadPtr) { 29 if (OSRdyList[1].HeadPtr->TaskDelayTicks == 0) { 30 OSTCBHighRdyPtr = OSRdyList[1].HeadPtr; 31 } else if (OSTCBCurPtr->TaskDelayTicks != 0) { 32 OSTCBHighRdyPtr = &OSIdleTaskTCB; 33 } else { 34 /* 返回,不进行切换,因为两个任务都处于延时状态 */ 35 return; 36 } 37 } else if (OSTCBCurPtr == OSRdyList[1].HeadPtr) { 38 if (OSRdyList[0].HeadPtr->TaskDelayTicks == 0) { 39 OSTCBHighRdyPtr = OSRdyList[0].HeadPtr; 40 } else if (OSTCBCurPtr->TaskDelayTicks != 0) { 41 OSTCBHighRdyPtr = &OSIdleTaskTCB; 42 } else { 43 /* 返回,不进行切换,因为两个任务都处于延时中 */ 44 return; 45 } 46 } 47 } 48 49 /* 任务切换 */ 50 OS_TASK_SW();(3) 51 }
代码清单5-11(1):如果当前任务是空闲任务,则尝试执行任务1或者任务2,看看其延时时间是否结束,如果任务的延时时间均没有到期,就返回继续执行空闲任务。
代码清单5-11(2):如果当前任务不是空闲任务,则会执行到此,那就看看当前任务是哪个任务。无论是哪个任务,都要检查另外一个任务是否处于延时状态,如果没有延时,就切换到该任务,如果处于延时状态,则判断当前任务是否应该进入延时状态,如果是,则切换到空闲任务,否则不进行任务切换。
代码清单5-11(3):任务切换,实际就是触发PendSV异常。