云计算百科
云计算领域专业知识百科平台

HRTOS_InterruptNesting:中断打断内核运行测试

1. 实验目的

在实时操作系统中,中断并不是只发生在普通应用任务运行期间。

对于一个完整的实时系统来说,中断可能在系统运行的任意时刻到来,包括:

  • 普通任务运行期间;

  • 任务切换过程中;

  • 系统调度过程中;

  • 内核执行关键操作期间。

因此,一个实时操作系统除了需要验证普通任务之间的调度是否正确,还需要进一步验证:

当 CPU 正处于 HRTOS 内核执行过程中时,如果硬件中断到来,系统能否正确响应中断,并在中断处理完成后恢复原有执行流程。

本实验正是针对这一问题设计的。

通过 Timer1 周期性产生中断,同时创建普通任务、中断任务以及嵌套中断任务,对 HRTOS 的中断打断内核运行能力进行测试。


2. 测试系统结构

本实验包含三个层次的运行对象:

┌─────────────────────────────┐
│ HRTOS 内核运行 │
│ │
│ 调度 / 任务切换 / 内核处理 │
└──────────────┬──────────────┘

│ 硬件中断到来

┌─────────────────────────────┐
│ T1 中断处理 │
│ 优先级 9 │
└──────────────┬──────────────┘

│ 更高优先级中断

┌─────────────────────────────┐
│ T1 嵌套中断层 │
│ 优先级 10 │
└─────────────────────────────┘

与此同时,系统还运行两个普通任务:

TASK_A Priority 4
TASK_B Priority 4

因此整个实验同时包含:

  • 普通任务运行;

  • 同优先级任务调度;

  • 硬件 Timer1 中断;

  • 中断打断内核;

  • 中断优先级;

  • 中断嵌套;

  • 中断退出后的系统恢复。

这使得它并不是一个简单的“LED 中断实验”,而是一个针对 HRTOS 内核与中断协同工作能力 的测试程序。


3. 普通任务

实验首先创建两个普通任务:

#define TASK_A 1
#define TASK_B 2

#define PRIO_TASK 4

两个任务具有相同的优先级。

任务 A:

static void task_a(void)
{
LED_A = 1;

while (1)
{
count_a++;

LED_A = ~LED_A;

os_delay(TICK_TASK);
}
}

任务 B:

static void task_b(void)
{
LED_B = 1;

while (1)
{
count_b++;

LED_B = ~LED_B;

os_delay(TICK_TASK);
}
}

两个任务分别完成:

任务运行

计数器增加

LED 翻转

延时 20

重新进入调度

它们的作用并不是本实验的重点,而是提供一个持续运行的 HRTOS 应用环境。

这样 Timer1 中断发生时,系统并不是停留在一个简单的裸机 while(1) 中,而是在真实的任务调度环境中运行。


4. Timer1 初始化

Timer1 配置代码如下:

void Timer1_Init(void)
{
TMOD &= 0x0F;
TMOD |= 0x10; // T1模式1

TH1 = 0xFC;
TL1 = 0x18; // 12MHz 1ms

TF1 = 0;
ET1 = 1;
PT1 = 1; // T1高优先级
TR1 = 1;
}

这里使用 Timer1 模式 1。

在 12MHz 时钟条件下,通过:

TH1 = 0xFC;
TL1 = 0x18;

设置定时器初值,使 Timer1 周期性产生中断。

同时:

ET1 = 1;

打开 Timer1 中断。

而:

PT1 = 1;

将 Timer1 设置为较高的硬件中断优先级。

最后:

TR1 = 1;

启动 Timer1。


5. T1 中断处理

T1 中断处理函数:

static void t1_isr(void)
{
count_t1++;

TH1 = 0xFC;
TL1 = 0x18;

/*
* T1进入中断
*/
LED_T1 = ~LED_T1;

/*
* 中断处理完成
*/
os_interrupt_exit();
}

每次 Timer1 产生中断后,首先:

count_t1++;

增加中断计数。

然后重新装载定时器:

TH1 = 0xFC;
TL1 = 0x18;

之后翻转:

LED_T1 = ~LED_T1;

通过 LED 可以直观看到 Timer1 中断是否持续进入。

最后调用:

os_interrupt_exit();

通知 HRTOS:

当前中断处理已经完成,可以退出当前中断处理流程。

因此,中断处理的基本过程可以表示为:

Timer1 到期

产生硬件中断

进入 HRTOS 中断处理

保存当前运行环境

执行 t1_isr()

更新中断计数

重新装载 Timer1

处理中断

os_interrupt_exit()

恢复原有运行环境


6. 中断优先级设计

本实验非常关键的一部分,是 HRTOS 对中断运行层级的设计。

代码中定义:

#define PRIO_TASK 4
#define PRIO_T1 9
#define PRIO_T1_NEST 10

可以看到:

Priority 10 T1 嵌套中断

Priority 9 T1 普通中断

Priority 4 普通任务

因此 HRTOS 的运行层级可以理解为:

普通任务

普通中断

嵌套中断

这里体现的是一种非常明确的实时优先级层次。

普通任务处于较低优先级。

Timer1 中断处于更高的中断优先级。

而嵌套中断又处于更高一级。


7. 什么叫“中断打断内核”?

这是本实验最核心的概念。

普通情况下,我们可能只考虑:

任务 A

Timer1 中断

返回任务 A

这种情况实际上只说明:

中断可以打断应用任务。

但对于操作系统来说,这还不够。

HRTOS 的 CPU 并不总是在运行应用任务。

例如系统可能正在执行:

任务切换

保存任务上下文

选择下一个任务

恢复任务上下文

这些操作属于内核运行过程。

此时如果 Timer1 中断到来,就会形成:

HRTOS 内核

正在执行内核代码

Timer1 中断到来

中断打断内核

执行中断处理

中断退出

恢复被打断的内核运行

继续完成原来的内核操作

这才是本实验真正想验证的内容。


8. 为什么这个测试很重要?

因为内核代码与普通应用代码存在一个重要区别:

内核代码往往直接操作任务上下文、调度状态以及 CPU 寄存器环境。

如果中断在不合适的时刻进入,而系统没有正确保存和恢复现场,就可能产生非常严重的问题。

例如:

内核正在切换任务

中断突然进入

修改 CPU 上下文

中断返回

原来的上下文恢复错误

任务异常

严重情况下可能表现为:

  • 程序跑飞;

  • 任务无法继续运行;

  • LED 停止变化;

  • 系统进入异常状态;

  • 栈数据破坏;

  • 长时间运行后出现随机错误。

因此,中断打断内核之后还能否正确恢复,是判断实时内核可靠性的重要测试之一。


9. HRTOS 中断嵌套测试

系统入口中创建了两个中断运行层:

os_task_create((unsigned int)t1_isr, TASK_T1, PRIO_T1, STACK_T1);

以及:

os_task_create((unsigned int)t1_isr, TASK_T1, PRIO_T1_NEST, STACK_T1);

对应:

T1 普通中断任务
Priority 9

T1 嵌套中断任务
Priority 10

这意味着 HRTOS 不只是测试普通中断,还进一步建立了更高优先级的嵌套中断运行层。

因此测试覆盖的范围进一步扩大:

普通任务

中断

更高优先级中断

如果在这种情况下系统仍然能够持续运行,就可以进一步验证中断上下文管理和嵌套处理能力。


10. 中断退出为什么需要专门的 API?

本实验使用:

os_interrupt_exit();

而不是简单地从中断函数返回。

这是因为对于 HRTOS 来说,中断不仅仅是普通 C 函数调用。

进入中断以后,系统可能涉及:

  • CPU 上下文;

  • 当前任务状态;

  • 中断层级;

  • 调度状态;

  • 中断嵌套状态;

  • 中断返回后的任务恢复。

因此,中断处理完成以后,需要通过 HRTOS 提供的中断退出机制完成对应的系统处理。

本实验中:

os_interrupt_exit();

就是整个中断处理流程的重要组成部分。

因此不能简单地把它理解成一个普通的函数调用。


11. 实验观察方法

本实验使用三个 LED:

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

分别对应:

P1.0 → 任务 A
P1.1 → 任务 B
P1.2 → Timer1 中断

同时还有三个计数变量:

static u16 count_a = 0;
static u16 count_b = 0;
static u16 xdata count_t1 = 0;

它们可以分别用于观察:

count_a → 任务 A 是否正常运行
count_b → 任务 B 是否正常运行
count_t1 → Timer1 中断是否持续进入

因此,如果系统长时间运行后:

  • A LED 正常变化;

  • B LED 正常变化;

  • T1 LED 持续变化;

  • 三个计数器持续增长;

  • 系统没有跑飞;

那么就说明在测试条件下,中断与 HRTOS 任务运行之间能够持续协同工作。


12. 与普通裸机中断实验的区别

传统 8051 裸机中断测试通常是:

while (1)
{
// 主循环
}

然后:

Timer1 中断

执行 ISR

返回主循环

这种实验主要验证:

8051 硬件中断能否正常工作。

而 HRTOS 的测试环境则复杂得多:

HRTOS 内核

┌────────┴────────┐
│ │
任务 A 任务 B
│ │
└────────┬────────┘

Timer1


中断处理

更高优先级嵌套


中断退出


恢复原有执行流程

所以这个实验的目标已经从:

“中断能不能工作”

提升到了:

“中断在 HRTOS 运行过程中能否正确打断系统,并保持内核运行环境的一致性。”

这两者的测试难度并不是一个级别。


13. 完整测试代码

#include "hrtos.h"

/*==================== 配置 ====================*/
#define TASK_A 1
#define TASK_B 2

