ChibiOS/RT 提供了一套完整的时间管理机制,包括系统时钟、虚拟定时器、阶梯定时器和时间测量工具,是实现周期任务、超时检测和性能分析的基础。
系统时间
系统时间是 ChibiOS/RT 中所有时间相关操作的基础。内核维护一个全局系统计数器,在每次系统滴答(tick)时递增。
核心类型
/* 系统时间戳,64位无符号整数,单位为 tick */typedef uint64_t systime_t;
/* 系统时间间隔,32位无符号整数,用于表示相对时间 */typedef uint32_t sysinterval_t;systime_t 是绝对时间戳,从系统启动开始单调递增;sysinterval_t 表示相对时间间隔,两者用途不同,不可混用。
获取系统时间
/* 获取当前系统时间(32位截断,适合短间隔测量) */systime_t chSysGetRealtimeCounterX(void);
/* 获取系统滴答计数 */systime_t chVTGetSystemTimeX(void);
/* 获取系统频率(ticks/秒) */sysinterval_t chVTGetSystemFrequencyX(void);线程休眠
/* 休眠指定 tick 数 */void chThdSleep(sysinterval_t interval);
/* 休眠到指定系统时间点 */void chThdSleepUntil(systime_t time);
/* 示例:每 100ms 周期执行 */static THD_WORKING_AREA(waWorker, 128);static THD_FUNCTION(WorkerThread, arg) { (void)arg; systime_t prev = chVTGetSystemTimeX();
while (!chThdShouldTerminateX()) { /* 执行周期任务 */ do_periodic_work();
/* 精确周期休眠,补偿任务执行耗时 */ chThdSleepUntil(chTimeAddX(prev, TIME_MS2I(100))); prev = chVTGetSystemTimeX(); }}chThdSleepUntil 相比 chThdSleep 的优势在于:它基于绝对时间点休眠,不会因为任务执行耗时而产生累积漂移,适合对时序精度要求高的场景。
虚拟定时器
虚拟定时器是 ChibiOS/RT 最常用的时间管理机制,用于在指定时间后执行回调函数。
数据结构
typedef struct { virtual_timer_t * volatile next; /* 链表指针 */ systime_t deadline; /* 触发时间点 */ vtfunc_t callback; /* 回调函数 */ void * par; /* 回调参数 */} virtual_timer_t;基本操作
/* 启动定时器,interval 后触发回调 */void chVTSet(virtual_timer_t *vtp, sysinterval_t interval, vtfunc_t fn, void *par);
/* 重置定时器(取消 + 重新启动) */void chVTReset(virtual_timer_t *vtp);
/* 检查定时器是否已启动(中断上下文) */bool chVTIsArmedX(const virtual_timer_t *vtp);单次定时器示例
static virtual_timer_t led_timer;
/* LED 闪烁回调 */static void led_blink_cb(void *par) { (void)par; palTogglePad(GPIOC, GPIOC_LED);
/* 重新启动定时器,实现周期效果 */ chVTSet(&led_timer, TIME_MS2I(500), led_blink_cb, NULL);}
/* 启动 LED 闪烁 */static void start_led_blink(void) { chVTSet(&led_timer, TIME_MS2I(500), led_blink_cb, NULL);}周期定时器
ChibiOS/RT 的虚拟定时器本质上是单次触发的。要实现周期定时器,在回调中重新设置即可:
static virtual_timer_t periodic_timer;
static void periodic_cb(void *par) { uint32_t *count = (uint32_t *)par; (*count)++;
do_periodic_task(*count);
/* 重新启动定时器 */ chVTSet(&periodic_timer, TIME_S2I(1), periodic_cb, par);}
static uint32_t tick_count = 0;
static void start_periodic_timer(void) { chVTSet(&periodic_timer, TIME_S2I(1), periodic_cb, &tick_count);}注意事项
- 虚拟定时器回调在中断上下文(系统 tick 中断)中执行,回调函数应尽量简短,避免阻塞操作。
- 定时器回调中不能调用任何会导致线程切换的 API。
- 定时器精度受限于系统 tick 频率,对于亚毫秒级精度需求应使用硬件定时器。
时间窗口
时间窗口机制用于验证某个时间点是否落在指定的时间间隔内,常用于通信超时检测和周期任务调度。
时间间隔表示
/* 时间间隔结构 */typedef struct { sysinterval_t start; /* 窗口起始点 */ sysinterval_t end; /* 窗口结束点 */} time_window_t;
/* 无效时间窗口(已过期) */#define TIME_WINDOW_NONE ((sysinterval_t)0)窗口检查
/* 检查时间是否在窗口内 */static inline bool chTimeIsInWindowX(sysinterval_t time, sysinterval_t start, sysinterval_t end) { return (time >= start) && (time < end);}
/* 示例:超时检测 */#define TIMEOUT_MS TIME_MS2I(5000) /* 5秒超时 */
static bool wait_with_timeout(virtual_timer_t *vt) { systime_t start = chVTGetSystemTimeX(); systime_t deadline = chTimeAddX(start, TIMEOUT_MS);
chVTSet(vt, TIMEOUT_MS, timeout_cb, NULL);
/* 等待事件 */ eventmask_t evt = chEvtWaitAnyTimeout(ALL_EVENTS, TIMEOUT_MS);
if (evt == 0) { return false; /* 超时 */ } return true; /* 收到事件 */}阶梯定时器
阶梯定时器(Step Timer)提供一种轻量级的时间步进机制,适用于需要在固定时间间隔执行多个任务的场景,比虚拟定时器更节省资源。
数据结构与操作
typedef struct { systime_t next; /* 下一步时间点 */ sysinterval_t step; /* 步进间隔 */ stfunc_t callback; /* 回调函数 */ void * par; /* 回调参数 */} step_timer_t;
/* 初始化阶梯定时器 */void chSTimerSetup(step_timer_t *stp, sysinterval_t step, stfunc_t fn, void *par);
/* 驱动阶梯定时器(在 tick 中断或主循环中调用) */void chSTimerTick(step_timer_t *stp);阶梯定时器示例
static step_timer_t heartbeat_timer;
/* 心跳回调 */static void heartbeat_cb(void *par) { (void)par; palTogglePad(GPIOB, GPIOB_HEARTBEAT);}
/* 初始化并启动 */static void heartbeat_init(void) { chSTimerSetup(&heartbeat_timer, TIME_MS2I(250), heartbeat_cb, NULL);}
/* 在主循环或周期任务中驱动 */static THD_FUNCTION(HeartbeatThread, arg) { (void)arg;
heartbeat_init();
while (!chThdShouldTerminateX()) { chSTimerTick(&heartbeat_timer); chThdSleep(TIME_MS2I(50)); }}阶梯定时器与虚拟定时器的区别:阶梯定时器需要显式调用 chSTimerTick 来驱动,适合在已有的周期任务中复用;虚拟定时器由内核自动驱动,适合独立的定时需求。
时间测量
ChibiOS/RT 提供时间测量工具,用于精确测量代码段的执行时间,是性能分析和调试的重要手段。
数据结构
typedef struct { systime_t start; /* 测量起始时间 */ systime_t end; /* 测量结束时间 */ systime_t best; /* 最短执行时间 */ systime_t worst; /* 最长执行时间 */ uint32_t n; /* 测量次数 */} time_measurement_t;测量操作
/* 初始化测量对象 */void chTMInitTimeMeasurementX(time_measurement_t *tmp);
/* 开始测量 */void chTMStart(time_measurement_t *tmp);
/* 停止测量并更新统计 */void chTMStop(time_measurement_t *tmp);
/* 获取测量结果(tick 数) */systime_t chTMGetElapsedX(const time_measurement_t *tmp);性能分析示例
static time_measurement_t meas;
/* 测量中断服务程序执行时间 */void irq_handler(void) { chTMStart(&meas);
/* 执行 ISR 逻辑 */ process_interrupt();
chTMStop(&meas);}
/* 定期打印测量结果 */static THD_FUNCTION(MonitorThread, arg) { (void)arg; chTMInitTimeMeasurementX(&meas);
while (!chThdShouldTerminateX()) { chThdSleep(TIME_S2I(5));
/* 打印统计信息 */ uart_printf("n=%lu, best=%lu, worst=%lu\r\n", meas.n, meas.best, meas.worst); }}时间测量会自动记录最小值和最大值,便于发现最坏情况下的执行时间,对实时系统的响应时间分析非常有价值。
总结
ChibiOS/RT 的时间管理机制层次分明:
| 机制 | 用途 | 精度 | 适用场景 |
|---|---|---|---|
| 系统时间 | 获取当前时间 | tick 级 | 基础时间参考 |
| 虚拟定时器 | 延时回调 | tick 级 | 超时、周期任务 |
| 阶梯定时器 | 步进式定时 | 调用精度 | 复用周期任务 |
| 时间窗口 | 间隔验证 | tick 级 | 通信检测 |
| 时间测量 | 性能分析 | tick 级 | 调试优化 |
合理选择时间管理机制,是编写高效、精确嵌入式程序的关键。在实际项目中,通常需要组合使用多种机制来满足不同的时间管理需求。
部分信息可能已经过时