中断系统

中断的作用

所谓中断是指CPU对系统中或系统外发生的某个事件的一种响应过程,即CPU暂停现行程序的执行,而自动转去执行预先安排好的处理该事件的服务子程序(函数)。当处理完毕后,再返回被暂停程序的断点处,继续执行原来的程序。

image-20210613132920720

8051单片机的中断资源

  • AT89S515个中断源

外部中断请求0,P3.2

定时器计数器0溢出

外部中断请求1P3.3

定时器计数器1溢出

串口发送接收

image-20210613133923572

2个可编程软件中断优先级(2级中断嵌套)

  • IE(中断允许寄存器)

中断源的中断请求是否能得到响应,受IE的控制;

  • IP(中断优先级寄存器)

各个中断源的优先级可由IP的各位来确定。

TCON:定时/计数器控制寄存器

image-20210613134313362

  • 定时计数器中断相关:

TF1 - 定时器1溢出中断标志

TF0 - 定时器0溢出中断标志

  • 外部中断相关:

IE1、IE0 - 外部中断1、外部中断0中断标志

IT1、IT0 - 外部中断1、外部中断0触发方式控制位
(IT=1: 下降沿触发)
(IT=0:低电平触发)

📢📢:TF1、TF0、IE1、IE0具有自动清零功能(进入中断响应程序时由**硬件**清零)

SCON:串行口控制寄存器

image-20210613134819206

SM0 SM1串行模式选择

SM2 多机通讯允许位:方式0时,此位应该为0;模式1时,当接收到停止位时,该位将置位;方式2或方式3时,当接收的第9位数据为1时,将置位

REN 串行接收允许位

TB8 在模式2和模式3中,将被发送数据的第9位

RB8:在方式0中, 不起作用;在方式1中该位为接收数据的停止位;在方式2和方式3 中为接收数据的第9位。

📢📢:TI 串行发送结束标志,只能由**软件** 清零

​ **RI 串行接收结束标志,只能由软件**清零

MCS-51的中断控制系统

image-20210613135239736

中断的控制

image-20210613135415257

EA – 全局使能

EX0 – 外部中断0使能

ET0 – 定时计数器溢出中断0使能

EX1 – 外部中断1使能

ET1 – 定时计数器溢出中断1使能

ES – 串口中断使能

📌记忆:

记忆:

X – E**x** ternal 外部中断

T – **T**ime 定时器计数器中断

S – **S**erial Port 串口中断

1 – 使能; 0 – 禁止

image-20210613140442651

image-20210613143521508

1 – 高优先级;0 – 低优先级

8051单片机中断的优先级

8051单片机有可编程的两个中断优先级**,即可实现二级中断服务嵌套。每个中断源的中断优先级都是由中断优先级寄存器IP中的相应位的状态来规定的。
**(软件优先级)

**同一时刻同一优先级中的中断申请不止一个时,则有中断优先权排队问题。同一优先级的中断优先权排队,由中断系统硬件查询机制确定的自然优先级形成。
**(硬件查询排序)

8051单片机的中断优先级控制的三条原则:

1、正在进行的中断过程不能被新的同级或低优先级的中断请求所中断

image-20210613144218153

2、正在进行的低优先级中断服务,能被较高优先级中断请求所中断

image-20210613144325453

3、CPU同时接收到几个中断时,首先响应优先级别最高的中断请求

image-20210613144426677

中断的硬件排序

**硬件排序**是由单片机内部硬件的中断查询机制确定的,它是固定不变的。

image-20210613144620508

8051单片机中断的响应过程

CPU在每个机器周期的S5P2时刻扫描中断标志

阻止条件:

(1)CPU正在处理同级的或者高一级的中断;

(2)当前机器周期不是当前所执行指令的最后一个机器周期;

(3)当前正在执行的指令是RETI指令或是对IE或者IP的读写指令

中断标志扫描结果不保留,每个周期都重新扫描

保存断点 → 调用 → 恢复断点

