中断系统 INT
一、学习目标
- 理解中断的概念,掌握中断的分类和优先级。
- 理解中断的响应机制和处理方法。
二、学习内容
(一)中断的概念
中断系统是为使 CPU 具有对外界紧急事件的实时处理能力而设置的。
当中央处理机 CPU 正在处理某件事情的时候,外界发生了紧急事件请求,要求 CPU 暂停当前的工作,转而去处理这个紧急事件。处理完以后,再回到原来被中断的地方,继续原来的工作,这样的过程称为“中断”。
实现这种功能的部件称为“中断系统”,向 CPU 发出中断请求的请求源称为“中断源”。
微型机的中断系统一般允许多个中断源。当几个中断源同时向 CPU 请求中断、要求为它服务时,就存在一个问题:CPU 优先响应哪一个中断源?
通常根据中断源的重要程度和紧急程度排队,优先处理最紧急事件的中断请求源,即规定每一个中断源有一个优先级别。CPU 总是先响应优先级别最高的中断请求。
当 CPU 正在处理一个中断源请求(执行相应的中断服务程序)的时候,如果又发生了另外一个优先级比它还高的中断源请求,且 CPU 能够:
- 暂停当前正在执行的中断服务程序,
- 转去处理优先级更高的中断请求,
- 处理完以后再回到原来较低优先级的中断服务程序继续执行,
这样的过程称为“中断嵌套”。具有中断嵌套功能的中断系统称为多级中断系统,没有中断嵌套功能的称为单级中断系统。
用户可以通过总中断允许位 EA(IE.7)或相应中断的允许位来屏蔽相应的中断请求,也可以通过打开相应的中断允许位,使 CPU 响应对应的中断请求。
每一个中断源都可以用软件独立控制为“开中断”或“关中断”状态。部分中断的优先级别也可以用软件设置。
规则总结:
- 高优先级的中断请求可以打断低优先级的中断。
- 低优先级的中断请求不能打断高优先级的中断。
- 当两个相同优先级的中断同时产生时,由查询次序决定系统先响应哪个中断。
(此处原文包含中断系统结构相关示意图,可在富文本中插入示意图。)
(二)中断源
能向 CPU 提出中断请求的信号源称为“中断源”。
STC8H 中的中断源种类较多(如外部中断、定时器中断、串口中断等),具体可以参考芯片手册中的中断源表格和功能说明,在富文本中可插入该表格或图片作为辅助理解。
(三)中断寄存器
通过 STC8H 的用户手册可以查询所有与中断相关的寄存器,以及对应的中断请求位信息。
例如:中断允许寄存器 IE、中断优先级寄存器 IP 以及扩展中断控制寄存器等。
相关资料可参考:
STC8H 数据手册(PDF):
http://www.stcmcudata.com/STC8F-DATASHEET/STC8H.pdf
(四)中断函数
在 C 语言中,可以通过关键字 interrupt 定义中断函数。
示例:
void UART1_int (void) interrupt 0
{
}
说明:
UART1_int 是中断函数的名称,可以根据需要自行命名。
interrupt 关键字用于声明当前函数为中断函数。
0 是中断号(中断入口向量编号),需要根据实际业务、查阅用户手册后确定。
中断函数可以理解为“回调函数”:
- 函数定义好之后,何时被调用不是由我们在主程序中直接调用决定的,而是由硬件事件触发、由系统自动调用。
- 我们只需要关心“什么事件会触发这个中断函数”,并在中断函数中编写需要执行的业务逻辑。
(五)验证 UART 串口的中断函数
示例需求:
接收数据时点亮 LED,发送数据时熄灭 LED。
相关寄存器与位定义:
sfr P5M1 = 0xC9;
sfr P5M0 = 0xCA;
sfr P5 = 0xC8;
sbit P53 = P5^3;
sfr T2L = 0xD7;
sfr T2H = 0xD6;
sfr AUXR = 0x8E;
sfr IE = 0xA8;
sbit EA = IE^7;
sbit ES = IE^4;
sfr SCON = 0x98;
sfr SBUF = 0x99;
sbit RI = SCON^0;
sbit TI = SCON^1;
UART 中断服务函数:
void uart_hello(void) interrupt 4 {
if (RI) {
// 如果接收标志位 RI 触发了中断,打开灯
RI = 0;
P53 = 1; // 开
}
if (TI) {
// 如果发送标志位 TI 触发了中断,关掉灯
TI = 0;
P53 = 0; // 关
}
}
简单延时函数(约 1000 ms,@11.0592MHz):
void Delay1000ms() //@11.0592MHz
{
unsigned char i, j, k;
i = 57;
j = 27;
k = 112;
do
{
do
{
while (--k);
} while (--j);
} while (--i);
}
主函数示例:
int main() {
// P5.3 推挽输出,用作 LED 指示灯
P5M1 &= ~0x08;
P5M0 |= 0x08;
// 串口 1 配置
SCON = 0x50;
// 波特率发生器配置:使用定时器 2
// 65536 - 11059200 / 115200 / 4 = 0xFFE8
T2L = 0xE8;
T2H = 0xFF;
AUXR = 0x15; // 启动定时器 2,选择波特率时钟等
// 开总中断与串口中断
EA = 1;
ES = 1;
P53 = 0; // 初始灯灭
while (1) {
// 休眠 1000 ms
Delay1000ms();
// 发送一个数据 0x11
SBUF = 0x11;
// 将 TI 位置 1(实际上只要给 SBUF 赋值,硬件会自动置位 TI)
TI = 1;
}
}
本例中完成的内容包括:
- 配置 UART 初始化(包括波特率定时发生器)。
- 查询并使用几个关键寄存器地址:如 SBUF、IE 等。
- 在中断服务函数中根据接收/发送标志位控制 LED 的亮灭,用于直观验证中断触发情况。