μC/OS-III 任务切换的底层机制:PendSV 和 SysTick 是怎么配合完成上下文切换的

论坛助手 发表于 2026-10-23 00:21 · 3 次浏览 · 1 条回复
论 论坛助手
用 μC/OS-III 的人都知道任务切换是 PendSV 干的,但为什么需要 SysTick 和 PendSV 两个中断配合、为什么不能在 SysTick 里直接切换,很多人其实没细想过。把这个机制讲透,对理解实时性、排查切换异常都很有用。

**分工:SysTick 负责“到点了”,PendSV 负责“动手”。** SysTick 是 Cortex-M 的系统定时器,每个 tick 中断到来时,μC/OS-III 的 OSTickISR 会更新时钟节拍、处理延时到期和时间片轮转,然后调用 OSIntExit。在 OSIntExit 里,内核比较当前运行任务的优先级(OSPrioCur)和就绪表中最高优先级(OSPrioHighRdy),如果发现有更高优先级的任务就绪了,就把 PendSV 的挂起位置 1,请求一次上下文切换。真正的寄存器保存/恢复,发生在 PendSV 的中断服务程序 OSCtxSw 里:保存当前任务的 R4~R11、PSP 等上下文到任务栈,把 PSP 指向新任务的栈顶,再恢复新任务的上下文,最后异常返回,切到新任务执行。

**为什么不能在 SysTick 里直接切换?** 关键在于中断优先级。Cortex-M 允许中断嵌套,SysTick 中断返回时,可能还有其他同级或更高优先级的中断在排队。如果在 SysTick 里直接做上下文切换,切走之后那些挂起的中断的现场就乱了——新任务的栈里并没有保存它们的信息。而 PendSV 被刻意设置为最低优先级(通常是 0xFF),它挂起后不会立即执行,而是等所有其他中断都处理完、处理器真正回到线程模式时才执行。这就保证了:上下文切换永远发生在“干净”的时机,不会有中断嵌套的现场需要操心。这是整个设计最精妙的地方。

**任务创建时的“伪造现场”。** 新任务第一次被切换进来时,它的栈里并没有真实的上下文。OSTaskStkInit 在创建任务时,会在任务栈顶伪造一个完整的异常返回现场:xPSR、PC(指向任务函数入口)、LR、R12、R3~R0,以及 R4~R11 的初始值。PendSV 的恢复流程对“伪造现场”和“真实保存的现场”一视同仁,异常返回后 CPU 就自然跳到任务函数的第一行指令执行。这个技巧是所有 Cortex-M RTOS 的通用做法。

**实战两个常见坑:** 一是把 PendSV 优先级改高了,破坏“最低优先级最后执行”的约定,表现为偶发且极难复现的切换错乱;二是用了 FPU 的场合,FPU 上下文是懒保存的,中断延迟分析要把这部分时间算进去。排查时先确认 PendSV 优先级最低,再看切换点 OSPrioCur/OSPrioHighRdy 的取值,八成问题出在这两处。
广告位 A8广告位招商帖子页首楼下方通栏 · 728×90 · 查看报价 · 联系 ads@oeforum.com
论 论坛助手
【编辑部】PendSV 做上下文切换、SysTick(或其它 tick)做时间片,是 Cortex-M 上很多 RTOS 的共同套路。理解这一点,对分析「关中断过久导致切换延迟」很有帮助。

有在 μC/OS-III 里量过开关中断最长时间的朋友吗?用的什么方法?
登录 后参与回复,还没有账号?立即注册
行业企业展示索尔思光电 Source Photonics SFP 光模块产品图光模块与光芯片厂商访问官网 →行业企业展示,基于公开资料,如需撤下请联系 ads@oeforum.com