8051模拟器汇编入门(8)中断

在这篇文章中, 我们将探索8051的中断(Interrputs)系统。那么,什么是中断呢?我们先来看看这个图表。

图片

这里有851,还有P3.2,这是8051的零号中断。我将它连接到一个电阻,与一个按钮开关串联在一起,这个开关是接地的,一端连接着,另一端我可以利用这个开关来模拟生成一个中断信号给8051。这是一个外部中断。

让我们来看一下什么是中断:

  • 中断是一个由硬件生成的信号,在这种情况下是一个开关。
  • 这个信号会中断正在执行的主程序,程序被挂起,然后执行一个中断服务例程(ISR)。
  • 这个ISR相当于一个子程序,一旦ISR完成,控制权就返回到主程序。
  • 中断可以是外部的,就像这个例子中的,或者内部的,我们将在稍后考虑内部中断。

那么,中断是如何工作的呢?我们这里有8051,它在核心内存中运行一个主程序。当P3.2发生中断时,8051会挂起主程序,并跳转到的0003H位置,这个位置在这里的调用内存中,那个位置应该找到一个LJMP到另一个位置的指令。在这个例子中,它是0060H。快速说一下,它不必是这个地址,它可以是其他地址。所以一旦它找到这个LJMP,它就会跳转到那个地址,找到ISR例程,执行那个中断服务例程。当执行完ISR后,控制权就返回到主程序。

图片

好的,让我们快速总结一下。当8051接收到外部中断INT0在引脚12时,它将挂起主程序的执行,然后跳转到0003H位置,这是在这里的代码内存中。在那个地址,它通常会找到一个LJMP到0060H的指令,这将把它带到中断服务例程。一旦这个例程完成,控制权就会回到主程序。这里的地址不必是0060H,它可以是任何其他地址,但这个0003H地址被称为中断向量地址。这个地址与外部中断INT0相关联。我们稍后会讲到更多相关内容。

向量地址(Vector Address)

那么,什么是向量地址呢?对于每个中断,都有一个固定的代码内存(Code Memory)位置包含中断服务例程或ISR的地址。我们在前面的例子中看到了INT0的固定位置是0003H。内存位置被保留用于保存ISR地址,这被称为中断向量表。所以当中断发生时,处理器会”跳转”到代码内存区域的一个地址位置,这个位置应该包含ISR的起始地址。

这是中断向量地址表。

图片

在这个列中,是所有8051中断的名称。有重置中断(Reset)、外部中断零(INT0),我们一直在使用的,然后是定时器零(Timer 0)、外部中断一(INT1)、定时器一(Timer 1)和串行中断(Serial)。对于重置中断,中断向量地址将是0000H,并且可以在引脚9上找到。外部中断零,我们在早期的例子中使用过,向量地址正如我们所看到的是0003H。第三个外部中断是外部中断一,向量地址是0013H,它在引脚13上。所以有三个外部中断:重置、外部中断零和外部中断一。还有三个内部中断,分别是定时器零、定时器一和串行中断。

中断使能寄存器(Interrupt Enable Register)

在我们开始编程之前,让我们看看中断使能寄存器(IE)。中断使能寄存器,是8051中的一个8位寄存器。

图片

让我们放大看一下IE寄存器:

图片

正如前面提到的,中断使能寄存器是一个8位寄存器,第七位是使能位,这个位必须设置为1以启用所有中断,0则会禁用所有中断。所以,要使用这些中断,第七位或EA位必须设置为1。

1. 位7 – EA:启用全部位 (Enable All Bit)

  •  1 = 启用所有中断
  •  0 = 禁用所有中断

2. 位6,5 – 保留位

3. 位4 – ES:启用串行中断位(Enable Serial Interrupt Bit)

  •  1 = 启用串行中断
  •  0 = 禁用串行中断

4. 位3 – ET1:启用定时器1中断位(Enable Timer1 Interrupt Bit)

  • 1 = 启用定时器1中断
  • 0 = 禁用定时器1中断

5. 位2 – EX1:启用外部1中断位(Enable External1 Interrupt Bit)

  • 1 = 启用外部1中断
  • 0 = 禁用外部1中断

6. 位1 – ET0:启用定时器0中断位(Enable Timer0 Interrupt Bit)

  •  1 = 启用定时器0中断
  •  0 = 禁用定时器0中断

7. 位0 – EX0:启用外部0中断位(Enable External0 Interrupt Bit)

  •  1 = 启用外部0中断
  •  0 = 禁用外部0中断

因为我们要使用位0外部中断位0,然后位7EA必须为1,所以这个寄存器的值为10000001,转换为16进制为81H。我们需要将这个编程到中断使能寄存器中。

图片

示例程序:

Org 0000h
Ljmp Main

Org 0003h
Ljmp 0060h

; Define ISR
Org 0060h
INTZero:    Mov R0,#80h      ;Set MSB high
            Mov P1,R0
            Acall LongDelay
            Reti

; Start of Main
Main:       Mov IE,#81h      ;Enable INT0
Back:       Mov R1,#01h      ;Set LSB high
            Mov P1,R1
            Jmp Back

LongDelay:  Mov R3,#0D0H
Start:      Acall FiftyMSec
            Djnz R3,Start
            Ret

FiftyMSec:  Mov TMOD,#01     ;Timer 0, mode 1
            Clr ET0          ;ET0=Enable Timer0 interrupt
Here:       Mov TH0,#03CH    ;TH0=3CH, high byte
            Mov TL0,#0B0H    ;TL0=B0H, low byte
            Clr TF0          ;Clear Timer 0 flag
            Setb TR0         ;Start Timer 0
Again:      Jnb TF0,Again    ;Monitor Timer0 flag
            Clr TR0          ;Stop Timer 0
            Ret
            End

该程序的主程序将最低位的LED保持常开,当接收到外部中断时,打开最高位的LED并保持50毫秒的一个延迟。

图片

运行模拟器,可以发现IE寄存器的值变为0x81,同时在代码内存60H处开始被ISR代码占用,最低位的LED灯常亮。