3

我一直在 8051 微控制器上编程,在处理中断时发现了一些奇怪的东西。假设发生了中断。在处理该中断时,正在发生另一个具有更高优先级的中断。控制器不应该跳入服务较高优先级的中断,然后返回到较低的中断吗?

以下说明了我的问题。连接键盘以触发外部中断 1(较低优先级)并启用定时器 0 中断(较高优先级)。


// With this snippet, the LED-s are blinking as expected.
#include <8051.h>
#include <stdint.h>
#include <stdbool.h>

__xdata __at (0x9000) uint8_t KEYPAD;
__xdata __at (0xA000) uint8_t LED;

uint8_t LedState = 0x00;
bool Running = false;

void StopperIsr() __interrupt TF0_VECTOR
{
    LedState = ~LedState;
    LED      = LedState;
    TR0      = 0;   // Prevent the timer restating right away.
    Running = false;
}

void StopperStart()
{
    TL0 = 0;
    TH0 = 0;
    TR0 = 1;      // Start timer 0
    Running = true;
}

void main()
{
    ET0  = 1;     // Enable timer 0 interrupt.
    EA   = 1;     // Enable global interrupts.
    TMOD = T0_M0; // Set timer 0 to 16-bit mode.

    while(1) {
      if (false == Running) {
        StopperStart();
      }
    }
}

// The stopper is used inside external interrupt 1 ISR and since timer 0 has
// higher priority, the LED-s should be blinking just like in the previous snippet.
// This is not the case. Instead, on keypress, the ISR is called (LED gets 0xFF),
// but timer 0 ISR is never entered.
#include <8051.h>
#include <stdint.h>
#include <stdbool.h>

__xdata __at (0x9000) uint8_t KEYPAD;
__xdata __at (0xA000) uint8_t LED;

uint8_t LedState = 0x00;
bool Running = false;

void StopperStart()
{
    TL0 = 0;
    TH0 = 0;

    TR0 = 1;      // Start timer 0.
    Running = true;
}

void StopperIsr() __interrupt TF0_VECTOR
{
    LedState = ~LedState;
    LED      = LedState;

    TR0      = 0;  // Stop the timer.
    Running = false;
}

void KeypadIsr() __interrupt IE1_VECTOR
{
    LedState = 0xFF;
    LED      = LedState;

    while(1) {
      if (!Running) {
        StopperStart();
      }
    }
}

void main()
{
    EX1  = 1;     // Enable keypad interrupt on external interrupt 1.
    ET0  = 1;     // Enable timer 0 interrupt.
    TMOD = T0_M0; // Set timer 0 to 16-bit mode.
    EA   = 1;     // Enable global interrupts.
    KEYPAD = 0;   // Reset the keypad to its initial state.
}
4

2 回答 2

4

很抱歉这么说,但这里完全错误的答案被认为是最好的。同时,TurboJ 给出了正确答案(实际上不止一个),该答案仅作为评论可见。

8051 micro(或任何其他具有多个中断优先级的)在完成之前不会执行中断,如果更高级别的中断未决,如果所有相关中断都已启用,并且优先级正确设置。更高优先级的中断处理程序将执行。相同优先级的中断会按照预定的顺序被扫描,那些不能中断同级的中断。默认情况下,8051 将所有中断设置在同一级别,这就是示例中显示的问题(正如@TurboJ 正确指出的那样)

如果不是这种情况,那么拥有多个中断优先级又有什么意义呢?较高优先级中断处理程序中断较低优先级中断处理程序的概念称为“中断嵌套”。

于 2013-03-14T14:29:05.507 回答
2

也许“同时”在这里是错误的词,因为这对我来说意味着它们是同时开始的。鉴于此,优先级较高的一方将获胜。我认为“并发”可能是一个更好的词。你会认为处理器会跳转到更高优先级的处理器,但不,它不是这样工作的。只有一个进入实际处理器的中断线。因此,就处理器而言,它要么处理中断,要么不处理(线路有信号或没有信号)。有一个中断控制器可以帮助将多个中断多路复用到那条线上,而中断控制器可以帮助确定优先级。在更大的微控制器中,中断控制器和处理器之间有更多的分离,但它仍然存在于 8051 中......只是稍微隐藏了一点。无论如何,一旦中断处理开始,微控制器将处理该中断直到完成,然后再通知下一个中断,即使待处理的中断具有更高的优先级。

有关其工作原理的详细信息,您可以查看Atmel 的 8051 硬件指南。虽然它特定于它们的实现,但大多数实现都非常接近(它们都试图保持原始 8051 micro 的原始语义)。在第 2-112 页上,他们谈到处理中断。第 2.16.1 节说:

从该位置继续执行,直到遇到 RETI 指令。RETI 指令通知处理器该中断程序不再进行,然后从堆栈中弹出顶部两个字节并重新加载程序计数器。被中断的程序从中断处继续执行

第一行在这里很重要。在该RETI指令执行之前,不会处理下一个中断。

于 2012-09-12T07:36:08.250 回答