两个Delay函数
有两个延时函数
vTaskDelay:至少等待指定个数的Tick Interrupt才能变为就绪态
xTaskDelayUtil:等待到指定的绝对时刻,才能变为就绪态
个人感觉这两个延时函数就是,比如一个我等3个小时,一个是我等到下午3点的区别。
两个函数的原型如下:
vTaskDelay:
void vTaskDelay( const TickType_t xTicksToDelay )
{
BaseType_t xAlreadyYielded = pdFALSE;
/* A delay time of zero just forces a reschedule. */
if( xTicksToDelay > ( TickType_t ) 0U )
{
configASSERT( uxSchedulerSuspended == 0 );
vTaskSuspendAll();
{
traceTASK_DELAY();
/* A task that is removed from the event list while the
* scheduler is suspended will not get placed in the ready
* list or removed from the blocked list until the scheduler
* is resumed.
*
* This task cannot be in an event list as it is the currently
* executing task. */
prvAddCurrentTaskToDelayedList( xTicksToDelay, pdFALSE );
}
xAlreadyYielded = xTaskResumeAll();
}
else
{
mtCOVERAGE_TEST_MARKER();
}
/* Force a reschedule if xTaskResumeAll has not already done so, we may
* have put ourselves to sleep. */
if( xAlreadyYielded == pdFALSE )
{
portYIELD_WITHIN_API();
}
else
{
mtCOVERAGE_TEST_MARKER();
}
}
xTaskDelayUtil
BaseType_t xTaskDelayUntil( TickType_t * const pxPreviousWakeTime,
const TickType_t xTimeIncrement )
{
TickType_t xTimeToWake;
BaseType_t xAlreadyYielded, xShouldDelay = pdFALSE;
configASSERT( pxPreviousWakeTime );
configASSERT( ( xTimeIncrement > 0U ) );
configASSERT( uxSchedulerSuspended == 0 );
vTaskSuspendAll();
{
/* Minor optimisation. The tick count cannot change in this
* block. */
const TickType_t xConstTickCount = xTickCount;
/* Generate the tick time at which the task wants to wake. */
xTimeToWake = *pxPreviousWakeTime + xTimeIncrement;
if( xConstTickCount < *pxPreviousWakeTime )
{
/* The tick count has overflowed since this function was
* lasted called. In this case the only time we should ever
* actually delay is if the wake time has also overflowed,
* and the wake time is greater than the tick time. When this
* is the case it is as if neither time had overflowed. */
if( ( xTimeToWake < *pxPreviousWakeTime ) && ( xTimeToWake > xConstTickCount ) )
{
xShouldDelay = pdTRUE;
}
else
{
mtCOVERAGE_TEST_MARKER();
}
}
else
{
/* The tick time has not overflowed. In this case we will
* delay if either the wake time has overflowed, and/or the
* tick time is less than the wake time. */
if( ( xTimeToWake < *pxPreviousWakeTime ) || ( xTimeToWake > xConstTickCount ) )
{
xShouldDelay = pdTRUE;
}
else
{
mtCOVERAGE_TEST_MARKER();
}
}
/* Update the wake time ready for the next call. */
*pxPreviousWakeTime = xTimeToWake;
if( xShouldDelay != pdFALSE )
{
traceTASK_DELAY_UNTIL( xTimeToWake );
/* prvAddCurrentTaskToDelayedList() needs the block time, not
* the time to wake, so subtract the current tick count. */
prvAddCurrentTaskToDelayedList( xTimeToWake - xConstTickCount, pdFALSE );
}
else
{
mtCOVERAGE_TEST_MARKER();
}
}
xAlreadyYielded = xTaskResumeAll();
/* Force a reschedule if xTaskResumeAll has not already done so, we may
* have put ourselves to sleep. */
if( xAlreadyYielded == pdFALSE )
{
portYIELD_WITHIN_API();
}
else
{
mtCOVERAGE_TEST_MARKER();
}
return xShouldDelay;
}
下面是图示:
使用vTaskDelay(n)时,进入,退出vTaskDelay的时间间隔至少是n个Tick中断
使用xTaskDelayUtil(&Pre,n)时,前后两次退出xTaskDelayUntil的时间至少是n个Tick中断
退出xTaskDelayUntil时任务就进入就绪态,一般都能得到执行机会
所以可以使用xTaskDelayUntil来让任务周期性的运行
实验证明
程序创建2个任务
Task1:
高优先级
设置变量flag为1,然后调用vTaskDelay(xDelay50ms)或vTaskDelayUntil(&xLastWakeTime,xDelay50ms)
Task2:
低优先级
设置变量flag=0
main函数代码如下:
int main(void)
{
prvSetupHardware();
/*Task1的优先级更高,Task1先执行*/
xTaskCreate(vTask1,"Task1",1000,NULL,2,NULL);
xTaskCreate(vTask2,"Task2",1000,NULL,1,NULL);
/*启动调度器*/
vTaskStartScheduler();
/*如果程序运行到这里,就表示出错了,一般是内存不足*/
return 0;
}
Task1的代码中使用条件开关来选择Delay函数,把#if 1 改为 #if 0 就可以使用vTaskDelayUntil,代码如下:
void vTask1(void *pvParameters)
{
const TickType_t xDelay50ms = pdMS_TO_TICKS(50UL);
TickType_t xLastWakeTime;
int i;
/*获得当前的Tick Count*/
xLastWakeTime = xTaskGetTickCount();
for(;;)
{
flag =1;
/*故意加入多个循环,让程序运行时间长一点*/
for(i=0;i<5;i++)
printf("Task1 is running\r\n");
#if 1
vTaskDelay(xDelay50ms);
#else
vTaskDelayUntil(&PreWakeTime,xDelay50ms);
}
}
使用MDK的逻辑分析仪,可以观察flag变量的bit波形,如下:
flag为1时表示,Task1正在运行,flag为0时表示Task2正在运行,也就是Task1处于阻塞状态
vTaskDelay:指定的是阻塞时间
vTaskDelayUntil:指定的是任务执行的间隔,周期