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

鸿蒙南向开发教程 Day 5:延时与系统节拍

目标:掌握 OpenHarmony 轻量系统的延时 API,理解osDelayosDelayUntil的区别
前置条件:已完成 Day 4 的定时器教程


一、工程结构

app/ ├── BUILD.gn └── 03_delay/ # 模块目录 ├── BUILD.gn └── demo.c # 延时测试代码

1.1app/BUILD.gn

import("//build/lite/config/component/lite_component.gni") lite_component("app") { features = [ "03_delay:delay_demo", # 引用 03_delay 模块 ] }

1.203_delay/BUILD.gn

static_library("delay_demo") { sources = [ "demo.c" ] include_dirs = [ "//utils/native/lite/include", "//kernel/liteos_m/components/cmsis/2.0", ] }

二、完整代码详解

2.1 头文件

#include<stdio.h>// 标准输入输出#include<unistd.h>// UNIX 标准函数#include"ohos_init.h"// OpenHarmony 系统初始化#include"cmsis_os2.h"// CMSIS-RTOS2 接口

2.2 宏定义

#defineSTACK_SIZE(1024)// 线程栈大小#defineDELAY_TICKS_100(100)// 100 个 tick 延时

2.3 延时测试主函数

voidrtosv2_delay_main(void){// 1. 获取当前系统 tick 计数printf("[Delay Test] Current system tick: %d.\r\n",osKernelGetTickCount());// 2. 相对延时:从当前时刻起延时 100 tickosStatus_tstatus=osDelay(DELAY_TICKS_100);printf("[Delay Test] osDelay, status: %d.\r\n",status);// 3. 再次获取 tick,验证延时效果printf("[Delay Test] Current system tick: %d.\r\n",osKernelGetTickCount());// 4. 计算目标 tick:当前 tick + 100uint32_ttick=osKernelGetTickCount();tick+=DELAY_TICKS_100;// 5. 绝对延时:延时到指定的 tick 值status=osDelayUntil(tick);printf("[Delay Test] osDelayUntil, status: %d.\r\n",status);// 6. 最终 tick 值printf("[Delay Test] Current system tick: %d.\r\n",osKernelGetTickCount());}

2.4 系统入口

staticvoidDelayTestTask(void){osThreadAttr_tattr={.name="rtosv2_delay_main",.attr_bits=0U,.cb_mem=NULL,.cb_size=0U,.stack_mem=NULL,.stack_size=STACK_SIZE,.priority=osPriorityNormal,};if(osThreadNew((osThreadFunc_t)rtosv2_delay_main,NULL,&attr)==NULL){printf("[DelayTestTask] Failed to create rtosv2_delay_main!\n");}}APP_FEATURE_INIT(DelayTestTask);

三、核心 API 详解

3.1osKernelGetTickCount— 获取系统 Tick 计数

uint32_tosKernelGetTickCount(void);
说明内容
功能获取系统启动以来的 tick 计数
返回值32 位无符号整数,从 0 开始递增
溢出约 49.7 天后溢出(1ms tick 时),CMSIS-RTOS2 已处理溢出兼容

什么是 Tick?

Tick 是 RTOS 的心跳节拍,由硬件定时器中断产生:

  • 默认配置:1 tick = 1 毫秒
  • 系统每 1ms 产生一次 tick 中断
  • 在 tick 中断中:更新计数器、检查线程调度、触发软件定时器
时间轴: 0ms 1ms 2ms 3ms ... 100ms 101ms │ │ │ │ │ │ Tick: 0 1 2 3 ... 100 101 ↑______↑______↑______↑____________↑_______↑ 硬件定时器中断(1ms 周期)

3.2osDelay— 相对延时

osStatus_tosDelay(uint32_tticks);
参数说明
ticks延时的 tick 数

特点

  • 相对延时:从调用时刻开始计算
  • 线程进入Blocked(阻塞)状态
  • 延时期间不占用 CPU,其他线程可运行

执行流程

时刻 T: 调用 osDelay(100) ↓ 线程阻塞,等待 100 tick ↓ 时刻 T+100: 线程唤醒,继续执行

⚠️注意osDelay的实际延时 ≥ 100 tick,因为线程唤醒后需要等待调度器分配 CPU。

3.3osDelayUntil— 绝对延时

osStatus_tosDelayUntil(uint32_tticks);
参数说明
ticks目标 tick 值(绝对时间点)

特点

  • 绝对延时:延时到指定的 tick 值
  • 用于周期性任务,保证执行间隔固定

典型用法 — 固定周期任务

voidperiodic_task(void){uint32_tnext_tick=osKernelGetTickCount();// 记录起始 tickwhile(1){next_tick+=100;// 下一次执行时间点:+100 tick// 执行业务代码do_work();osDelayUntil(next_tick);// 绝对延时到目标 tick}}

osDelayvsosDelayUntil对比

特性osDelay(100)osDelayUntil(T+100)
基准点调用时刻指定的绝对 tick 值
适用场景单次延时、不严格要求周期周期性任务、固定频率
误差累积有(每次调用都有偏差)无(始终对准目标 tick)
图示`—业务—

误差累积示例

假设do_work()执行耗时 5ms:

使用 osDelay(100): 0ms: 开始执行 5ms: 执行完毕 5ms: osDelay(100) → 105ms 唤醒 105ms: 开始执行 110ms: 执行完毕 110ms: osDelay(100) → 210ms 唤醒 ← 实际周期 = 105ms,累积偏差! 使用 osDelayUntil: 0ms: next = 0, 执行 5ms: 执行完毕 5ms: osDelayUntil(100) → 100ms 唤醒 100ms: next = 100, 执行 ← 周期严格 = 100ms,无累积偏差! 105ms: 执行完毕 105ms: osDelayUntil(200) → 200ms 唤醒

四、底层实现:LiteOS 原生延时

CMSIS-RTOS2 的延时 API 在 LiteOS-M 中的映射:

CMSIS-RTOS2LiteOS-M 原生说明
osKernelGetTickCountLOS_TickCountGet获取 tick 计数
osDelayLOS_TaskDelay相对延时
osDelayUntilLOS_TaskDelayUntil绝对延时

LiteOS-M 的延时实现:

  1. 将当前线程从Ready(就绪)队列移除
  2. 计算唤醒 tick 值,加入Delay(延时)队列
  3. 触发线程调度,切换至其他就绪线程
  4. 在每次 tick 中断中检查:若唤醒 tick 到达,将线程移回 Ready 队列

五、编译与验证

5.1 编译烧录

VSCode 点击BuildUpload,串口波特率115200

5.2 预期输出

[Delay Test] Current system tick: 1234. [Delay Test] osDelay, status: 0. [Delay Test] Current system tick: 1334. ← 增加了约 100 tick [Delay Test] osDelayUntil, status: 0. [Delay Test] Current system tick: 1434. ← 再次增加约 100 tick

实际 tick 值取决于系统启动后的运行时间,两次差值应接近 100。


六、总结

要点内容
Tick 概念系统心跳,默认 1ms,驱动调度
osDelay相对延时,从调用时刻起算
osDelayUntil绝对延时,到指定 tick 值
周期任务osDelayUntil避免误差累积
状态变化调用延时 → 线程进入 Blocked → tick 到达 → Ready → Running

七、下一步

Day 6 预告:互斥锁(Mutex)—— 多线程共享资源保护。

http://www.zskr.cn/news/1456264.html

相关文章:

  • 沥青混合料细观结构的三维粘弹本构及虚拟力学试验方案【附数据】
  • 别光会apt install了!手把手教你拆解deb包,读懂control文件里的“说明书”
  • 在线溶解氧仪十大品牌排行榜 - 水质仪表品牌排行榜
  • 为什么83%的AI评价项目半年内失败?资深架构师拆解4层技术-管理协同断层
  • Qwopus3.6-27B-v1-preview-GGUF未来路线图:更大规模训练与功能升级展望
  • 2026北京16区通用!家里发现天牛虫千万别忽视,木质家具根治方法 - 苏易修缮
  • 终极图像标注指南:5分钟掌握LabelImg创建AI训练数据
  • 基于T-S模糊模型的强流电子枪建模与控制算法改进【附仿真】
  • 基于宽动态视觉传感的GMAW机器人焊接偏差实时识别及电弧监测解析方案【附数据】
  • 旧Mac重生指南:使用OpenCore Legacy Patcher实现macOS系统升级
  • 显微操作系统怎么选?液压、电动、手动三大方案全面对比! - 实了个验
  • imFile下载管理器:5个颠覆性功能与3大实战技巧
  • Windows系统优化终极指南:Chris Titus Tech WinUtil一键管理工具完全教程
  • 解密AliceSoft游戏文件:alice-tools让你轻松修改游戏资源
  • 电脑获取安卓手机中app的APK
  • 告别磁盘混乱:Czkawka文件管理工具实战指南
  • AI依赖症康复计划(企业级落地版):已验证于华为/阿里/微软内部培训,仅开放前200份完整SOP
  • 从零搭建自动化心电图系统:仪表放大器、双T陷波滤波与LabVIEW心率检测
  • 温州EPC项目落地全流程解析及合规服务商参考 - 奔跑123
  • SeedVR2视频修复终极指南:三步实现AI生成视频高清优化
  • 2026厨卫小飞蛾根除全攻略!告别反复滋生,北京16区上门可用 - 苏易修缮
  • 10分钟打造专业级音乐中心:Foobar2000美化终极指南
  • Audacity音频处理深度解析:高级功能与性能优化实战
  • Daihen RGA 400A 12.88mhz-14mhz Power 40kw RF Generator 射频电源
  • 3步解决方案:通过OpenCore Legacy Patcher让2012-2015年老款Mac重获最新macOS系统支持
  • 2026年国产荧光法溶解氧仪十大品牌深度测评:技术突围与精准选型实战指南 - 水质仪表品牌排行榜
  • MAPDN:多智能体强化学习破解配电网电压控制难题的分布式智能解决方案
  • 京东自动下单工具终极指南:如何用Node.js实现24小时智能购物助手
  • Boss Show Time:革新招聘信息时效性的浏览器插件技术解析
  • 2026雨季防潮防虫!北京厨卫飞蛾大爆发?16区根治消杀榜单汇总 - 苏易修缮