8051外部中断

image-20210613145017494

如果外部中断输入引脚检测到如下信号:

下降沿(当IT0=1时)

低电平(当IT0=0时)

则相应中断标志将被自动置位,即IE0=1。CPU在S5P2时刻检测到中断标志位后,如果中断使能,并且没有阻止条件存在,将调用相应的中断服务函数,同时清除中断标志,执行完毕后返回原程序继续执行。

1低电平触发方式

外部中断申请触发器的状态随着CPU在每个机器周期采样到的外部中断输入引脚的电平变化而变化。

中断服务程序返回之前外中断请求输入必须无效(即外部中断请求输入已由低电平变为高电平),否则会再次响应中断。

所以本方式适合于外部中断以低电平输入且中断服务程序能清除外部中断请求源(即外中断输入电平又变为高电平)的情况。

2下降沿触发方式

外部中断申请触发器能锁存外部中断输入线上的负跳变。即使不能响应,中断请求标志不丢失。

相继连续两次采样,一个机器周期为高,下一个机器周期采样为低,则中断申请触发器置1,直到CPU响应此中断时,才。

输入的负脉冲宽度至少保持12个时钟周期,才能被采样到。适合于以负脉冲形式输入的外部中断请求。

中断标志的可靠产生

  • 下降沿(当IT0=1时)

高电平持续时间 >= 1个机器周期

低电平持续时间 >= 1个机器周期

  • 低电平(当IT0=0时)

低电平持续时间 >= 1个机器周期

📢📢:针对**低电平触发**方式,应当注意避免不必要的多次响应

中断请求的撤销

  • 外部中断

进入中断响应函数时**自动清除**。(注意低电平方式)

  • 定时器中断

进入中断响应函数时**自动清除**。

  • 串口中断

响应串行口的中断后,CPU无法知道是接收中断还是发送中断,还需测试这两个中断标志位,以判定是接收操作还是发送操作,然后才清除。所以串行口中断请求的撤销只能使用软件的方法,在中断服务程序中进行的。

8051单片机的中断响应时间

  • 最短响应时间

image-20210613150513979

实际考虑阻止条件,中断响应时间总是在3~8个机器周期
(前提:不考虑中断嵌套)

8051的中断响应函数与寄存器组

为了满足在C语言源程序中直接编写中断服务程序的要求,C51编译器对函数的定义进行了扩展,增加了一个关键字**interrupt** 。它是函数定义时的一个可选关键字,加上这个关键字即可将一个函数定义成中断服务函数。

中断响应函数的定义格式为:

返回值数据类型 函数名(形式参数表)[ interrupt n ]

**关键字interrupt后面的n是中断号 。编译器根据中断号计算中断号向量 ,具体的中断号n和中断向量取决于单片机芯片型号,8051单片机中断向量为8n+3 **。

中断号n 中断源 中断向量8n+3
0 外部中断0 0003H
1 定时器0 000BH
2 外部中断1 0013H
3 定时器1 001BH
4 串行口 0023H

完整的中断响应函数的定义格式为:

返回值数据类型 函数名(形式参数表)[ interrupt n ] [using n]

中断响应函数不需要返回值,因此返回值数据类型为void;

中断响应函数不能传递参数,因此形式参数表为空;

中断响应函数一般不需要书写return语句

中断响应函数一般使用第1~3组工作寄存器组,同一优先级的中断响应函数可以使用同一个工作寄存器组,不同优先级的中断响应函数最好使用不同的工作寄存器组

中断服务函数与寄存器的定义

void  INT0_ISR(void)     interrupt 0	{   }
void TIMER0_ISR(void) interrupt 1 { }
void INT1_ISR(void) interrupt 2 { }
void TIMER1_ISR(void) interrupt 3 { }
void UART_ISR(void) interrupt 4 { }

例:

void INT0_ISR () interrupt 0  using 1 {}

编程实例:

