中断服务函数简介

在生活中,我们做一件事时常常被打断,然后自动去处理更紧急的事情。那么在计算机又是如何识别和处理这些紧急事件呢?本文将主要介绍什么是中断,中断服务函数又是什么,遇到中断了硬件和软件是怎么协作的呢?。

一、定义

1、定义

中断(Interrupt)是计算机体系结构中一种硬件驱动的控制转移机制。

当处理器正在执行某条指令流时,外部或内部硬件事件(中断源)向处理器发送请求信号(即:不是CPU主动轮询去查事件有没发生,是硬件主动通知CPU) ,处理器在当前指令执行完毕后,暂停原有指令流,保存执行现场,转去执行预先指定的中断处理程序;处理完成后恢复现场,回到被暂停的指令流继续执行。

2、核心名词

中断源:发出信号的地方(外部引脚、定时器、串口、ADC等)

中断服务函数(ISR):中断来了之后,要跑的那段专门处理代码。

中断标志位:硬件置1,告诉CPU:有中断来了,处理完一般软件/硬件清零。

中断优先级:多个中断同时来,先处理优先级高的;高优先级可以抢占低优先级(中断嵌套)

开/关中断(总中断开关):全局开关,关掉之后所有中断都不响应。

二、中断的作用

相对轮询,中断可以:

及时响应外部事件 :按键触发、外部传感器信号、脉冲输入,不用一直循环检测

解放CPU :没有事件的时候,CPU安心跑主业务,有事才临时切过去处理

精准定时 :定时器中断,用来做固定周期任务(1ms定时、PWM、采样)

通信收发 :串口、I2C、SPI收到数据、发完一帧触发中断,避免轮询卡死

故障紧急处理:硬件错误、电源异常、看门狗等紧急告警。

三、普通函数和中断服务函数ISR区别

有人会认为"ISR不就是一个特殊的函数吗?",虽然语法上看起来像C函数,但是执行模型和调度者完全不一样 。

普通函数是软件调度 的,编译器自动根据函数情况,按需保存用到寄存器,C函数可以传参数,也可以有返回值

中断服务函数是硬件事件驱动的,中断突如其来,CPU不知道当前主程序正在用哪些寄存器。Cortex-M内核硬件会自动压入一部分寄存器,剩下的需要程序员、编译器手动保存(有些编译器__interrupt关键字自动处理)。ISR不是普通return,用专门的中断返回指令(Cortex-M是BX LR,由编译器自动生成),回到被打断的断点,而不是某个函数的调用点。

对比项 普通函数 中断服务函数
触发方式 代码主动调用,顺序可控制 硬件中断自动触发,触发时机不可预知
参数、返回值 可以有参数、return返回 无参数无返回值
是否抢占 不能,顺序执行 高优先级可抢占主程序或低优先级中断(由中断优先级控制)
调用位置 代码可以随便写调用 禁止手动调用
执行时长 无强制限制 必须尽量短,禁止阻塞
返回 return 回到调用行 中断专用返回指令,回到被打断断点
注册 无需注册 需要放在中断向量表

四、中断服务函数(ISR)底层实现

底层本质:ISR不是CPU自带的一段特殊代码,而是你写好、放在内存里,在中断向量表登记入口地址;当中断请求到来时,硬件自动完成一系列动作,最终跳转到这个入口地址执行你的代码

整个流程分为6个阶段(以Cortex-M为例子):

前提:已配置好外设、打开外设中断、打开NVIC、打开全局中断

阶段1:中断源发起中断请求(硬件)

外设检测到事件,把中断标志位(IF)置1

如果外设的中断使能位打开,就向外设中断控制器(NVIC)发出中断请求信号IRQ

阶段2:处理器判断是否响应中断(在一条指令执行完之后才响应)

CPU有一条硬件规则:不会打断一条正在执行的指令,必须等当前指令执行结束,才检查是否有中断请求。

判断:总中断开关是否开启;这个中断的优先级,是否高于当前正在执行上下文的优先级(这一步硬件自动做,软件代码不参与)

阶段3:硬件自动保存上下文(自动压栈)【Cortex-M特色】

Cortex-M内核硬件自动把一部分寄存器压入当前栈(主栈MSP、进程线PSP)--这是硬件入栈,不需要软件写汇编push

