FreeRTOS中的两个Delay函数

        FreeRTOS 提供了两个主要的延时函数:vTaskDelay 和 vTaskDelayUntil。虽然它们都用于引入任务延迟,但它们的使用场景和实现机制有所不同。

vTaskDelay

概述

vTaskDelay 是基于相对时间的延时函数。它根据当前时间进行延时,使任务进入阻塞状态,并在指定的Tick数后重新进入就绪态。

函数原型
void vTaskDelay( const TickType_t xTicksToDelay );
参数
  • xTicksToDelay:延迟的 Tick 数数量。
示例

任务每隔100个Tick周期执行一次:

void vTaskFunction( void * pvParameters )
{
    for( ;; )
    {
        // 执行任务
        PerformTask();
        
        // 延迟100个Tick周期
        vTaskDelay(100);
    }
}
特点
  • 简单易用:只需指定要延迟的 Tick 数量。
  • 无法保证精确的周期时间:由于任务的开始时间不固定,无法保证精确的周期时间。
  • 适用于不可预知的延迟:适合那些不需要精确周期的场景。

vTaskDelayUntil

概述

vTaskDelayUntil 是基于绝对时间的延时函数。它用于实现精确的周期性任务调度,通过设置绝对的唤醒时间来达到精准的控制。

函数原型
BaseType_t xTaskDelayUntil( TickType_t * const pxPreviousWakeTime, const TickType_t xTimeIncrement );
参数
  • pxPreviousWakeTime:指向任务上次被唤醒时间的指针。
  • xTimeIncrement:周期性唤醒时间间隔。
示例

任务每隔100个Tick周期执行一次,使用 vTaskDelayUntil 保证周期的精确度:

void vTaskFunction( void * pvParameters )
{
    TickType_t xLastWakeTime;
    const TickType_t xFrequency = 100;

    // 初始化上次唤醒时间
    xLastWakeTime = xTaskGetTickCount();

    for( ;; )
    {
        // 执行任务
        PerformTask();

        // 相对于上次唤醒时间进行延迟,确保固定周期
        vTaskDelayUntil( &xLastWakeTime, xFrequency );
    }
}
特点
  • 精确的周期性调度:基于绝对时间,能够确保任务在精确的周期时间被唤醒。
  • 避免累计误差:通过相对于上次唤醒时间进行延迟,避免了累计误差。
  • 适用于周期性任务:特别适合那些需要严格周期执行的任务。

疑问:vTaskDelayUntil 是基于绝对时间的延时函数,在上述例子中如果任务执行的时间大于100tick 这种情况会怎么处理?

答:这种情况通常叫做“时间噪音”或者“任务过载”,意味着任务的执行时间超过了预定的周期时间。如果任务的执行时间超过了周期时间 xTimeIncrement,那么下次调用 vTaskDelayUntil 时,会发现唤醒时间已经过了,函数会立即返回。

两个Delay函数的比较

特性vTaskDelayvTaskDelayUntil
延迟类型相对时间绝对时间
典型应用场景不需要精确周期性的任务需要精确周期性调度的任务
累计误差存在可能不存在
实现的复杂性简单较复杂

总结

  • vTaskDelay 更加简单,适用于不需要严格周期性的任务。
  • vTaskDelayUntil 提供了更高的定时精度,是实现周期性任务的理想选择。

  • 10
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
FreeRTOS ,延时函数应该使用 vTaskDelay() 函数来实现,而不是使用 delay_us() 函数。因为在 FreeRTOS ,任务的调度是由操作系统来完成的,所以在任务使用延时函数可以让任务挂起一段时间,让其他任务有机会被调度执行。 如果你需要在任务实现微秒级别的延时,可以使用 FreeRTOS 的 Tick 定时器来实现。具体方法如下: 1. 获取当前系统 Tick 值 ```c uint32_t current_tick = xTaskGetTickCount(); ``` 2. 计算延时 Tick 数 ```c uint32_t delay_tick = (uint32_t)(delay_us * (configTICK_RATE_HZ / 1000000)); ``` 其delay_us 是需要延时的微秒数,configTICK_RATE_HZ 是 FreeRTOS 配置文件定义的系统 Tick 频率,一般默认为 1000。 3. 等待延时时间到达 ```c vTaskDelayUntil(&current_tick, delay_tick); ``` 其,vTaskDelayUntil() 函数会挂起任务,直到当前系统 Tick 值达到指定的延时 Tick 数为止。 完整的代码示例: ```c #include "FreeRTOS.h" #include "task.h" void task_delay_us(uint32_t delay_us) { uint32_t current_tick = xTaskGetTickCount(); uint32_t delay_tick = (uint32_t)(delay_us * (configTICK_RATE_HZ / 1000000)); vTaskDelayUntil(&current_tick, delay_tick); } void task1(void *pvParameters) { while (1) { // 延时 100 微秒 task_delay_us(100); // 执行任务代码 } } void task2(void *pvParameters) { while (1) { // 延时 200 微秒 task_delay_us(200); // 执行任务代码 } } int main() { // 创建任务 xTaskCreate(task1, "task1", configMINIMAL_STACK_SIZE, NULL, 1, NULL); xTaskCreate(task2, "task2", configMINIMAL_STACK_SIZE, NULL, 1, NULL); // 启动调度器 vTaskStartScheduler(); return 0; } ``` 在上面的例子,我们创建了两个任务 task1 和 task2,它们分别每隔 100 微秒和 200 微秒执行一次。通过使用 vTaskDelayUntil() 函数,可以保证任务的延时精度达到微秒级别。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值