当前位置: 首页 > news >正文

RTOS-F429-HAL-绝对延时和相对延时(2026/7/31)

目录

一:vTaskDelayUntil() — 绝对延时

1:函数原型

2:怎么用

3:跟 vTaskDelay 的语法对比

二:rtos\9\ 改动清单

1:freertos_demo.c

2:main.c

3:时间轴推演

task2(prio=5, 绝对延时) task1(prio=3, 相对延时)

task2(prio=3, 绝对延时) task1(prio=5, 相对延时)

三:生活化解释

1:vTaskDelay — "从现在开始算,睡多久"

2:vTaskDelayUntil — "定一个固定的闹钟时间"

3:一张图对比

4:什么时候用哪个


一:vTaskDelayUntil()— 绝对延时

1:函数原型

void vTaskDelayUntil( TickType_t * const pxPreviousWakeTime, const TickType_t xTimeIncrement );
形参含义
pxPreviousWakeTime上一次醒来的绝对时间。第一次调用前必须用xTaskGetTickCount()初始化。函数内部每次调用自动更新这个值。
xTimeIncrement周期时长(单位:tick)。每次醒来后间隔多久再醒。

返值:无。

需要宏INCLUDE_vTaskDelayUntil = 1✅ 我们已开

2:怎么用

TickType_t xLastWakeTime = xTaskGetTickCount(); // 记下"现在是几点" ​ while (1) { // 干活... vTaskDelayUntil(&xLastWakeTime, 500); // 下次醒 = xLastWakeTime + 500 // ↑ ↑ // 它帮你 +500 更新 周期 500 个 tick }

第一次:xLastWakeTime = 100(假设当前时间)→ 睡到100+500=600第二次:xLastWakeTime = 600→ 睡到600+500=1100第三次:xLastWakeTime = 1100→ 睡到1100+500=1600

内部自动帮你做了xLastWakeTime += 500,你不用手动加。

3:跟vTaskDelay的语法对比

// 相对延时:就一个参数,睡多久 vTaskDelay(500); ​ // 绝对延时:多一个"上次几点醒的"变量来锚定节奏 TickType_t wake = xTaskGetTickCount(); vTaskDelayUntil(&wake, 500); // wake 必须传地址,函数内部会更新它

二:rtos\9\ 改动清单

1:freertos_demo.c

行号内容
37-38task1(prio=3)、task2(prio=5)——高优先级抢占低优先级
88-98task1:vTaskDelay(500)相对延时,周期会漂
108-119task2:vTaskDelayUntil(&xLastWakeTime, 500)绝对延时,不漂

2:main.c

行号内容
5-7去掉 Key.h/TIM6.h(本实验不需要按键和运行时间统计)
18-20去掉 Key_Init()/ConfigureTimeForRunTimeStats()
27printf 标题 →vTaskDelay vs vTaskDelayUntil Test!

代码很简洁。用示波器看 PH10(红灯, task1) 和 PH11(绿灯, task2):

  • task2 绿灯:精确 500ms 一个周期,不漂

  • task1 红灯:~500ms 但有抖动,因为会被 task2 抢或者起步晚了

没示波器的话看着灯闪也行,肉眼分不出,重点是用逻辑分析仪/示波器看差异。

3:时间轴推演

