分享

FreeRTOS(V8.0.1)系统之vTaskDelay()和vTaskDelayUntil()

 毛豆1111 2015-02-12
  1. <pre name="code" class="objc">#if ( INCLUDE_vTaskDelay == 1 )  
  2.     //延时特定时间xTicksToDelay,这个时间需要转换为唤醒绝对时间xTimeToWake,  
  3.     //这样才能在与vTaskIncrementTick函数中操作的数值是一致的xTicksToDelay:延时的节拍数  
  4.     void vTaskDelay( const TickType_t xTicksToDelay )  
  5.     {  
  6.     TickType_t xTimeToWake;  
  7.     BaseType_t xAlreadyYielded = pdFALSE;  
  8.   
  9.         if( xTicksToDelay > ( TickType_t ) 0U )//若延迟的时间是0,就是调度器的重新启动。若延时时间大于0,执行延时操作。  
  10.         {  
  11.             configASSERT( uxSchedulerSuspended == 0 );  
  12.             vTaskSuspendAll();//系统维护一个uxSchedulerSuspended计数值,当其大于0时表示禁止调度;等于0时则表示允许调度。  
  13.             {  
  14.                 traceTASK_DELAY();  
  15.                 //计算唤醒时间--这可能会溢出,但不会有问题 ,大家会问为什么  
  16.                 //大家可以自己做个试验,两个uCHAR型数据相加,如果超过255,则等于多少?  
  17.                 xTimeToWake = xTickCount + xTicksToDelay;//任务的唤醒时间更新。  
  18.                 if( uxListRemove( &( pxCurrentTCB->xGenericListItem ) ) == ( UBaseType_t ) 0 )//若删除完后链表中没有任务  
  19.                 //把任务从当前运行链表中移除出去,然后把它添加到阻塞链表里面  
  20.                 {  
  21.                     //当前任务必须在就绪链表中,所以其是不必检查的,下面的宏定义可以直接调用  
  22.                     portRESET_READY_PRIORITY( pxCurrentTCB->uxPriority, uxTopReadyPriority );  
  23.                 }  
  24.                 else  
  25.                 {  
  26.                     mtCOVERAGE_TEST_MARKER();  
  27.                 }  
  28.                 prvAddCurrentTaskToDelayedList( xTimeToWake );  
  29.                 //prvAddCurrentTaskToDelayedList是一个函数,它是把当前的任务控制块,  
  30.                 //放进DelayedList链表中,而DelayedList有两个链表,一个是溢出的,一个是正在应用的,  
  31.                 //所以要根据传递进的参数xTimeToWake进行分别设置,如果是在当前的延时链表里就添加进现在的延时链表,  
  32.                 //如果计算出来后是溢出链表,则添加进溢出链表里面  
  33.             }  
  34.             xAlreadyYielded = xTaskResumeAll();//得到任務切換的具體情況,pdTRUE切换成功否则切换失败。  
  35.         }  
  36.         else  
  37.         {  
  38.             mtCOVERAGE_TEST_MARKER();  
  39.         }  
  40.         if( xAlreadyYielded == pdFALSE )//若上面的切换失败,或不需要延迟。直接进行切换。  
  41.         {  
  42.             portYIELD_WITHIN_API();  
  43.             //实际就是终端控制及状态寄存器ICSR,写位28为1悬起PendSV,进入到xPortPendSVHandler。  
  44.         }  
  45.         else  
  46.         {  
  47.             mtCOVERAGE_TEST_MARKER();  
  48.         }  
  49.     }  
  50.   
  51. #endif   
  1. #if ( INCLUDE_vTaskDelayUntil == 1 )  
  2.     void vTaskDelayUntil( TickType_t * const pxPreviousWakeTime, const TickType_t xTimeIncrement )  
  3. //参数:pxPreviousWakeTime---上一次调用本函数的时间   
  4. //      xTimeIncrement---相对于pxPreviousWakeTime本次延时的节拍数  
  5. //由于调用此函数的任务解除阻塞的时间是绝对时刻,比起相对于调用时刻的相对时间更精确(即比调用vTaskDelay()可以实现更精确的周期性)。  
  6. //pxPreviousWakeTime: 此参数命名时假定vTaskDelayUntil()用于实现某个任务以固定频率周期性执行。这种情况下pxPreviousWakeTime  
  7. //                    保存了任务上一次离开阻塞态(被唤醒)的时刻。这个时刻被用作一个参考点来计算该任务下一次离开阻塞态的时刻。  
  8. //xTimeIncrement: 此参数命名时同样是假定vTaskDelayUntil()用于实现某个任务以固定频率周期性执行 —— 这个频率就是由xTimeIncrement 指定的。   
  9. //                *xTimeIncrement 的单位是心跳周期, 可以使用常量portTICK_RATE_MS 将毫秒转换为心跳周期  
  10.     {  
  11.     TickType_t xTimeToWake;//和vTaskDelay函数中一样定义,最终得到xTimeToWake赋值给xGenericListItem .xItemValue  
  12.     BaseType_t xAlreadyYielded, xShouldDelay = pdFALSE;  
  13.   
  14.         configASSERT( pxPreviousWakeTime );  
  15.         configASSERT( ( xTimeIncrement > 0U ) );  
  16.         configASSERT( uxSchedulerSuspended == 0 );  
  17.   
  18.         vTaskSuspendAll();//调度器挂起  
  19.         {  
  20.             const TickType_t xConstTickCount = xTickCount;//xTickCount在这个函数里面不能改变,所以采用另外一个变量做优化。  
  21.             xTimeToWake = *pxPreviousWakeTime + xTimeIncrement; //计算下次唤醒的时刻.  
  22.   
  23.             if( xConstTickCount < *pxPreviousWakeTime )//说明 xTickCount 溢出了  
  24.             {  
  25.                 //pxPreviousWakeTime指向上一次的唤醒时间,这个地方有点难理解,可以这样说明:时间轴是一个往前的轴,  
  26.                 //是不会有溢出之说法,也就是说xTickCount永远都是大于唤醒时间的而不管哪一次的唤醒时间都是大于,  
  27.                 //但由于溢出的存在,所以有时候xTickCount会小于唤醒时间,这里就说明是小于上一次设置的唤醒时间,如果是就说明是溢出了  
  28.                 //::T3::::::T2:::::::::::::::::::::T1:::::::::::::::::::::::::::::::::::::T2:::::::::::::::::T3:::::::::*/  
  29.                 //            xTickCount    *pxPreviousWakeTime                       xTickCount       xTimeToWake*/  
  30.                 //T1对应*pxPreviousWakeTime ,T2对应xTickCount,T3对应xTimeToWake*/  
  31.                 //因为在运行这个程序时,任务因为运行了其它程序,造成了xTickCount和唤醒时间不是在同一个点上,要么大于*pxPreviousWakeTime,  
  32.                 //要么小于*pxPreviousWakeTime,就像T2一样,如果运行到T第一个T0处,那么,就相当于xTickCount已经溢出了,那么需要不  
  33.                 //需要延时,就要看xTimeToWake所处的位置了,如果没溢出,则说明不需要延时就可以调度任务  
  34.                 //,如果溢出了,还要看是否大于xTickCount,如果是才能算的上是真正的需要放入延时链表里面  
  35.                 if( ( xTimeToWake < *pxPreviousWakeTime ) && ( xTimeToWake > xConstTickCount ) )  
  36.                 //这时只有 xTimeToWake 也溢出了,并且 xTimeToWake > xConstTickCount 才需要休眠  
  37.                 {  
  38.                     xShouldDelay = pdTRUE;  
  39.                 }  
  40.                 else  
  41.                 {  
  42.                     mtCOVERAGE_TEST_MARKER();  
  43.                 }  
  44.             }  
  45.             else  
  46.             {  
  47.                 //下面两种情况才需要休眠  
  48.                 if( ( xTimeToWake < *pxPreviousWakeTime ) || ( xTimeToWake > xConstTickCount ) )  
  49.                 {  
  50.                     xShouldDelay = pdTRUE;  
  51.                 }  
  52.                 else  
  53.                 {  
  54.                     mtCOVERAGE_TEST_MARKER();  
  55.                 }  
  56.             }  
  57.             //为下一次 Delay 更新 pxPreviousWakeTime.  
  58.             *pxPreviousWakeTime = xTimeToWake;//把需要唤醒的绝对时间保存起来,保存到pxPreviousWakeTime指针变量里面  
  59.   
  60.             if( xShouldDelay != pdFALSE )//这时需要休眠,由上面的判断任务是否进入延时链表,如果不需要,则仍是当前运行的任务  
  61.             {  
  62.                 traceTASK_DELAY_UNTIL();  
  63.                 //从 Ready 链表中删除,加入 Blocked List  
  64.                 if( uxListRemove( &( pxCurrentTCB->xGenericListItem ) ) == ( UBaseType_t ) 0 )  
  65.                 {  
  66.                     portRESET_READY_PRIORITY( pxCurrentTCB->uxPriority, uxTopReadyPriority );  
  67.                 }  
  68.                 else  
  69.                 {  
  70.                     mtCOVERAGE_TEST_MARKER();  
  71.                 }  
  72.   
  73.                 prvAddCurrentTaskToDelayedList( xTimeToWake );  
  74.             }  
  75.             else  
  76.             {  
  77.                 mtCOVERAGE_TEST_MARKER();  
  78.             }  
  79.         }  
  80.         xAlreadyYielded = xTaskResumeAll();  
  81.         //在运行上面临界区的程序时,可能有任务需要调度,但因为调度器的挂起而没有被调度,只是给出了登记,  
  82.         //而这个xTaskResumeAll函数就是要把放进xPendingReadyList链表中的任务节点转移到真正的就绪链表pxReadyTasksLists里面,  
  83.         //如果任务是因为tick缺失或者因为在恢复实际走过的滴答数时有任务需要抢占CPU,则 xAlreadyYielded 都为真,  
  84.         //从而导致下面不会运行,如果没有被抢占也就是说当前还是处于最高级任务,但是上面的延时已经使其阻塞,从而在下面发生抢占  
  85.         if( xAlreadyYielded == pdFALSE )  
  86.         //强制自己交出CPU,使自身进入等待延时。个人认为:此处并不需要强制交出,如果上面并不需要加入延时链表,  
  87.         //表示还是运行的当前任务,如果这个任务仍然是最高级的,则并不需要切换  
  88.         {  
  89.             portYIELD_WITHIN_API();  
  90.         }  
  91.         else  
  92.         {  
  93.             mtCOVERAGE_TEST_MARKER();  
  94.         }  
  95.     }  
  96.   
  97. #endif  




    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多