os系统

          任务延时函数OSTimeDly

功能:调用该函数的任务将自己延时一段时间并执行一次任务调度,一旦规定的延时时间完成或有其它的任务通过调用OSTimeDlyResume()取消了延时,调用OSTimeDly()函数的任务马上进入就绪状态(前提是先将任务调度后执行的任务执行到程序尾,且调用OSTimeDly的任务此时优先级最高)。

3.2.3 任务延时函数OSTimeDly

任务延时函数OSTimeDly用于阻塞任务一定时间,这个时间以参数的形式给出。如果这个参数的值是N,那么在N个时间片(时钟滴答)之后,任务才能回到就绪态获得继续运行的机会。如果参数的值是0,就不会阻塞任务。任务延时函数OSTimeDly的代码分析如程序3.4所示。

程序3.4 任务延时函数OSTimeDly代码分析
 

  1. void OSTimeDly (INT32U ticks)  
  2. {  
  3. INT8U y;  
  4. if (OSIntNesting > 0u) { /*中断服务程序不能延时*/  
  5. return;  
  6. }  
  7. if (OSLockNesting > 0u) { /*如果调度器被上锁不能延时,因为延时后就要进行调度*/  
  8. return;  
  9. }  
  10. if (ticks > 0u) { /*如果延时时间大于0才会进行延时*/  
  11. OS_ENTER_CRITICAL();  
  12. /*在就绪表和就绪组中取消当前任务的就绪标志*/  
  13. y=OSTCBCur->OSTCBY;  
  14. OSRdyTbl[y] &= (OS_PRIO)~OSTCBCur->OSTCBBitX;  
  15. if (OSRdyTbl[y] == 0u) {  
  16. OSRdyGrp &= (OS_PRIO)~OSTCBCur->OSTCBBitY;  
  17. }  
  18. /*给任务块的OSTCBDly项赋值延时时间*/  
  19. OSTCBCur->OSTCBDly = ticks; /* 向任务控制块TCB装载延时时间 */  
  20. OS_EXIT_CRITICAL();  
  21. OS_Sched();/* 进行一次任务调度*/  
  22. }  

本段代码层次清晰且比较简单。OSLockNesting是调度锁,也就是说,如果OSLockNesting>0,那么不允许进行任务调度。因为任务延时的时候要中止当前任务的执行,所以要进行调度,因此在调度锁有效的情况下是不能执行任务延时的。如果延时时间大于0,那么就要进行一次任务调度,将当前的任务的就绪标志取消,也就是对就绪表和就绪组的相关操作。之后将延时时间给任务块的OSTCBDly项以对延时进行计数。操作系统在每个时钟中断都要对每个OSTCBDly大于0的任务块的OSTCBDly进行减1操作和进行调度,那么当任务的延迟时间到了的时候(OSTCBDly为0)就可以恢复到就绪态。

需要注意的是,如果将任务延时1个时间片,调用OSTimeDly(1),会不会产生正确的结果呢?回答是否定的。这是因为任务在调用时间延时函数的时候可能已经马上就要发生时钟中断了,那么设置OSTCBDly的值为1,想延时10ms,然后系统切换到一个新的任务运行。在可能极短的时间,如0.5ms的时间后就进入时钟中断服务程序,立刻将OSTCBDly的值减到0了。调度器在调度的时候就会恢复这个才延时了0.5ms的任务执行。可见,OSTimeDly的误差最大应该就是1个时间片的长度,OSTCBDly(1)不会刚好延时10ms,如果真的需要延时1个时间片,最好调用OSTCBDly(2)。

任务延时函数OSTimeDly的流程如图3.3所示。
 

原文地址:https://www.cnblogs.com/wgang171412/p/5036115.html