task2(prio=5, 绝对延时) task1(prio=3, 相对延时)
​ t=0: task2(prio=5) 跑 LED1翻 → delay_ms(20) → vTaskDelayUntil → 睡到 t=500 ​ t=20: task1(prio=3) 拿到 CPU(task2 在睡) LED0翻 → delay_ms(20) → vTaskDelay(500) → 睡到 t=20+500=540 ​ t=500: task2 准时醒 LED1翻 → delay_ms(20) → t=520 vTaskDelayUntil → 睡到 t=1000 ​ t=540: task1 醒(task2 在睡,没人抢) LED0翻 → delay_ms(20) → t=560 vTaskDelay(500) → 睡到 t=1060 ​ ​ task1 周期:第一次翻灯 t=20,第二次 t=540 → 520ms ​ task2 周期:第一次翻灯 t=0,第二次 t=500 → 500ms ​ 差的那 20ms 不是被抢了 CPU——task2 醒的时候 task1 本来就在睡。差的是开头 task2 先占了 20ms,task1 天生起步晚了 20ms。之后两家的唤醒时间永远错开,谁也不抢谁,各过各的。 ​ 那之前说的"抢占导致波形拉长"是上一节的场景——task1 优先级更高的时候才会发生(task1 在跑 delay_ms 期间,task2 的绝对时间到了,但 task2 优先级低,抢不进去,只能等 task1 腾出手,所以 task2 的 500ms 才变成 ~520ms)。 ​ 这一节的结论更简单:task2 优先级高就先跑,占了前面 20ms,task1 起步晚,周期自然长。
task2(prio=3, 绝对延时) task1(prio=5, 相对延时)
两个任务都做同一件事:翻转 LED → delay_ms(20) 忙等 → 延时。区别只在延时方式。 ​ ​ t=0 调度器启动 task1(prio=5,更高) 先跑 ├── LED0 翻转(瞬间) ├── delay_ms(20) → 忙等 20ms,CPU 不释放 └── vTaskDelay(500) → 阻塞,记录"500ms 后叫醒我",将于t=520ms时醒来。 t≈20 task2(prio=3,更低) 终于等到 CPU ├── xLastWakeTime = xTaskGetTickCount() → 记下"现在是 20" ├── LED1 翻转 ├── delay_ms(20) → 忙等 20ms,t≈40 └── vTaskDelayUntil(&wake, 500) → 计算:下次醒 = 20 + 500 = t=520 → 现在才 t=40,睡 480ms ​ t=520 task1 的 vTaskDelay(500) 到期,醒了 → task1 优先级 5 > task2 优先级 3, //task1 先跑!,把task2抢占了,两人同时从t=520ms醒来!!!!!!!!!! ├── LED0 翻转 └── delay_ms(20) → t≈540 ​ t=540 task2 的 vTaskDelayUntil 也到期了(应该 t=520 醒的,被 task1 拖到 540) → 已经错过了 20ms!立刻跑 ├── LED1 翻转 ├── delay_ms(20) → t≈560 └── vTaskDelayUntil:xLastWakeTime += 500 → 下次醒 = 20+500+500 = t=1020 实际睡多久?1020 - 560 = 460ms ← ★ 比 500 短! ​ t≈1040 task1 又醒了(520+500=1020 + delay_ms 20 = t≈1040) → 又抢占! 为什么示波器上看到的是 ~496ms 而不是 500ms? 看上图——task2 每次都被 task1 拖后腿,但 vTaskDelayUntil 死守着绝对时间点。你迟到了它就缩短下一段睡眠来追回来,所以示波器上 task2 的 LED 周期会围绕 500ms 上下抖动,有时候是 496ms(在追)、有时候是 504ms(被拖)。 ​ 这就是绝对延时的意义:长期来看平均周期精确是 500ms,不漂移。反观 task1 的 vTaskDelay,每次都在漂,100 次以后可能漂出几十毫秒。 ​ 一句话 vTaskDelay = 倒计时闹钟,晚起了就整体漂移。vTaskDelayUntil = 固定时刻闹钟,晚起了就自己缩短下一次睡眠来追回去,长期节奏永远不变。你示波器看到的 496ms 就是因为 task2 在"追"被 task1 拖后腿的进度。

三:生活化解释

1:vTaskDelay — "从现在开始算,睡多久"

vTaskDelay(500); // 从现在起,睡 500ms

生活例子:午休闹钟

你说:"从现开始睡 30 分钟" → 设了个倒计时 30 分钟 BUT:你在床上刷了 10 分钟手机才真的闭眼 → 实际醒来是 40 分钟后(刷手机也算在了"睡之前"的时间里) → 你的午休节奏漂移了

代码里的后果

一个任务每 100ms 打印一次: ​ 第 1 次:t=0 → 打印 → vTaskDelay(100) → t=100ms 醒来 第 2 次:t=100 → 打印 → 但!打印花了 5ms → vTaskDelay(100) → t=205ms 醒来 第 3 次:t=205 → 打印(5ms) → vTaskDelay(100) → t=310ms 醒来 第 4 次:t=310 → ... ​ 每次都在漂移,100 次以后可能差了半秒!

2:vTaskDelayUntil — "定一个固定的闹钟时间"

TickType_t last_wake = xTaskGetTickCount(); // 记下"起床时间" while (1) { // 干活... vTaskDelayUntil(&last_wake, 100); // 不管刚才干了多久,下次必须是 last_wake+100ms }

生活例子:学校上课铃

上课铃每隔 45 分钟响一次——不管你是准时回到座位还是磨蹭了 3 分钟: 第一节:9:00 响铃 → 上课 45 分钟 第二节:9:45 响铃 ← 固定!不是"从第一节下课开始 +45" 第三节:10:30 响铃 ← 固定! 即使你课间拖堂了 5 分钟,下一节的**响铃时间不变**。

