RTOS 的 Tick:操作系统的心跳

rtos freertos tick

术语速查

缩写全称大白话
TickTimer Tick 定时器滴答RTOS 的心跳,每个 Tick 调度器醒一次
SysTickSystem Tick Timer 系统滴答定时器Cortex-M 内核自带 24 位递减定时器,专为 RTOS 设计
ISRInterrupt Service Routine 中断服务例程Tick 中断来了,执行 xPortSysTickHandler()
PendSVPendable 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 Hz1msFreeRTOS 默认,通用每秒 1000 次中断
100 Hz10ms低功耗场景延时精度降低
10000 Hz100μs电机控制等硬实时中断开销大,CPU 大部分时间在处理 Tick
// sdkconfig / FreeRTOSConfig.h
#define configTICK_RATE_HZ  1000  // 1ms per tick