μC/OS-III内核实现与应用开发实战指南:基于STM32
上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异常。