目录
一、延时函数分类:
1.相对延时:vTaskDelay
vTaskDelay
函数实现的是相对延时,即从当前时刻开始计算延时时间。这个函数会将任务挂起指定的系统时钟节拍数(ticks),直到指定的时间过去后,任务才会被重新调度执行。
vTaskDelay( xTicksToDelay );
xTicksToDelay
:这是要延时的系统时钟节拍数。可以通过pdMS_TO_TICKS
宏将毫秒数转换为系统时钟节拍数。
vTaskDelay( pdMS_TO_TICKS(100) );
这会导致任务挂起,直到100毫秒后。
2.绝对延时:vTaskDelayUntil
vTaskDelayUntil
函数实现的是绝对延时,即从某个特定的未来时刻开始计算延时时间。这个函数会将任务挂起,直到从上一次调用vTaskDelayUntil
后经过了指定的时间间隔。
vTaskDelayUntil( pxPreviousWakeTime, xTimeIncrement );
pxPreviousWakeTime
:这是一个指针,指向一个变量,该变量保存了任务上一次被唤醒的时间(以系统时钟节拍为单位)。每次调用vTaskDelayUntil
时,都应该传入同一个变量的地址。xTimeIncrement
:这是要延时的系统时钟节拍数。
例如,如果你想让任务每隔100毫秒执行一次,可以这样调用:
const TickType_t xDelay = pdMS_TO_TICKS(100);
TickType_t xLastWakeTime;
// 初始化xLastWakeTime
xLastWakeTime = xTaskGetTickCount();
while(1)
{
// 任务代码...
// 延时直到下一个100毫秒
vTaskDelayUntil( &xLastWakeTime, xDelay );
}
在这个循环中,xLastWakeTime
会在每次调用vTaskDelayUntil
时更新,以确保任务每隔100毫秒被唤醒一次。
总结来说,vTaskDelay
是基于当前时间的相对延时,而vTaskDelayUntil
是基于上一次唤醒时间的绝对延时。使用vTaskDelayUntil
可以更容易地实现周期性的任务调度。
二、vTaskDelay 与 HAL_Delay 的区别:
vTaskDelay
和HAL_Delay
是两个完全不同的函数,它们分别属于不同的系统和库,用于不同的上下文和目的。下面是它们的主要区别:
-
vTaskDelay
(FreeRTOS):vTaskDelay
是FreeRTOS实时操作系统(RTOS)中的一个函数。- 它用于实现任务的延时,使当前任务挂起指定的系统时钟节拍数(ticks),让出CPU给其他任务运行。
vTaskDelay
是协作式的,它不会立即阻塞CPU,而是让任务进入阻塞状态,直到指定的延时时间过去。- 它允许任务在延时期间被操作系统的其他部分(如中断服务例程)打断。
vTaskDelay
的参数是系统时钟节拍数,可以通过pdMS_TO_TICKS
宏将毫秒数转换为系统时钟节拍数。
-
HAL_Delay
(HAL库):HAL_Delay
是硬件抽象层(HAL)库中的一个函数,通常用于STM32等微控制器。- 它用于实现一个简单的延时,通常是通过阻塞CPU来实现的,即在延时期间CPU不做其他事情,只是等待。
HAL_Delay
是非协作式的,它会阻塞CPU,直到指定的毫秒数过去。- 它不允许在延时期间被中断打断,因此可能会影响系统的实时性。
HAL_Delay
的参数是毫秒数。
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();
}
}
__weak void HAL_Delay(uint32_t Delay)
{
uint32_t tickstart = HAL_GetTick();
uint32_t wait = Delay;
/* Add a freq to guarantee minimum wait */
if (wait < HAL_MAX_DELAY)
{
wait += (uint32_t)(uwTickFreq);
}
while ((HAL_GetTick() - tickstart) < wait)
{
}
}
vTaskDelay 作用是让任务阻塞,任务阻塞后,RTOS系统调用其它处于就绪状态的优先级最高的任务来执行。
HAL_Delay 一直不停的调用获取系统时间的函数,直到指定的时间流逝然后退出,故其占用了全部CPU时间。
在实际应用中,选择使用哪个函数取决于你的系统需求和上下文:
- 如果你在使用FreeRTOS,并且需要实现任务间的协作和调度,那么应该使用
vTaskDelay
。 - 如果你在使用STM32 HAL库,并且需要一个简单的CPU阻塞延时,那么可以使用
HAL_Delay
。
需要注意的是,HAL_Delay
可能会影响RTOS的调度,因为它会阻塞CPU,所以在使用RTOS的情况下,通常推荐使用vTaskDelay
或其他RTOS提供的延时函数。此外,HAL_Delay
通常依赖于系统的时钟配置,而vTaskDelay
则依赖于FreeRTOS的时钟节拍配置。