时钟节拍
时钟节拍是特定的周期性中断,这个中断可以看做是系统心跳,中断之间的时间间隔取决于不同的应用,一般是 1ms–100ms,时钟节拍率越快,系统的额外开销就越大,从系统启动开始计数的时钟节拍数称为系统时间。时钟节拍由配置为中断触发模式的硬件定时器产生。
时间节拍和时间片
在时间节拍中,常常进行时间片轮转调度,时间片的长度本身就是以 “时钟节拍” 为单位定义的。 时间片的本质:以 “时钟节拍” 为最小单位。时钟节拍是 RTOS 的 “时间心跳”,由硬件定时器(如 SysTick)周期性触发(例如每 1ms 一次),是系统中唯一全局统一的时间基准。所有与时间相关的操作(延时、超时、定时器、调度)都依赖这个基准。
时间节拍和超时
中断中的 rt_timer_check() 用于检查系统硬件定时器链表,如果有定时器超时,将调用相应的超时函数。且所有定时器在定时超时后都会从定时器链表中被移除,而周期性定时器会在它再次启动时被加入定时器链表。
rt_timer_check() 运行在中断上下文(通常是时钟节拍中断,即系统每隔固定时间(如 1ms)触发的硬件中断)。它的核心作用是:
遍历系统维护的 “活跃定时器链表”(所有正在倒计时、等待超时的定时器都会被加入这个链表),检查每个定时器是否满足 “超时条件”(剩余计时滴答数减为 0)。
遍历系统维护的 “活跃定时器链表”(所有正在倒计时、等待超时的定时器都会被加入这个链表),检查每个定时器是否满足 “超时条件”(剩余计时滴答数减为 0)。
超时后的逻辑处理:
- 调用超时回调函数:触发该定时器预先注册的 “超时处理函数”(例如定时翻转 LED、触发数据采集等用户逻辑)。
- 从链表中移除定时器:无论定时器是 “单次定时器” 还是 “周期定时器”,超时后都会被临时从活跃链表中移除(防止重复处理)
定时器分为两种类型:
- 单次定时器:超时后仅执行一次回调,之后不再自动运行(若需再次定时,需用户手动调用
rt_timer_start()
重新启动)。 - 周期定时器:超时后执行回调,且会在回调执行完成后自动 “重启”—— 即重新计算下一次超时时间,并将自身再次加入 “活跃定时器链表”,进入下一轮倒计时。
定时器
1)硬件定时器是芯片本身提供的定时功能。一般是由外部晶振提供给芯片输入时钟,芯片向软件模块提供一组配置寄存器,接受控制输入,到达设定时间值后芯片中断控制器产生时钟中断。硬件定时器的精度一般很高,可以达到纳秒级别,并且是中断触发方式。
2)软件定时器是由操作系统提供的一类系统接口,它构建在硬件定时器基础之上,使系统能够提供不受数目限制的定时器服务。RT-Thread 操作系统提供软件实现的定时器,以时钟节拍(OS Tick)的时间长度为单位,即定时数值必须是 OS Tick 的整数倍,例如一个 OS Tick 是 10ms,那么上层软件定时器只能是 10ms,20ms,100ms等,而不能定时为 15ms。RT-Thread 的定时器也基于系统的节拍,提供了基于节拍整数倍的定时能力。

1.HARD_TIMER模式
在中断上下文环境中执行时,对于超时函数的要求与中断服务例程的要求相同:执行时间应该尽量短,执行时不应导致当前上下文挂起、等待。例如在中断上下文中执行的超时函数它不应该试图去申请动态内存、释放动态内存等。
RT-Thread 定时器默认的方式是 HARD_TIMER 模式,即定时器超时后,超时函数是在系统时钟中
断的上下文环境中运行的。在中断上下文中的执行方式决定了定时器的超时函数不应该调用任何会让当前上下文挂起的系统函数;也不能够执行非常长的时间,否则会导致其他中断的响应时间加长或抢占了其他线程执行的时间。
禁止“阻塞操作”:
中断上下文不能有任何导致“挂起/等待”操作
- 调用
rt_thread_delay()
(线程延时,会触发调度); - 申请 / 释放动态内存(如
rt_malloc()
/rt_free()
,可能因内存池空而等待); - 等待互斥锁、信号量等同步原语(会阻塞直到资源可用)。
2.SOFT_TIMER 模式
SOFT_TIMER 模 式 可 配 置, 通 过 宏 定 义 RT_USING_TIMER_SOFT 来 决 定 是 否 启 用 该 模式。该模式被启用后,系统会在初始化时创建一个 timer 线程,然后 SOFT_TIMER 模式的定时
器超时函数在都会在 timer 线程的上下文环境中执行。可以在初始化 / 创建定时器时使用参数
RT_TIMER_FLAG_SOFT_TIMER 来指定设置 SOFT_TIMER 模式。
定时器工作机制
下面以一个例子来说明 RT-Thread 定时器的工作机制。在 RT-Thread 定时器模块中维护着两个重要
的全局变量:
(1)当前系统经过的 tick 时间 rt_tick(当硬件定时器中断来临时,它将加 1);
(2)定时器链表 rt_timer_list。系统新创建并激活的定时器都会按照以超时时间排序的方式插入到
rt_timer_list 链表中。
如果在加一个300个tick的TIMER4,那么应该是当前的tick加上300=330,而且应该插在timer2和timer3之间(类似链表?)
实现该目的的其他方式:
- 如果数据量不大,且插入操作不频繁:动态数组(实现简单,使用方便)
- 如果需要频繁插入且数据量大:平衡二叉搜索树或跳跃表(提供更高的操作效率)
- 如果实现复杂度是首要考虑因素:链表(实现简单,适合对性能要求不极致的场景)
定时器控制块(类似于HAL库里面的句柄?)
因为定时器排序使用的是链表,每次查询都需要很大的时间(完全查询一遍O(0))如何加快搜索链表元素的速度。
定时器跳表算法:
跳表是一种基于并联链表的数据结构,实现简单,插入、删除、查找的时间复杂度均为 O(log n)。跳表是链表的一种,但它在链表的基础上增加了 “跳跃” 功能,正是这个功能,使得在查找元素时,跳表能够提供 O(log n) 的时间复杂度。