文章来源:《51单片机原理及应用(第3版)》5.4节。
51单片机采用了自然优先级和人工设置高、低优先级的策略。
当CPU处理低优先级中断,又发生更高级中断时,此时中断处理过程如下图所示。
一个正在执行的低优先级中断服务程序能被高优先级中断源的中断申请所中断,形成中断嵌套。
相同级别的中断源不能相互中断其服务程序,也不能被另一个低优先级的中断源所中断。
如果CPU正在执行高优先级的中断服务子程序,不能被任何中断源所中断。
上电时,中断优先级寄存器IP被清零,每个中断源都处于同一个优先级,这时如果其中几个中断同时产生中断请求,则CPU按照片内硬件优先级链路的顺序即自然优先级响应中断,硬件优先级有高到低的顺序如下表所示:
中断源 | 默认中断级别 | 中断号 |
---|---|---|
外部中断0——INT0 | 最高 | 0 |
定时/计数器0中断——T0 | 第2 | 1 |
外部中断1——INT1 | 第3 | 2 |
定时/计数器1中断——T1 | 第4 | 3 |
串口中断——TI/RI | 第5 | 4 |
定时/计数器2中断——INT2(52独有) | 第6 | 5 |
如果希望某个中断源有更高的优先级,可以通过设置中断优先级寄存器IP指定更高优先级的中断。IP各位如下表:
位序 | D7 | D6 | D5 | D4 | D3 | D2 | D1 | D0 |
---|---|---|---|---|---|---|---|---|
位名称 | / | / | / | PS | PT1 | PX1 | PT0 | PX0 |
IP中的某位设置为,则相应的中断就是高优先级;否则就是低优先级;在同一个优先级下,中断响应的顺序和自然优先一样。IP可位寻址。
各个位说明:
PS
:串口中断优先级控制位PT1
:定时器1优先级控制位PX1
:外部中断1优先级控制位PT0
:定时器0优先级控制位PX0
:外部中断0优先级控制位
比如要求将外部中断1,定时器0设为高优先级,其它为低优先级,那么应该置PT0=1,PX1=1,高三位取任意值,设置为0,那么IP的值应该为00000110B=06H,此时如果5个中断同时发生,中断响应的次序为:定时器0中断→外部中断1→外部中断0→定时器1→串口中断。
中断优先级应用示例
设置外部中断1为高优先级,在两个外部中断引脚(P3.2和P3.3)接两个按键,P1口连接LED。连接P3.2口的按键按下后,LED循环点亮;连接P3.3口的按键按下后,LED全部点亮-熄灭,连续3次。
Proteus设计原理电路图如下:
软件设计
源程序清单:
/*
实现功能:中断优先级使用示例,设置外部中断1为高优先级,P1口连接LED,P3.2和P3.3分别连接两个按键
连接P3.2的按键INT0按下后LED循环点亮,连接P3.3的按键INT1按下后LED全部点亮-熄灭,闪烁3次。
通过先按下按键INT0,然后再按下按键INT1可以看到LED依次点亮-全部点亮熄灭闪烁3次-依次点亮,直观显示中断优先级的作用。
[2024-01-31] zoya
*/
#include <reg51.h>
#include <intrins.h>
typedef unsigned char uchar;
#define GPIO_LED P1
void delay(uchar c)
{
uchar i,j;
for(;c>0;c--)
{
for(i=0;i<142;i++)
for(j=0;j<2;j++);
}
}
void main()
{
EX0=1; // 外部中断0允许位
EX1=1; // 外部中断1允许位
IT0=1; // 定时器0允许位
IT1=1; // 定时器1允许位
EA=1; // 总中断允许位
IP=0x04; // 中断优先级设置,外部中断1高优先级
GPIO_LED=0xff;
while(1);
}
void Int0() interrupt 0
{
uchar i, tmp;
EX0=0; // 关闭外部中断0,防止执行过程中再次发生中断
delay(20);
EX0=1; // 开外部中断0
while(1)
{
tmp=0xFE;
GPIO_LED=tmp;
for(i=0;i<8;i++)
{
tmp=_crol_(tmp,1);
delay(100);
GPIO_LED=tmp;
}
}
}
void Int1() interrupt 2
{
EX1=0; // 关闭外部中断1,防止执行过程中再次发生中断
delay(20);
EX1=1; // 开外部中断1
GPIO_LED=0x00; delay(100);
GPIO_LED=0xff; delay(100);
GPIO_LED=0x00; delay(100);
GPIO_LED=0xff; delay(100);
GPIO_LED=0x00; delay(100);
GPIO_LED=0xff; delay(100);
}
仿真结果: