在 FreeRTOS 中,延迟功能对于任务调度至关重要。vTaskDelay
、vTaskDelayUntil
和 xtestdelay
是常用的延迟函数,但它们在功能和适用场景上有所不同。本文将简要说明它们的区别,并通过示例代码展示每个函数的典型用法。每个函数的具体细节请参考本期刊的其它文章!
FreeRTOS 延迟函数概述
vTaskDelay
vTaskDelay
是 FreeRTOS 提供的标准延迟函数,用于将当前任务阻塞指定的时间。它的主要作用是让任务在一段时间内不参与调度,从而让其他任务有机会运行。
语法
void vTaskDelay(const TickType_t xTicksToDelay);
xTicksToDelay
:延迟的时间长度,以系统时钟节拍 (ticks) 为单位。
示例代码
void vTaskA(void *pvParameters)
{
for( ;; )
{
// 执行任务操作
// ...
// 延迟 1000 个 ticks
vTaskDelay(pdMS_TO_TICKS(1000)); // 延迟 1 秒
}
}
在这个例子中,vTaskA
每次循环时会延迟 1000 个时钟节拍 (1 秒),然后再继续执行。
vTaskDelayUntil
vTaskDelayUntil
是 FreeRTOS 的另一种延迟机制,用于创建精确的周期性延迟。它确保任务每隔固定时间间隔运行,不受其他任务执行时间的影响。
语法
BaseType_t xTaskDelayUntil(TickType_t * const pxPreviousWakeTime, const TickType_t xTimeIncrement);
pxPreviousWakeTime
:一个保存上一次唤醒时间的变量的指针。xTimeIncrement
:任务间隔的时间,以系统时钟节拍 (ticks) 为单位。
示例代码
void vTaskB(void *pvParameters)
{
TickType_t xLastWakeTime;
const TickType_t xFrequency = pdMS_TO_TICKS(1000); // 1 秒
// 初始化上一次唤醒时间
xLastWakeTime = xTaskGetTickCount();
for( ;; )
{
// 等待下一个周期
vTaskDelayUntil(&xLastWakeTime, xFrequency);
// 执行任务操作
// ...
}
}
在这个例子中,vTaskB
在每次循环时会精确地延迟 1 秒,无论其他任务的执行情况如何,都能保证固定周期运行。
xtestdelay
xtestdelay
通常不是标准的 FreeRTOS API 函数,而可能是某些示例代码或用户定义的函数。它的功能和 vTaskDelay
类似,用于延迟任务的执行,但通常用于测试或调试目的,或在某些特定场景下用作简单的延迟函数。
示例代码
假设 xtestdelay
是用户自定义的简单延迟函数:
void xtestdelay(TickType_t xTicksToDelay)
{
// 实现一个简单的延迟
TickType_t xCurrentTime = xTaskGetTickCount();
while ((xTaskGetTickCount() - xCurrentTime) < xTicksToDelay)
{
// 忙等待
}
}
void vTaskC(void *pvParameters)
{
for( ;; )
{
// 执行任务操作
// ...
// 延迟 500 个 ticks
xtestdelay(pdMS_TO_TICKS(500)); // 延迟 500 毫秒
}
}
区别
vTaskDelay
:让任务延迟指定的时间,从调用时刻开始计算,适合简单的延迟场景。vTaskDelayUntil
:提供精确的周期性延迟,从上次唤醒时间开始计算,适用于需要严格周期控制的任务。xtestdelay
:通常是用户自定义的延迟函数,用于测试或特定场景下的简单延迟,可能通过忙等待实现,不建议用于实际生产环境。
完整代码示例
以下是完整代码示例,展示如何在 FreeRTOS 中使用 vTaskDelay
、vTaskDelayUntil
和 xtestdelay
:
#include "FreeRTOS.h"
#include "task.h"
// 任务 A 使用 vTaskDelay
void vTaskA(void *pvParameters)
{
for( ;; )
{
// 打印任务 A 的信息
printf("Task A is running\n");
// 延迟 1000 个 ticks
vTaskDelay(pdMS_TO_TICKS(1000)); // 延迟 1 秒
}
}
// 任务 B 使用 vTaskDelayUntil
void vTaskB(void *pvParameters)
{
TickType_t xLastWakeTime;
const TickType_t xFrequency = pdMS_TO_TICKS(1000); // 1 秒
// 初始化上一次唤醒时间
xLastWakeTime = xTaskGetTickCount();
for( ;; )
{
// 等待下一个周期
vTaskDelayUntil(&xLastWakeTime, xFrequency);
// 打印任务 B 的信息
printf("Task B is running\n");
}
}
// xtestdelay 函数实现
void xtestdelay(TickType_t xTicksToDelay)
{
TickType_t xCurrentTime = xTaskGetTickCount();
while ((xTaskGetTickCount() - xCurrentTime) < xTicksToDelay)
{
// 忙等待
}
}
// 任务 C 使用 xtestdelay
void vTaskC(void *pvParameters)
{
for( ;; )
{
// 打印任务 C 的信息
printf("Task C is running\n");
// 延迟 500 个 ticks
xtestdelay(pdMS_TO_TICKS(500)); // 延迟 500 毫秒
}
}
int main(void)
{
// 创建任务
xTaskCreate(vTaskA, "TaskA", configMINIMAL_STACK_SIZE, NULL, 3, NULL);
xTaskCreate(vTaskB, "TaskB", configMINIMAL_STACK_SIZE, NULL, 3, NULL);
xTaskCreate(vTaskC, "TaskC", configMINIMAL_STACK_SIZE, NULL, 3, NULL);
// 启动调度器
vTaskStartScheduler();
// 调度器应该永不返回
for( ;; );
}
在这个示例中,我们创建了三个任务,每个任务使用不同的延迟机制。vTaskA
使用 vTaskDelay
进行简单延迟,vTaskB
使用 vTaskDelayUntil
进行周期性延迟,vTaskC
使用自定义的 xtestdelay
进行忙等待延迟。这些示例展示了如何在 FreeRTOS 中实现任务调度和延迟。