剩下在ISR里用到的其他寄存器,由编译器自动生成PUSH汇编保存(编译器识别到是中断函数,自动补)

同时硬件更新LR特殊值(EXC_RETURN)

51单片机没有硬件自动压栈,全部靠软件在ISR开头手动PUSH、结尾POP

阶段4:查表,跳转到中断服务函数入口(核心:中断向量表)

处理器去访问中断向量表(Vector Table),CPU根据本次中断的中断号,索引向量表,拿到ISR的起始地址,修改PC寄存器,从而开始执行中断服务函数。

向量表本质就是一块连续的内存数组,里面存的全是地址

阶段5:执行中断服务函数(你写的C代码,编译成汇编)

c 复制代码
void EXTIO_ISRHandler(void)
{
	if(EXTI_GetITStatus(EXTI_Line0)!=RESET)
	{
		//业务:读寄存器,置标志
		EXTI_ClearITPendingBit(EXTI_Line0);//软件清除中断标志(非常关键哦)
	}
}

这里有两种标志:

硬件自动清零:部分外设、读寄存器自动清标志位

软件手动清零:EXTI、很多定时器,必须代码写寄存器清除挂起位,不清会一进一出反复触发中断(中断雪崩)

在Keil里用__irq/GCC用__attribute__((interrupt))标记,告诉编译器:a:这个函数不能用普通函数返回;b:自动保存用到的寄存器;c:结尾生成中断返回指令。

阶段6:中断返回、恢复上下文

ISR末尾,编译器生成BX LR 指令

CPU识别到这是中断返回,根据EXC_RETURN的值:

a从栈里硬件自动弹出之前保存的寄存器

bPC恢复成被打断时原来的地址;

c:回到之前被暂停的代码继续运行

d:退出中断上下文,回到线程上下文。

五、说明

1、国内有些单片机教材,习惯把异常也称为中断。实际两者是差别的:

中断(Interrupt) :事件和CPU指令流不同步,不知道什么时候来(eg:外部引脚、串口接收、定时器溢出),所以是异步的

异常(Exception) :由当前正在执行的指令本身引发,和指令同步(访问非法地址、未定义指令),所以是同步的

2、中断服务函数一定要短,快进快出

中断不要写:delay、printf、长循环、复杂运算

正确做法:读硬件寄存器,只标记一个标志位/发事件信号;复杂逻辑放到主循环或者RTOS任务里去执行。

RTOS中,ISR里不能直接嗲用会阻塞的API(eg:osSemaphoreWait()),只能用ISR专用版本

3、千万不要手动ISR()

手动调用会破坏中断上下文,引发异常或死机

4、ISR不是硬件写的,是程序员写的软件代码

硬件:进入ISR、保存现场、查表跳转、恢复现场这一套流程,是处理器硬件电路和内核逻辑自动完成的。

软件只负责配置中断、写ISR业务、清中断标志。

相关推荐
Risehuxyc21 分钟前
STM32程序逻辑---入口函数逻辑和NVIC嵌套向量中断控制器初始化
stm32·单片机·嵌入式硬件
【 STM32开发 】34 分钟前
CubeMX+STM32】SD卡U盘实现__USB+FATFS (F103 篇)
stm32·单片机·嵌入式硬件
无敌最俊朗-15 小时前
【电感专题2:电感的感抗、电路的阻抗、电流的滞后】
单片机·嵌入式硬件·元器件·电感
wuyk55519 小时前
嵌入式故障诊断-Bug002-局部大数组压栈高温必死机
stm32·单片机·嵌入式硬件·mcu·物联网·51单片机·嵌入式实时数据库
Dev_XH1 天前
【成品设计】基于沁恒单片机的电动汽车充电站智慧调度系统
stm32·单片机·嵌入式硬件·物联网
shimly1234561 天前
(done) 嵌入式硬件电路图 (5) 重要的元器件特性之二极管三极管
嵌入式硬件
minglie11 天前
esp32c3+atshell测试ov7670
单片机·嵌入式硬件
不脱发的程序猿1 天前
STM32和VS1053制作电子琴
stm32·单片机·嵌入式硬件·midi·vs1053
shimly1234562 天前
(done) 嵌入式硬件电路图 (2) 熟悉常用元器件
嵌入式硬件