RT-Thread Clock HRTimer 高精度定时器完全指南:API、事件编程与退化机制解析 操作系统嵌入式物联网嵌入式OSRTOS【免费下载链接】rt-threadRT-Thread is an open source IoT Real-Time Operating System (RTOS). https://rt-thread.github.io/rt-thread/项目地址https://gitcode.com/gh_mirrors/rt/rt-thread点击查看免费下载Clock HRTimer 是 RT-Thread clock_time 子系统在时间源clock source之上提供的高精度超时调度框架。它以统一的计数单位维护按到期时间排序的定时器队列自动将下一次到期换算为事件设备clock event单位进行编程并在到期时分发回调当硬件事件缺失时还能自动退化为软件定时器触发。读完本文你将掌握rt_clock_hrtimer_*全部 API 的语义与返回值、阻塞延时辅助函数的使用方法以及 hrtimer 在 clock_hrtimer.c 中的队列排序、回绕比较与退化编程实现原理。定位与设计从 clock_time 到高精度超时RT-Thread 的 clock_time 子系统由 clock_time_core.c、clock_hrtimer.c、clock_timer.c 与 clock_time_arm_arch.c 组成对外接口集中在 clock_time.h。子系统中存在两类角色时钟源clock source负责提供高频计数get_freq/get_counter是 hrtimer 延时计数的基准。若没有注册外部源系统默认使用基于rt_tick_get()的 tick 源频率即RT_TICK_PER_SECOND。事件设备clock event负责编程下一次事件set_timeout即按 delta 计数值设置下一次硬件超时。若没有注册事件设备则rt_clock_time_set_timeout()返回-RT_ENOSYShrtimer 会自动退化。hrtimer 正是架在两者之上的调度层它维护按到期时间排序的队列把队首事件换算成事件设备单位编程到期时在中断里分发回调。rt_clock_time_device_register()clock_time_core.c在注册设备时会通过capsRT_CLOCK_TIME_CAP_SOURCE/RT_CLOCK_TIME_CAP_EVENT定义于 clock_time.h自动填充默认源与默认事件而rt_clock_timer_register()clock_timer.c则把传统硬件定时器封装成 clock time 设备并挂到默认事件上。hrtimer 对象模型struct rt_clock_hrtimer定义于 clock_time.hstruct rt_clock_hrtimer { rt_uint8_t flag; /** 与 tick 定时器 flag 兼容 */ char name[RT_NAME_MAX]; rt_list_t node; void *parameter; unsigned long delay_cnt; /* 相对延时默认时钟源计数 */ unsigned long timeout_cnt; /* 绝对到期计数值 */ rt_err_t error; struct rt_completion completion; void (*timeout_func)(void *parameter); }; typedef struct rt_clock_hrtimer *rt_clock_hrtimer_t;要点delay_cnt是启动时传入的相对计数timeout_cnt delay_cnt 当前计数是绝对到期点队列按timeout_cnt排序。flag直接复用RT_TIMER_FLAG_*系列宏单次/周期/硬定时器RT_TIMER_FLAG_ACTIVATED表示激活态与 RT-Thread 传统定时器语义一致。每个 hrtimer 内置一个completion供rt_clock_hrtimer_sleep()阻塞等待使用。API 详解完整原型见 clock_time.h实现见 clock_hrtimer.c。rt_clock_hrtimer_initvoid rt_clock_hrtimer_init(rt_clock_hrtimer_t timer, const char *name, rt_uint8_t flag, void (*timeout)(void *parameter), void *parameter);作用初始化高精度定时器对象。参数timer为待初始化对象name为名称内部通过rt_strncpy(timer-name, name, RT_NAME_MAX - 1)截断flag复用RT_TIMER_FLAG_*timeout为超时回调parameter为回调参数。行为rt_memset清空内部状态、初始化链表节点node与completion并清除RT_TIMER_FLAG_ACTIVATED标志clock_hrtimer.c。仅初始化不会启动需另行调用rt_clock_hrtimer_start()。上下文线程上下文。timer与timeout均不能为空RT_ASSERT。rt_clock_hrtimer_startrt_err_t rt_clock_hrtimer_start(rt_clock_hrtimer_t timer, unsigned long cnt);作用启动定时器在cnt个计数后到期。参数cnt为相对延时单位是默认时钟源的计数不是 tick、不是纳秒。返回值RT_EOK启动成功-RT_ERROR表示定时器已处于激活态重复 start。说明源码通过RT_ASSERT(delay_cnt (_HRTIMER_MAX_CNT / 2))约束cnt必须小于计数器最大值的一半以避免计数器回绕造成到期判断歧义。_HRTIMER_MAX_CNT在 64 位架构上为UINT64_MAX否则为UINT32_MAXclock_hrtimer.c。启动时计算timeout_cnt delay_cnt 当前计数插入排序队列后调用_set_next_timeout_locked()重新编程下一次硬件事件clock_hrtimer.c。这意味着启动新定时器可能改写硬件比较寄存器。在中断上下文调用会产生并发风险应与rt_clock_hrtimer_stop/control一样遵守调用上下文约束。rt_clock_hrtimer_stoprt_err_t rt_clock_hrtimer_stop(rt_clock_hrtimer_t timer);作用停止正在运行的定时器。返回值RT_EOK成功-RT_ERROR表示定时器未激活。说明从队列移除节点、清除激活标志并触发_set_next_timeout_locked()重新编程下一次事件clock_hrtimer.c。rt_clock_hrtimer_controlrt_err_t rt_clock_hrtimer_control(rt_clock_hrtimer_t timer, int cmd, void *arg);作用查询或修改定时器属性命令与 RT-Thread 传统定时器保持一致clock_hrtimer.c。常用命令命令行为RT_TIMER_CTRL_GET_TIME读取delay_cnt到*(unsigned long *)argRT_TIMER_CTRL_SET_TIME用*(unsigned long *)arg设置delay_cnt并重算timeout_cnt 新值 当前计数同样要求小于最大值一半RT_TIMER_CTRL_SET_ONESHOT清除RT_TIMER_FLAG_PERIODIC切换为单次模式RT_TIMER_CTRL_SET_PERIODIC置位RT_TIMER_FLAG_PERIODIC切换为周期模式RT_TIMER_CTRL_GET_STATE查询激活状态写入RT_TIMER_FLAG_ACTIVATED或RT_TIMER_FLAG_DEACTIVATED到*(rt_uint32_t *)argRT_TIMER_CTRL_GET_REMAIN_TIME获取绝对到期计数值timeout_cnt到*(unsigned long *)argRT_TIMER_CTRL_GET_FUNC/SET_FUNC获取/设置超时回调RT_TIMER_CTRL_GET_PARM/SET_PARM获取/设置回调参数说明修改时间或模式不会自动启动已停止的定时器所有操作在自旋锁保护下进行。rt_clock_hrtimer_detachrt_err_t rt_clock_hrtimer_detach(rt_clock_hrtimer_t timer);作用分离定时器并唤醒等待者。行为clock_hrtimer.c通过rt_completion_wakeup_by_errno(timer-completion, RT_ERROR)唤醒rt_clock_hrtimer_sleep()中的等待线程标记定时器为未激活若之前因-RT_EINTR被中断则同时从队列移除并重新编程下一次事件。适用场景定时器资源释放或任务退出前清理。rt_clock_hrtimer_delay_init / delay_detachvoid rt_clock_hrtimer_delay_init(struct rt_clock_hrtimer *timer); void rt_clock_hrtimer_delay_detach(struct rt_clock_hrtimer *timer);delay_init初始化用于阻塞延时的 one-shot hrtimer。内部调用rt_clock_hrtimer_init(timer, hrtimer_sleep, RT_TIMER_FLAG_ONE_SHOT | RT_TIMER_FLAG_HARD_TIMER, _sleep_timeout, timer)回调_sleep_timeout负责rt_completion_done()触发 completion[clock_hrtimer.c](https://link.gitcode.com/i/2efd354b4c5057a23ca927ed5bb90de8#L152-L156, L400-L404)。delay_detach释放上述定时器等价于rt_clock_hrtimer_detach()即使已经超时也可安全调用completion唤醒与队列操作均有防御处理。rt_clock_hrtimer_sleep / ndelay / udelay / mdelayrt_err_t rt_clock_hrtimer_sleep(struct rt_clock_hrtimer *timer, unsigned long cnt); rt_err_t rt_clock_hrtimer_ndelay(struct rt_clock_hrtimer *timer, unsigned long ns); rt_err_t rt_clock_hrtimer_udelay(struct rt_clock_hrtimer *timer, unsigned long us); rt_err_t rt_clock_hrtimer_mdelay(struct rt_clock_hrtimer *timer, unsigned long ms);sleep阻塞当前线程直到超时。实现为rt_clock_hrtimer_start()后调用rt_completion_wait_flags(..., RT_WAITING_FOREVER, RT_INTERRUPTIBLE)clock_hrtimer.c。返回值RT_EOK正常到期-RT_EINTR被信号打断或 detach 唤醒-RT_EINVALcnt为 0若 start 失败则直接返回其错误码。仅线程上下文可用依赖 completion 阻塞机制。ndelay/udelay/mdelay按纳秒/微秒/毫秒换算为计数后调用sleep。换算基准为rt_clock_time_get_res_scaled()cnt (ns * RT_CLOCK_TIME_RESMUL) / res其中RT_CLOCK_TIME_RESMUL 1000000ULLclock_time.h。udelay即ndelay(us * 1000)mdelay即ndelay(ms * 1000000)clock_hrtimer.c。说明实际延时精度受时钟源计数频率与事件编程粒度限制当res为 0未注册有效源时ndelay返回-RT_ERROR。内部机制队列、回绕与事件编程按到期时间排序的队列所有 hrtimer 挂在静态链表_timer_list上clock_hrtimer.c。_insert_timer_to_list_locked()使用_cnt_before比较timeout_cnt把新定时器插到正确位置并置位RT_TIMER_FLAG_ACTIVATEDclock_hrtimer.c。计数比较采用无符号减法再转有符号的技巧避免回绕歧义rt_inline rt_bool_t _cnt_before(unsigned long a, unsigned long b) { return ((rt_base_t)(a - b)) 0; }这正是start要求cnt 最大值的一半的根本原因——保证任意两个活跃定时器的绝对到期点之差不会超过半个计数空间使上述比较在回绕场景下依然正确。事件编程与退化机制_set_next_timeout_locked()clock_hrtimer.c是每次 start/stop/到期后的统一收口取队首定时器用_cnt_convert把其绝对到期计数减去当前计数再按源分辨率/事件分辨率换算成事件单位调用rt_clock_hrtimer_settimeout()。rt_clock_hrtimer_settimeout()是rt_weak弱函数clock_hrtimer.c其退化逻辑正是文档强调的缺硬件事件自动用软件定时器先尝试rt_clock_time_set_timeout(cnt)即编程真实的事件设备成功则直接返回若返回非RT_EOK典型是未注册事件设备时的-RT_ENOSYS则通过_hrtimer_cnt_to_tick()把计数换算为 tick驱动一个名为shrtimer的静态 one-shot 软件定时器rt_timer_init/start其回调为rt_clock_hrtimer_process实现等价的到期处理。_hrtimer_cnt_to_tick内部依次按事件分辨率rt_clock_hrtimer_getres()默认取rt_clock_time_get_event_res_scaled()换算纳秒、再向上取整到 tick保证最小延时至少 1 tickclock_hrtimer.c。到期处理与中断调用链到期后事件中断调用rt_clock_time_event_isr()clock_hrtimer.c它只做一件事调用rt_clock_hrtimer_process()。该函数在自旋锁保护下_hrtimer_process_locked()循环取出队首若now timeout_cnt则出队周期定时器RT_TIMER_FLAG_PERIODIC按timeout_cnt delay_cnt now重新插入单次定时器清除激活标志最后执行timeout_func(parameter)clock_hrtimer.c。_set_next_timeout_locked()重新编程下一次事件若队首已到期换算结果为 0则先就地处理再继续找下一个。在硬件事件设备场景下该路径运行于中断上下文因此回调可能在中断上下文执行文档注意事项第一条。具体中断如何到达rt_clock_time_event_isr可参见 clock_timer.c 中rt_clock_timer_isr()硬件定时器 ISR 计数溢出后调用rt_clock_time_event_isr()。典型流程初始化 hrtimer 并设置回调rt_clock_hrtimer_init(timer, name, flag, timeout, param)。将时间转换为计数值直接使用rt_clock_time_ns_to_counter(ns)clock_time_core.c或借助ndelay/udelay/mdelay辅助函数自动换算。启动定时器rt_clock_hrtimer_start(timer, cnt)系统自动排序并编程下一次事件。到期后事件中断调用rt_clock_time_event_isr()触发 hrtimer 处理与回调分发周期模式自动重挂单次模式自动停用。完整示例示例一单次超时#include drivers/clock_time.h static struct rt_clock_hrtimer demo_timer; static void demo_timeout(void *parameter) { RT_UNUSED(parameter); rt_kprintf(hrtimer timeout\n); } static void demo_hrtimer_start(void) { rt_uint64_t ns 5ULL * 1000 * 1000; /* 5 ms */ unsigned long cnt (unsigned long)rt_clock_time_ns_to_counter(ns); rt_clock_hrtimer_init(demo_timer, demo, RT_TIMER_FLAG_ONE_SHOT, demo_timeout, RT_NULL); rt_clock_hrtimer_start(demo_timer, cnt); }要点rt_clock_time_ns_to_counter()依据默认时钟源的分辨率把纳秒换算为计数这是把人类时间单位翻译成计数单位的标准入口若要在运行时查询当前事件分辨率与频率可用rt_clock_hrtimer_getres()/rt_clock_hrtimer_getfrq()均为rt_weak可被平台覆盖。示例二阻塞延时辅助static void demo_hrtimer_sleep(void) { struct rt_clock_hrtimer timer; rt_clock_hrtimer_delay_init(timer); rt_clock_hrtimer_mdelay(timer, 10); rt_clock_hrtimer_delay_detach(timer); }要点delay_init建立的 one-shot 定时器内部回调会触发 completionmdelay阻塞当前线程 10 msdelay_detach负责清理即使已经超时也安全。启用与配置hrtimer 随 clock_time 子系统一起编译。配置入口为 components/drivers/clock_time/KconfigRT_USING_CLOCK_TIME启用 clock_time 子系统hrtimer 随之包含CLOCK_TIMER_FREQRISC-V64 平台上时钟计数器的基准频率HzRT_CLOCK_TIME_ARM_ARCHARM ARCH TimerCortex-A / ARMV8依赖RT_USING_DMRT_USING_CLOCK_TIMER_TRIGGER可选启用时钟定时器硬件触发输出供 ADC 等使用选中定时器需专用。构建层面components/drivers/clock_time/SConscript 在未定义RT_USING_CLOCK_TIME时直接跳过编译启用后编译clock_time_core.c、clock_hrtimer.c、clock_boottime.c、clock_timer.c并视平台加入clock_time_arm_arch.c或arch/ARCH下的平台实现。注意事项使用硬件事件时超时回调可能在中断上下文执行回调内应避免阻塞操作与调度敏感调用。rt_clock_hrtimer_sleep()依赖 completion 阻塞等待可能返回-RT_EINTR信号打断或 detach调用方需按返回值处理重试或退出逻辑它只能在线程上下文中使用。start/control(SET_TIME)要求计数值小于计数器最大值的一半这是保证回绕比较正确性的硬性约束。cnt的单位始终是默认时钟源的计数而非纳秒/微秒换算请统一走rt_clock_time_ns_to_counter()或ndelay/udelay/mdelay辅助函数。未注册事件设备无硬件定时器时 hrtimer 会自动退化为软件定时器触发此时精度受 tick 粒度限制——退化是可用性兜底并非高精度保证。赞分享操作系统嵌入式物联网嵌入式OSRTOS【免费下载链接】rt-threadRT-Thread is an open source IoT Real-Time Operating System (RTOS). https://rt-thread.github.io/rt-thread/项目地址https://gitcode.com/gh_mirrors/rt/rt-thread点击查看免费下载相关推荐RT-Thread 高精度定时器Clock HRTimer完全指南API 详解、实现原理与实战示例RT Thread 高精度定时器Clock HRTimer完全指南API 详解、实现原理与实战示例 高精度定时器Clock HRTimer是 RT T操作系统嵌入式物联网嵌入式OSRTOSRT-Thread Clock Time 子系统深度解析统一时间基准与高精度定时事件调度RT Thread Clock Time 子系统深度解析统一时间基准与高精度定时事件调度 RT Thread 的 Clock Time 子系统位于 comp操作系统嵌入式物联网嵌入式OSRTOSRT-Thread Clock Time Core 子系统解析时钟设备模型、定点换算与高精度事件调度RT Thread Clock Time Core 子系统解析时钟设备模型、定点换算与高精度事件调度 Clock Time Core 是 RT Thread操作系统嵌入式物联网嵌入式OSRTOS上一篇5步搭建个人AI助手闻达平台零基础部署指南下一篇WPF UI 表单验证实战用 INotifyDataErrorInfo 3 步搞定输入校验创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考