#include "reg51.h"
//C51 中断程序框架
/**********int0中断服务程序**********/
void INT0_ISR (void) interrupt 0 using 0
{ //中断服务程序
//……
}
/**********主函数*******************/
void main (void)
{ IT0=1;
EX0 = 1; EA = 1; // 打开中断源
while (1) ; //等待中断
}

中断资源的编程

  • 中断方式

使能中断,通过编写中断响应函数来完成对中断事件的处理。

中断标志的检查和中断响应函数的调用由硬件自动完成。

  • 查询方式

不使能中断,通过编程查询中断标志位的方式来完成对中断事件的处理。

中断标志的检查有用户编程实现,中断事件的处理代码可以不书写在中断响应函数中。

编程样例

如图按下S0,对D0取反:查询方式、中断方式

image-20210613160836556

查询方式

#include "reg51.h"
sbit S0=P3^2;
sbit D0=P0^0;
void main(void)
{
bit pre_S0=1;
while(1)
{
if(pre_S0==1&&S0==0)//S0按下
{
D0=~D0;
}
pre_S0=S0;
}
}

查询方式存在的问题:实时性

中断扩充1——定时器

  • 定时器中断作为外部中断使用

把8051的T0 、T1用作对外部脉冲计数方式。每当P3.4(T0)或P3.5(T1)引脚上发生负跳变时, T0、T1计数器加1。利用这个特性,可以把P3.4和P3.5引脚作为外部中断请求输入线,而定时器的溢出中断作为外部中断请求标志。

image-20210613161828627

  • 定时器中断作为外部中断使用(软件)
/*定时器T1对外部计数*/
/*TH1、TL1采用16进制赋值*/
void T1_ISR(void) interrupt 3

/*中断服务程序*/

void main(void)
{ TMOD=(TMOD&0x0f)|0x60;
ET1=1; EA=1; TR1=1;
TH1=0xFF;
TL1=0xFF;
while(1);

image-20210613161947775

中断扩充2——中断查询

  • 中断和查询结合的方式

image-20210613162040724

#include "reg51.h"
sbit INA=P1^0;
sbit INB=P1^1;
sbit INC=P1^2;
sbit IND=P1^3;
sbit OUTA=P2^0;
sbit OUTB=P2^1;
sbit OUTC=P2^2;
sbit OUTD=P2^3;

void main(void)
{
OUTA=1;OUTB=1;OUTC=1;OUTD=1;
IT0=1;
IT1=1;
EX0=1;
EX1=1;
EA=1;
while(1)
{
//wait;
}
}

void INT0_ISR(void) interrupt 0
{
EX1=1;
IE1=0;
OUTA=1;OUTB=1;OUTC=1;OUTD=1;
}

void INT1_ISR(void) interrupt 2
{
EX1=0;
if(INA==0) {OUTA=0;OUTB=1;OUTC=1;OUTD=1;}
else if(INB==0){OUTA=1;OUTB=0;OUTC=1;OUTD=1;}
else if(INC==0){OUTA=1;OUTB=1;OUTC=0;OUTD=1;}
else if(IND==0){OUTA=1;OUTB=1;OUTC=1;OUTD=0;}
}

中断扩充3——利用硬件扩充多个中断源

采用一个8/3优先编码器74LS148,把多个中断源信号作为一个中断效果很好。

I7-I0优先级逐步降低

GS为标志位:判断是否有有效输入

image-20210613162401987

  • 软件设计思路
#include <reg51.h>
unsigned char status;
bit flag;
void int1(void) interrupt 2 using 2
{
flag=1; /*设置标志*/
status=P1; /*存状态*/
 }

void main(void)
{
PX1=1; /*置INT1高优先级中断*/
EX1=1; EA=1/*INT1开中断,CPU开中断*/
while(1)
{ if(flag) /*有中断*/
{ switch(status) /*根据中断源分支*/
{
case 0: break; /*处理0*/
case 1: break; /*处理1*/
case 2: break;
case 3: break;
default:;
}
flag=0;
}
}
}