主程序正在执行,这时候定时器溢出、串口收到一个字节、或者按键被按下——中断请求来了。

CPU 现在面临一个选择:手头这条指令还没执行完,是继续执行完,还是立刻跳过去处理中断?

答案是:执行完当前这一条

8051 的中断响应不是"立即"的,它有三个明确的条件:

  1. 当前指令必须执行完毕。哪怕还差最后一个机器周期,也要等它做完。
  2. 如果当前正在执行 RETI,或者正在访问 IE / IP 这两个寄存器,也要等这条指令之后再响应。
  3. 当前没有被更高优先级的中断服务程序占用。

所以中断响应的延迟不是固定的。最快的情况,中断请求来临时刚好处在最后一条指令的最后一个周期,下一个周期就能响应;最慢的可能要等好几个机器周期。

这个细节解释了一个常见的困惑:"为什么我算好的定时时间总是有一点点偏差?"——偏差的一部分就来自这里。

现场保护:谁来做

跳去处理中断之前,CPU 得先把"手头的活"记下来,不然回来就接不上了。8051 自动做两件事:

但注意,这远远不够。ACC、B、DPTR、以及你正在用的通用寄存器 R0~R7,这些 CPU 都不会帮你保存。它们得你自己在中断服务程序里用 PUSH 保存、RETI 前用 POP 恢复。

TIMER0_ISR:
    PUSH ACC            ; 保存现场
    PUSH PSW
    PUSH DPL
    PUSH DPH

    ; ... 中断处理代码 ...
    MOV TH0, #0xDC      ; 重装初值
    MOV TL0, #0x00

    POP DPH             ; 恢复现场
    POP DPL
    POP PSW
    POP ACC
    RETI                ; 注意是 RETI,不是 RET

中断服务程序结尾必须用 RETI,不能用 RET。RETI 除了弹出返回地址,还会清除中断优先级触发器——用 RET 的话,这个中断的响应标志不会被清掉,会导致这个中断之后再也不响应了。

优先级:谁能插谁的队

8051 有两级优先级。规则很简单:

情况 结果
高优先级请求到达,低优先级正在执行 可以打断(嵌套)
低优先级请求到达,高优先级正在执行 等它做完
同级请求到达,同级正在执行 等它做完(同级不能嵌套)
同时来两个不同级 高优先级先响应

同级不能嵌套这条经常被忽略。比如串口和定时器1都被设成低优先级,定时器1的中断服务程序执行到一半,串口请求来了——CPU 不会切过去,必须等定时器1的 ISR 完全结束。

如果你希望串口能打断定时器,就得把串口设成高优先级。

同一优先级内部还有顺序

如果同时来了两个同级中断,按固定的查询顺序响应,也就是所谓的"中断优先级排队"顺序:

外部中断0  →  定时器0  →  外部中断1  →  定时器1  →  串口
   高                                              低

这个顺序是硬件定死的,改不了。只能通过设置 IP 寄存器把它们分到不同优先级来调整。

一句话总结

指令取指、译码、执行的具体过程,可以对着 8051 指令查表动画 一步一步走一遍,比看文字直观。

B. 直接写 HTML:

...

其余(顶栏分类、左侧边栏、右侧工具条、目录、上下篇)全部自动生成。 -->
单片机实训平台MCU Lab

首页/图文文章

中断是怎么插队的

主程序正在执行时来了一个中断请求,CPU 是先把手头的活干完,还是立刻跳走?答案是看这条指令执行完没有——这个细节决定了中断响应的延迟。