RT-Thread时钟与定时器管理 — 时间管理的艺术

前言

时间管理是RTOS的核心能力之一。RT-Thread通过时钟节拍驱动系统运转,通过定时器实现延时触发和周期任务。本文将介绍时钟节拍的概念、定时器的分类与使用方法,以及高精度延时的实现。


一、时钟节拍(OS Tick)

1.1 什么是时钟节拍?

时钟节拍是RT-Thread中最小的时间单位,类似于闹钟的"滴答"声。每一次"滴答",系统就前进一个时间单位。

时钟节拍的时间间隔由宏 RT_TICK_PER_SECOND 决定:

  • RT_TICK_PER_SECOND = 100,则每秒100次节拍,每个节拍 = 10ms
  • RT_TICK_PER_SECOND = 1000,则每秒1000次节拍,每个节拍 = 1ms

1.2 时钟节拍的产生

时钟节拍依赖硬件定时器中断。以 STM32 的 SysTick 为例:

void SysTick_Handler(void)
{
    rt_interrupt_enter();  // 进入中断
    rt_tick_increase();    // 系统时钟+1
    rt_interrupt_leave();  // 退出中断
}

每次 rt_tick_increase() 被调用,全局变量 rt_tick 自增1,记录系统从启动以来经历的总节拍数。

1.3 获取当前时钟节拍

rt_tick_t rt_tick_get(void);

通过在任务前后各获取一次 rt_tick 值,相减即可计算任务执行耗时:

rt_tick_t start = rt_tick_get();
// ... 执行某些操作 ...
rt_tick_t elapsed = rt_tick_get() - start;
rt_kprintf("耗时: %d ticks\n", elapsed);

二、定时器管理

定时器可以在指定时间后自动触发回调函数,就像家中的厨房定时器——时间到了就提醒你。

2.1 硬件定时器 vs 软件定时器

类型 精度 实现方式 适用场景
硬件定时器 纳秒级 硬件直接提供 电机控制等高精度场景
软件定时器 依赖OS Tick 操作系统管理 一般延时任务,灵活易用

2.2 定时器的分类

按触发方式分:

  • 单次触发定时器:触发一次后自动停止,如一次性闹钟。
  • 周期触发定时器:周期性重复触发,如每日闹钟。

按执行上下文分:

  • 硬件模式(HARD_TIMER):回调在中断上下文中执行,响应极快,但回调函数必须简短。
  • 软件模式(SOFT_TIMER):回调在 timer 线程中执行,可以做更复杂的操作。

2.3 创建定时器

rt_timer_t rt_timer_create(const char *name,
                           void (*timeout)(void *parameter),
                           void *parameter,
                           rt_tick_t time,
                           rt_uint8_t flag);
参数 说明
name 定时器名称
timeout 超时回调函数
parameter 传递给回调函数的参数
time 定时时长,单位为 OS Tick
flag 定时器类型标志

flag 常用值:

  • RT_TIMER_FLAG_ONE_SHOT:单次触发
  • RT_TIMER_FLAG_PERIODIC:周期触发
  • RT_TIMER_FLAG_HARD_TIMER:硬件模式
  • RT_TIMER_FLAG_SOFT_TIMER:软件模式

2.4 启动与停止定时器

rt_err_t rt_timer_start(rt_timer_t timer);   // 启动
rt_err_t rt_timer_stop(rt_timer_t timer);    // 停止
rt_err_t rt_timer_delete(rt_timer_t timer);  // 删除

三、定时器使用示例

以下示例创建一个周期定时器和一个单次定时器:

#include <rtthread.h>

static rt_timer_t timer1;  // 周期定时器
static rt_timer_t timer2;  // 单次定时器

/* 周期定时器回调 */
static void timeout1(void *parameter)
{
    rt_kprintf("Periodic timer timeout\n");
}

/* 单次定时器回调 */
static void timeout2(void *parameter)
{
    rt_kprintf("One-shot timer timeout\n");
}

int main(void)
{
    /* 创建周期定时器,每10个tick触发一次 */
    timer1 = rt_timer_create("timer1", timeout1,
                             RT_NULL, 10,
                             RT_TIMER_FLAG_PERIODIC);
    if (timer1 != RT_NULL)
        rt_timer_start(timer1);

    /* 创建单次定时器,30个tick后触发一次 */
    timer2 = rt_timer_create("timer2", timeout2,
                             RT_NULL, 30,
                             RT_TIMER_FLAG_ONE_SHOT);
    if (timer2 != RT_NULL)
        rt_timer_start(timer2);

    return 0;
}

运行效果:

  • timer1 每 10 个 tick 输出一次 “Periodic timer timeout”
  • timer2 在第 30 个 tick 输出一次 “One-shot timer timeout” 后停止

四、控制定时器

通过 rt_timer_control() 可以动态修改定时器属性:

rt_err_t rt_timer_control(rt_timer_t timer, rt_uint8_t cmd, void *arg);
命令 说明
RT_TIMER_CTRL_SET_TIME 修改超时时间
RT_TIMER_CTRL_SET_ONESHOT 设置为单次定时器
RT_TIMER_CTRL_SET_PERIODIC 设置为周期定时器

示例——将定时器超时时间改为50个tick:

rt_tick_t new_time = 50;
rt_timer_control(timer1, RT_TIMER_CTRL_SET_TIME, &new_time);

五、高精度延时

当需要比 OS Tick 更精确的延时(如微秒级),可以利用硬件定时器。以 ARM Cortex-M 的 SysTick 为例:

void rt_hw_us_delay(rt_uint32_t us)
{
    rt_uint32_t ticks = us * (SysTick->LOAD / 1000000);
    rt_uint32_t start = SysTick->VAL;
    while ((SysTick->VAL - start) < ticks);
}

注意:高精度延时使用忙等待,仅适用于极短时间的精确延时场景,不应在常规逻辑中大量使用。


总结

要点 内容
时钟节拍 系统最小时间单位,由 RT_TICK_PER_SECOND 配置
定时器类型 单次触发 / 周期触发
执行模式 硬件模式(中断上下文)/ 软件模式(线程上下文)
核心API rt_timer_creatert_timer_startrt_timer_stop
高精度延时 通过 SysTick 等硬件实现微秒级延时

掌握时钟与定时器,你就能精确控制任务的执行时机。下一篇将进入RTOS最核心的机制——线程间同步与通信。

Logo

智能硬件社区聚焦AI智能硬件技术生态,汇聚嵌入式AI、物联网硬件开发者,打造交流分享平台,同步全国赛事资讯、开展 OPC 核心人才招募,助力技术落地与开发者成长。

更多推荐