代码里的效果

第 1 次:t=0 → 打印(5ms) → vTaskDelayUntil(&wake, 100) → t=100 准时醒 第 2 次:t=100 → 打印(5ms) → vTaskDelayUntil(&wake, 100) → t=200 准时醒 第 3 次:t=200 → 打印(5ms) → vTaskDelayUntil(&wake, 100) → t=300 准时醒 不管每次打印花了 5ms 还是 50ms,下一次醒来的**绝对时间点不变**!

3:一张图对比

vTaskDelay(相对): 干活→睡100ms→干活→睡100ms→干活→睡100ms→... ↑ ↑ 漂了5ms ↑ 漂了10ms 节奏越来越偏 vTaskDelayUntil(绝对): t=0 t=100 t=200 t=300 t=400 ← 固定的绝对时间点 │ │ │ │ │ 干活 干活 干活 干活 干活 ↑ ↑ ↑ ↑ ↑ 每次都在同一个节拍上,不漂移

4:什么时候用哪个

场景用哪个
无所谓精确周期,随便睡一下vTaskDelay(100)
周期性采集数据(ADC 采样)vTaskDelayUntil()
周期性发送心跳包vTaskDelayUntil()
按键扫描、LED 闪烁vTaskDelay(10)够用了

一句话vTaskDelay= "从刚才睡醒开始倒计时",每次会漂移。vTaskDelayUntil= "定好下一次醒来的绝对时间",不管中间折腾了多久,节奏永远不乱。

http://www.jsqmd.com/news/1301561/

相关文章:

  • 从视频中智能提取PPT:如何用计算机视觉技术将视频内容转化为可编辑文档
  • 早晚都可用的修护精华OEM推荐:从核心定义到实践路径的深度解析 - 汇聚至此
  • 如何5分钟掌握YimMenu:GTA5最强防崩溃菜单完整指南
  • 30分钟从零搭建AI Agent:LangChain实战指南与核心原理
  • 杭州银行与品牌金店黄金回收模式全面对比参考 - 日常比对手册
  • 字节跳动发布 Seedance 2.5,视频生成模型从创意工具走向产业生产力
  • 2026 年沈阳值得关注的财税代办服务机构盘点:辽宁省信誉分第一的头部财税公司深度盘点 - 财税推荐官
  • GoldHEN Cheats Manager终极指南:1490+款PS4游戏修改神器免费使用教程
  • 【AI工具产品化黄金公式】:如何用1个Prompt+1套API+1页落地页,3周冷启动获客5000+
  • Python并发爬虫实战:多线程与多进程架构设计与性能优化
  • 【编译链接】
  • Win11Debloat:3分钟让你的Windows系统焕然一新的终极优化工具
  • 佛山市民速看!2026 黄金回收诚信名单出炉,多家合规门店公示,卖金认准三证一价安心变现 - 好物测评局
  • 计算机单片机毕设实战-基于 C 语言单片机篮球裁判辅助设备设计与开发 基于 STM32 单片机球类赛事计时计分平台搭建(015101)
  • 终极魔兽争霸3优化指南:WarcraftHelper让你的经典游戏重获新生
  • BilibiliDown完整指南:3步轻松下载B站视频和音频的终极教程
  • 终极PPT计时器:告别演讲超时的完整解决方案
  • UDP协议下实现可靠心跳检测的技术方案
  • 水彩晕染不真实?深度解析GAN-based Texture Prior在扩散模型中的3处隐式偏差(附PyTorch修复补丁)
  • 通州万达附近名包回收|2026 年 8 月全套香奈儿、爱马仕闲置包估价参考 - 生活时报
  • StreamCap实战指南:3步构建你的智能直播录制工作流
  • 提示LLM词
  • 系统性焦虑治理:现代社会通过婚恋、生育、衰老、职场焦虑完成全民秩序通知与行为规训
  • 品牌金饰出手须知,成都锦江区黄金回收不会纳入品牌附加价值核算价格 - 融媒生活
  • 抖音批量下载神器终极指南:5分钟学会免费下载无水印视频、音乐和合集
  • 2026年湖北省正规武术学校榜单名单及办学资质查询! - 圣龙武术朱老师
  • 直接优化策略:策略梯度、Actor-Critic、Advantage 与重要性采样
  • 射击精度基础:归零调整原理与实战操作详解
  • XUnity自动翻译插件:5分钟实现游戏实时汉化,告别语言障碍
  • 高校技术转移办公室资源配置优化与科研成果转化实践