#define TASK_T1 0

#define PRIO_TASK 4
#define PRIO_T1 9
#define PRIO_T1_NEST 10

#define STACK_TASK_A 5
#define STACK_TASK_B 5
#define STACK_T1 0

#define TICK_TASK 20

/*==================== LED 定义 ====================*/
sbit LED_A = P1^0; /* 任务A指示灯 */
sbit LED_B = P1^1; /* 任务B指示灯 */
sbit LED_T1 = P1^2; /* T1中断指示灯 */

/*==================== 全局 ====================*/
static u16 count_a = 0;
static u16 count_b = 0;
static u16 xdata count_t1 = 0;

/*==================== 普通任务A ====================*/
static void task_a(void)
{
LED_A = 1;

while (1)
{
count_a++;

LED_A = ~LED_A;

os_delay(TICK_TASK);
}
}

/*==================== 普通任务B ====================*/
static void task_b(void)
{
LED_B = 1;

while (1)
{
count_b++;

LED_B = ~LED_B;

os_delay(TICK_TASK);
}
}

void Timer1_Init(void)
{
TMOD &= 0x0F;
TMOD |= 0x10; // T1模式1

TH1 = 0xFC;
TL1 = 0x18; // 12MHz 1ms

TF1 = 0;
ET1 = 1;
PT1 = 1; // T1高优先级
TR1 = 1;
}

/*==================== T1中断处理 ====================*/
static void t1_isr(void)
{
count_t1++;

TH1 = 0xFC;
TL1 = 0x18; // 12MHz 1ms

/*
* T1进入中断
*/
LED_T1 = ~LED_T1;

/*
* 中断处理完成
*/
os_interrupt_exit();
}

/*==================== 系统入口 ====================*/
void hrtos_main(void)
{
Timer1_Init();

/*
* 两个同优先级普通任务
*/
if (os_task_create(task_a, TASK_A, PRIO_TASK, STACK_TASK_A) != 1)
{
while (1);
}

if (os_task_create(task_b, TASK_B, PRIO_TASK, STACK_TASK_B) != 1)
{
while (1);
}

/*
* T1普通中断任务
* 优先级9
*/
os_task_create((unsigned int)t1_isr, TASK_T1, PRIO_T1, STACK_T1);

/*
* T1嵌套中断任务
* 优先级10
*/
os_task_create((unsigned int)t1_isr, TASK_T1, PRIO_T1_NEST, STACK_T1);
}


14. 这个实验真正验证了什么?

这个程序的价值并不在于 Timer1 本身。

Timer1 只是一个中断触发源。

真正需要验证的是下面这一条链路:

HRTOS 正常运行

CPU 执行内核代码

硬件中断产生

中断打断当前内核执行

进入中断处理

中断处理完成

os_interrupt_exit()

恢复原来的运行环境

HRTOS 继续执行

进一步加入中断嵌套后,则变成:

HRTOS 内核

T1 中断

更高优先级中断

嵌套中断退出

T1 中断继续/退出

恢复 HRTOS

因此,这个实验实际上是在对 HRTOS 最底层的内核—中断协同机制进行压力验证。


15. AI 编写 HRTOS 中断程序需要注意什么?

这个实验同样非常适合用于建立 HRTOS 的 AI 编程知识体系。

对于 AI 来说,看到:

os_interrupt_exit();

不能简单按照其他 RTOS 的中断 API 进行推测。

HRTOS 的中断模型具有自己的任务优先级和中断层级设计:

普通任务
Priority 4

普通中断
Priority 9

嵌套中断
Priority 10

因此,AI 在生成 HRTOS 中断程序时,需要首先依据 HRTOS 自身的 API 和任务模型进行设计,而不是直接套用其他 RTOS 的中断处理模板。

尤其需要注意:

中断处理程序、普通任务和内核调度代码并不是同一种运行上下文。

如果不了解这一点,很容易生成虽然“语法正确”,但不符合 HRTOS 实际运行机制的程序。


16. 总结

HRTOS_InterruptNesting 并不是一个简单的 Timer1 中断例程。

它的核心测试目标是:

验证 HRTOS 内核运行过程中受到硬件中断打断后,系统能否正确处理中断,并恢复原有的内核运行流程。

实验同时引入普通任务、Timer1 中断以及更高优先级的嵌套中断,形成:

普通任务

HRTOS 内核

Timer1 中断

嵌套中断

中断退出

恢复 HRTOS

对于一个 8051 实时操作系统来说,这类测试比单纯的 LED、任务创建测试更加接近内核底层可靠性验证。

也正因为如此,中断打断内核的测试,是 HRTOS 从“能够运行”进一步走向“能够长期可靠运行”的重要测试环节。

 

赞(0)
未经允许不得转载:网硕互联帮助中心 » HRTOS_InterruptNesting:中断打断内核运行测试
分享到: 更多 (0)

评论 抢沙发

评论前必须登录!