H HRTOS 示例
Task Execution Core

上下文切换

在 HRTOS v2 中,上下文切换由调度器触发,用于在 task_A 与 task_B 之间保存与恢复执行状态, 实现 LED 任务的交替运行。上下文切换是 RTOS 实现多任务运行的核心机制。

示例目标

系统运行两个任务:task_A 与 task_B,每个任务独立控制一个 LED, 并通过延时循环形成可观察的切换效果。验证两个独立任务在同一CPU上通过调度器实现交替执行。

核心API os_task_create
调度触发 时间片 + yield
状态转换 Running → Ready
任务栈 独立任务栈

核心机制

  • 任务寄存器环境保存
  • 堆栈切换
  • 调度器触发
  • 恢复任务运行
Principle

原理说明

上下文切换是 RTOS 实现多任务运行的核心机制

上下文(Context)是指任务在执行过程中的完整状态,包括程序计数器、寄存器值、栈指针等。 当调度器决定切换任务时,必须保存当前任务的上下文,并恢复目标任务的上下文, 这样才能确保任务从中断点继续执行,实现多任务的并发运行。

什么是上下文

上下文是任务执行状态的完整快照,包含 CPU 寄存器、程序计数器、栈指针、状态寄存器等。 在 HRTOS 中,上下文主要通过任务栈来保存和恢复。

为什么需要保存上下文

多任务系统中,CPU 资源有限,任务需要轮流执行。 保存上下文确保任务切换后能从中断点继续执行,不会丢失执行状态, 这是实现任务并发和实时性的基础。

任务切换过程

任务切换包括三个关键步骤:保存当前任务上下文到任务栈、选择下一个就绪任务、 恢复目标任务上下文并继续执行。整个过程由调度器统一管理。

上下文切换触发点

本示例中主要触发来源为时间片调度(系统Tick)和 task yield 主动让出CPU。 不同触发点对应不同的调度策略,影响系统的实时性和响应性。

核心判断: 上下文切换是 RTOS 的核心机制,通过保存和恢复任务执行状态, 实现多任务在单一 CPU 上的并发执行,是实时操作系统的基础。
HRTOS Implementation

HRTOS 实现机制

HRTOS 如何实现上下文切换

在 HRTOS v2 中,上下文切换的实现围绕任务寄存器环境保存、堆栈切换、调度器触发和恢复任务运行四个核心环节展开。 每个环节都经过精心设计,确保切换过程的高效性和可靠性。

任务寄存器环境保存

保存内容:程序计数器、栈指针、通用寄存器、状态寄存器

保存位置:当前任务的任务栈

保存时机:调度触发时,在中断上下文中保存

设计考虑:最小化保存内容,减少切换开销

堆栈切换

切换方式:修改栈指针寄存器(SP)指向目标任务栈

栈管理:每个任务拥有独立的栈空间

栈保护:防止栈溢出和栈冲突

恢复机制:从目标任务栈顶恢复执行现场

调度器触发

触发条件:时间片到期、任务主动让出(yield)、中断事件

调度算法:基于优先级的轮询调度

就绪队列:维护所有就绪任务的状态

选择策略:从就绪队列中选择最高优先级任务

恢复任务运行

恢复内容:从任务栈恢复寄存器和程序计数器

恢复时机:上下文切换的最后阶段

执行方式:通过中断返回指令(RETI)恢复执行

状态转换:任务从 Ready 状态进入 Running 状态

Workflow

工作流程

任务从创建到上下文切换的完整执行路径

1任务创建:hrtos_main 中创建 task_A 与 task_B,进入 Ready 状态
2调度启动:调度器选择一个任务进入 Running 状态
3LED 运行阶段:任务控制 LED 翻转,并执行软件延时循环
4时间片/切换点触发:Tick 或 yield 导致 CPU 让出
5上下文保存与恢复:保存当前任务状态,切换到另一个任务继续执行
hrtos_main → os_task_create → 就绪队列 → 调度器选择 → 任务运行 → LED 翻转 → 时间片/yield → 上下文保存 → 栈切换 → 上下文恢复 → 目标任务运行
Core Code

核心代码

上下文切换的完整实现

任务函数实现

task_A 和 task_B 任务函数,分别控制不同的 LED

#include "hrtos.h"

#define TASK_A 1
#define TASK_B 2

sbit LED_A = P1^0;
sbit LED_B = P1^1;

/* Task A */
void task_A(void)
{
    u16 i;
    P1=0XFF;
    while(1)
    {
        LED_A = ~LED_A;   // 切换A灯状态
        i=2000;
        while(i--);

    }
}

/* Task B */
void task_B(void)
{
    u16 i;
    while(1)
    {
        LED_B = ~LED_B;   // 切换B灯状态        
        i=2000;
        while(i--);        
        
    }
}

系统初始化与任务创建

hrtos_main 函数,创建两个任务并启动调度系统

/* 系统入口页 */
void hrtos_main(void)
{
    os_task_create((unsigned int)task_A, TASK_A, 3, 2);
    os_task_create((unsigned int)task_B, TASK_B, 3, 2);
}
Expected Result

运行结果

示例执行后的预期行为

LED 状态 LED_A 与 LED_B 交替变化,形成可观察的切换效果
任务调度 task_A 和 task_B 通过时间片和 yield 实现交替执行
系统状态 任务在 Running 和 Ready 状态之间循环切换
系统本质: 本示例的核心不是 LED,而是验证 HRTOS v2 中:两个独立任务在同一CPU上通过调度器实现交替执行。
Important Notes

注意事项

使用本示例时需要关注的关键点

任务栈配置

task_A 和 task_B 需要配置独立的任务栈空间,栈空间不足会导致上下文切换失败。 本示例使用默认栈配置,实际应用中应根据任务需求调整栈大小。

优先级设置

两个任务使用相同的优先级(优先级 3),在时间片调度下实现公平执行。 如果设置不同优先级,高优先级任务可能会抢占低优先级任务的执行。

上下文切换开销

上下文切换需要保存和恢复寄存器状态,存在一定的性能开销。 在实时性要求高的场景中,需要合理设置时间片长度,平衡切换频率和系统响应性。

调度触发时机

本示例主要通过时间片调度触发切换,也可以通过 yield 主动让出 CPU。 在实际应用中,应根据任务特性选择合适的调度触发方式。