折腾来折腾去

pikipity的blog

单片机原理及程序设计 第五章 中断

中断是单片机中一个非常重要的服务。中断是指由于接收到外围硬件的异步信号或是软件的同步信号,而进行的相应的软件或是硬件上的处理。发出这样的信号被称为中断请求,发出中断请求的硬件或是软件被称为中断源。当中断源产生了中断请求,相应的中断旗标(就是对应的寄存器的一个 bit)便会置“1”,8051的 CPU 每个机械周期里都会去检查这些中断旗标,若发现中断旗标置“1”,CPU便会在执行完当前指令后,将当前的执行状态(以程序计数器和程序状态字等寄存器信息为主)塞入堆叠中保存,然后跳到相应的程序内存地址(这个程序内存地址叫做中断向量)执行那里的中断副程序,直到执行到 “RETI” 指令后结束附程序,将塞入堆叠的执行状态取出,回到之前的主程序继续执行。

中断分类

8051中的中断可分为2两种:

  1. 不可屏蔽中断:无法通过在中断屏蔽寄存器中设定位掩码来关闭,典型例子是时钟中断(时钟中断不是指的计时/计数器 Timer0 或是 Timer1,而是一个硬件时钟,其会以恒定频率,如12MHz,发出中断)。
  2. 可屏蔽中断:可通过在中断屏蔽寄存器中设定位掩码来关闭。

不可屏蔽中断无法控制,是单片机工作的基础,所以不作介绍。只介绍可以控制的可屏蔽中断。

中断源

8051提供了五个中断源。中断源、中断向量、中断旗标及中断旗标所属寄存器都列在下表中:

|———–+——-+——+—————| |中断源 |中断向量|中断旗标|中断旗标所属寄存器| |:———:|:—–:|:—-:|:————-:| |INT0 |0003H |IE0 |TCON.1 | |Timer0 |000BH |TF0 |TCON.5 | |INT1 |0013H |IE1 |TCON.3 | |Timer1 |001BH |TF1 |TCON.7 | |UART (TXD) |0023H |TI |SCON.1 | |UART (RXD) |0023H |RI |SCON.0 | |———–+——-+——+—————|

具体满足什么条件会产生中断请求会在介绍各个中断源的时候详细介绍。需要注意的就是串列口 UART 的输入输出中断的中断向量都是 0023H,在使用的时候要判断到底是输入还是输出。

中断置能

8051在重置之后会关闭所有可屏蔽中断,所以在使用中断之前需要打开需要的中断功能,也就是中断置能。中断功能打开关闭通过中断置能寄存器(IE,地址为 A8H,允许按位寻址)管理。下面是中断置能寄存器各个 bit 的意思(“1”为使能,“0”为关闭):

EA  --  --  ES  ET1  EX1  ET0  EX0
  1. EA: 相当于中断的总开关。置“0”就关闭所有中断。置“1”再根据下面的 bit 来看这个中断是否置能。
  2. ES:串列口(UART)中断使能位。
  3. ET1:计时/计数器 Timer1 使能
  4. EX1:外部中断 INT1 使能
  5. ET0: 计时/计数器 Timer0 使能
  6. EX0:外部中断 INT0 使能

中断优先级

当多个中断旗标同时存在时,就会有一个先执行哪个中断向量的问题,8051内置了一个中断优先级,优先级高的先执行,优先级如下(顺序其实是按照中断向量排列的):

  1. 外部中断 INT0
  2. 计时/计数器 Timer0
  3. 外部中断 INT1
  4. 计时/计数器 Timer1
  5. 串列口(UART)

8051允许用户设置两层优先级,8051会先执行高层优先级中的中断,同一层中的中断优先顺序则按照上面的排序来进行。两层优先级的归属问题通过中断优先级寄存器(IP,地址为 B8H,允许位元定址)来设定。IP 每一个 bit 代表的意义如下(“1”代表高优先级,“0”代表低优先级):

--  --  --  PS  PT1  PX1  PT0  PX0
  1. PS:串列口(UART)优先级
  2. PT1:计时/计数器 Timer1 优先级
  3. PX1:外部中断 INT1 优先级
  4. PT0: 计时/计数器 Timer0 优先级
  5. PX0:外部中断 INT0 优先级

Assembly 程序设计

一个需要使用中断的 Assembly 程序设计的时候需要注意以下几点:

  1. 由于中断向量都在程序记忆体的开始部分,所以主程序要注意回避中断向量的位置,所以一开始一般通过一个跳跃跳到主程序,例如

         ORG 00H
         JMP MAIN
            .
            .
            .
    
         ORG 30H
     MAIN:
            .
            .
            .
         END
    
  2. 两个中断向量之间的空间很短,一般无法放下整个附程序,所以一般在中断向量处通过一个跳跃到其他位置来执行副程序,例如

         ORG 00H
         JMP MAIN
    
         ORG 03H
         JMP INT0
    
         ORG 0BH
         JMP TIMER0
    
         ORG 30H
     INT0:
            .
            .
            .
         RETI
    
     TIMER0:
             .
             .
             .
          RETI
    
    MAIN:
           .
           .
           .
         END    
    
  3. ORG 声明程序内存地址的时候要按照程序内存的顺序摆放,比如不可以出现 ORG 05HORG 03H 前面的情况

  4. 在执行中断副程序之前记得保存之间需要保护的变量(填入堆叠就可以了)。结束之后记得把保护的变量提取出来。
  5. 有的时候再执行一个中断的时候不希望其他中断来打扰,记得在执行中断副程序之前关闭中断( CLR EA ),在执行结束后记得打开中断( SETB EA)。
  6. 在执行一个中断副程序的时候,如果其中断旗标再次置起,不会重新跳回中断向量。


Comments