在 FreeRTOS 中,延迟功能对于任务调度至关重要。vTaskDelay
、vTaskDelayUntil
和 xtestdelay
是常用的延迟函数,但它们在功能和适用场景上有所不同。本文将简要说明它们的区别,并通过示例代码展示每个函数的典型用法。每个函数的具体细节请参考本期刊的其它文章!
FreeRTOS 延迟函数概述
vTaskDelay
vTaskDelay
是 FreeRTOS 提供的标准延迟函数,用于将当前任务阻塞指定的时间。它的主要作用是让任务在一段时间内不参与调度,从而让其他任务有机会运行。
语法
void vTaskDelay(const TickType_t xTicksToDelay);
xTicksToDelay
:延迟的时间长度,以系统时钟节拍 (ticks) 为单位。
示例代码
void vTaskA(void *pvParameters)
{for( ;; ){// 执行任务操作// ...// 延迟 1000 个 ticksvTaskDelay(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 个 ticksxtestdelay(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 个 ticksvTaskDelay(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 个 ticksxtestdelay(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 中实现任务调度和延迟。