news 2026/5/20 14:55:01

FreeRTOS中的两个Delay函数(vTaskDelay vs vTaskDelayUntil)

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
FreeRTOS中的两个Delay函数(vTaskDelay vs vTaskDelayUntil)

一、核心概念先理清:Tick(系统节拍)

在讲延时函数前,先明确一个关键概念:系统节拍(Tick)

  • 它是 FreeRTOS 的最小时间单位,由 SysTick 定时器周期性中断产生(常见配置为 1ms/Tick)
  • 所有延时函数的参数,本质上都是基于 “Tick 数” 来计算的
  • 延时时间 ≈ Tick 数 × 单个 Tick 的周期(比如 1000 Tick ≈ 1000ms,即 1 秒)

二、vTaskDelay:相对延时,“从调用时起,等多久”

1. 函数原型与参数说明

void vTaskDelay( const TickType_t xTicksToDelay );
  • xTicksToDelay:需要等待的 Tick 数(相对当前调用时刻的延时)
  • 功能:任务进入阻塞态,至少等待指定数量的 Tick 中断后,才会重新进入就绪态

2. 核心原理与特点

  • 相对计时:延时的起点是 “调用vTaskDelay的那一刻”,和任务上一次执行的结束时间无关
  • 会产生周期漂移:如果任务内业务逻辑耗时不固定,会导致整体执行周期越来越不准
  • CPU 利用率高:延时期间任务主动让出 CPU,不会像裸机while(1)延时那样 “忙等”

3. 代码示例:基础用法

void vTaskExample(void *pvParameters) { while(1) { // 业务逻辑(耗时不确定) printf("任务执行中...\n"); vTaskDelay(pdMS_TO_TICKS(1000)); // 延时1000ms(1秒),从调用这一刻开始计时 } }

三、vTaskDelayUntil:绝对延时,“固定周期,精准唤醒”

1. 函数原型与参数说明

BaseType_t xTaskDelayUntil( TickType_t * const pxPreviousWakeTime, const TickType_t xTimeIncrement );
  • pxPreviousWakeTime上一次任务被唤醒的 Tick 时间指针,首次调用前必须用xTaskGetTickCount()初始化
  • xTimeIncrement:期望的固定周期(Tick 数,比如 1000 Tick=1 秒)
  • 功能:任务会阻塞到 “*pxPreviousWakeTime + xTimeIncrement” 这个绝对时刻再唤醒,保证整体周期恒定

2. 核心原理与特点

  • 绝对计时:延时的起点是 “上一次任务被唤醒的时刻”,会自动补偿任务内业务逻辑的耗时
  • 无周期漂移:无论单次任务内耗时多少,两次唤醒的时间间隔始终等于xTimeIncrement
  • 适合周期性任务:比如传感器定时采集、定时串口发送等需要固定周期的场景

3. 代码示例:标准用法

void vTaskExample(void *pvParameters) { TickType_t xLastWakeTime; const TickType_t xCycleTime = pdMS_TO_TICKS(1000); // 固定周期1000ms xLastWakeTime = xTaskGetTickCount(); // 首次调用前初始化上一次唤醒时间 while(1) { // 业务逻辑(耗时不确定) printf("任务执行中...\n"); // 阻塞到下一个周期的绝对时间点 vTaskDelayUntil(&xLastWakeTime, xCycleTime); } }

四、两者核心区别对比

特性vTaskDelayvTaskDelayUntil
计时方式相对调用时刻计时相对上一次唤醒时刻的绝对计时
周期稳定性会漂移,任务内耗时会影响周期无漂移,自动补偿任务内耗时
核心用途非周期性延时(按键消抖、单次等待)周期性任务(定时采集、定时控制)
使用复杂度简单,直接传 Tick 数即可需额外初始化xLastWakeTime变量
典型场景单次延时、非固定频率任务传感器定时采集、PWM 输出、定时通信

五、实战避坑指南

1. 关于 pdMS_TO_TICKS ()

不要直接写数字!用pdMS_TO_TICKS(ms)宏函数,自动把毫秒转换成对应 Tick 数,避免手动计算出错:

// 推荐写法(1000ms → 对应Tick数) vTaskDelay(pdMS_TO_TICKS(1000)); // 不推荐写法(硬编码,Tick配置改变后会出错) vTaskDelay(1000);

2. vTaskDelayUntil 必须初始化

首次调用前,一定要用xTaskGetTickCount()初始化xLastWakeTime,否则会导致延时异常:

// 错误写法(未初始化) TickType_t xLastWakeTime; vTaskDelayUntil(&xLastWakeTime, pdMS_TO_TICKS(1000)); // 正确写法 TickType_t xLastWakeTime = xTaskGetTickCount(); vTaskDelayUntil(&xLastWakeTime, pdMS_TO_TICKS(1000));

3. 不要在中断里调用

两个延时函数都只能在任务上下文中调用,中断服务函数里请用vTaskDelayUntilFromISR或其他中断安全 API。

4. 延时时间不能为 0

xTicksToDelayxTimeIncrement传 0 时,vTaskDelay会直接让出 CPU,而vTaskDelayUntil会立即返回,无法实现延时效果。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/5/20 14:55:00

3PEAK思瑞浦 TP1282L1-SR SOP8 运算放大器

特性 供电电压:4.5V至36V 偏移电压:最大150伏 与电源轨的差分输入电压范围,可作为比 较器工作 输入轨至-Vs,轨到轨输出 带宽:7MHz 峰值瞬态响应率:20V/us 优异的EMI抑制性能:1GHz时45dB 过温保护低噪声:1kHz时为25nV/√Hz .4 kV HBM,2 kV CDM, 400 mA 锁…

作者头像 李华
网站建设 2026/5/20 14:54:59

3PEAK思瑞浦 TP1284-TR TSSOP14 精密运放

特性 供电电压:4.5V至36V 偏移电压:150mV(最大) 与电源轨的差分输入电压范围,可作为比较器工作 输入轨至-Vs,轨到轨输出 带宽:7MHz噪声抑制性能:45dB1Hz 优异的EMI抑制性能:1GHz时为45dB 过温保护 低噪声:1kHz时为25nV/vHz 4 kVHBM,2kV CDM,4…

作者头像 李华
网站建设 2026/5/20 14:54:56

LXMusic音源终极配置指南:三步快速解锁全网音乐资源

LXMusic音源终极配置指南:三步快速解锁全网音乐资源 【免费下载链接】LXMusic音源 lxmusic(洛雪音乐)全网最新最全音源 项目地址: https://gitcode.com/guoyue2010/lxmusic- 你是否厌倦了在不同音乐平台间切换,只为找到一首…

作者头像 李华
网站建设 2026/5/20 14:54:47

【Linux系统】初见线程,概念与控制

内核与资源角度: 进程分配系统资源的基本实体。 线程CUP调度的基本单位。 初步理解线程: 在之前我们讲过,进程PCB(task_struct)代码和数据,如上图所示。 而线程是什么呢? 线程是进程的一个个分支!一个线…

作者头像 李华
网站建设 2026/5/20 14:54:39

3步上手!用可视化AI工作流让普通人也玩转AI自动化开发

3步上手!用可视化AI工作流让普通人也玩转AI自动化开发 【免费下载链接】Awesome-Dify-Workflow 分享一些好用的 Dify DSL 工作流程,自用、学习两相宜。 Sharing some Dify workflows. 项目地址: https://gitcode.com/GitHub_Trending/aw/Awesome-Dify-…

作者头像 李华