RTOS 的 Tick:操作系统的心跳
rtos freertos tick术语速查
| 缩写 | 全称 | 大白话 |
|---|---|---|
| Tick | Timer Tick 定时器滴答 | RTOS 的心跳,每个 Tick 调度器醒一次 |
| SysTick | System Tick Timer 系统滴答定时器 | Cortex-M 内核自带 24 位递减定时器,专为 RTOS 设计 |
| ISR | Interrupt Service Routine 中断服务例程 | Tick 中断来了,执行 xPortSysTickHandler() |
| PendSV | Pendable Service Call 可挂起服务调用 | 最低优先级中断,实际任务切换在这里完成 |
Tick 管三件事
① 延时
// 等 100 个 Tick = 100ms
vTaskDelay(pdMS_TO_TICKS(100));
任务把自己挂起,调度器在 Tick 中断里检查:「100 次心跳了没?到了就唤醒。」
② 超时
// 等队列消息,最多 500ms
xQueueReceive(
xQueue, &data,
pdMS_TO_TICKS(500)
);
每个 Tick 减一次计数。归零了还没收到 → 返回超时错误码。
③ 调度
Tick 中断里检查当前任务时间片用完没。用完了 → 触发 PendSV,在最低优先级完成实际的任务切换。
为什么 Tick 中断不直接切任务? Tick 中断(SysTick)优先级高,如果它在处理一个更紧急的中断时插队切任务,会导致优先级反转。所以 Tick 只做「检查」,真正的切任务交给最低优先级的 PendSV。
完整链路
硬件 SysTick 定时器(每 1ms 减到零)
│
├→ SysTick_Handler() 中断
│ │
│ ├→ xPortSysTickHandler()
│ │ ├→ 遍历延时链表,唤醒到期的任务
│ │ ├→ 递减阻塞任务的 timeout 计数
│ │ └→ 检查当前任务时间片 → 触发 PendSV
│ │
│ └→ portEND_SWITCHING_ISR()
│
└→ PendSV_Handler()
└→ 保存当前上下文 → 切换到下一个任务
配置与代价
| 频率 | 周期 | 适用 | 代价 |
|---|---|---|---|
| 1000 Hz | 1ms | FreeRTOS 默认,通用 | 每秒 1000 次中断 |
| 100 Hz | 10ms | 低功耗场景 | 延时精度降低 |
| 10000 Hz | 100μs | 电机控制等硬实时 | 中断开销大,CPU 大部分时间在处理 Tick |
// sdkconfig / FreeRTOSConfig.h
#define configTICK_RATE_HZ 1000 // 1ms per tick