第六集:中断处理函数ISR
摘要:中断处理函数(ISR)应遵循"快进快出"原则。轻量级操作(如标志位设置、简单数据缓冲)可直接在ISR内完成,但需确保无阻塞、无资源竞争。复杂逻辑(如协议解析、耗时运算)应剥离到主程序,ISR仅作触发。回调函数机制可处理异步操作完成后的响应,需根据需求选择对应回调类型(如发送完成_TxCpltCallback或错误处理_ErrorCallback)。开发时应通过标志位同步I
内容与中断函数
一、可以直接写在中断函数内?
中断处理函数(ISR,Interrupt Service Routine)的核心要求是 “快进快出”(减少对主程序的阻塞)。当处理逻辑满足以下条件时,代码可以直接写在 ISR 内:
轻量级
-
定时器更新中断(基础定时)
-
RTC 闹钟中断
-
ADC 转换完成中断(单次采样)
-
外部唤醒中断(低功耗场景)
-
处理逻辑极简单,执行时间极短
- 仅包含少量操作(如设置标志位、读取 / 清除寄存器、简单数据缓冲),执行时间远小于系统允许的中断延迟(通常要求微秒级或毫秒级,具体取决于系统实时性要求)。
- 示例:
- 串口接收中断中,仅将接收寄存器的数据存入缓冲区,并更新缓冲区指针;
- 按键中断中,仅设置 “按键按下” 的全局标志位,不进行复杂的按键解析或业务逻辑。
-
无阻塞操作
- 不包含任何可能阻塞 CPU 的代码,如:
- 不调用延时函数(
delay()); - 不进行复杂运算(如循环迭代、浮点计算);
- 不访问慢速外设(如 I2C、SPI 设备的读写,可能等待应答);
- 不进行内存动态分配(
malloc())或释放(free())。
- 不调用延时函数(
- 不包含任何可能阻塞 CPU 的代码,如:
-
无跨中断优先级的资源竞争
- 若 ISR 中访问的全局变量 / 资源,不会被更高优先级的中断或主程序同时修改(或已通过原子操作 / 关中断保护),可直接处理。
二、不可以直接写在中断函数内?
当处理逻辑违反 “快进快出” 原则,或存在风险时,必须将核心逻辑剥离到主程序中,ISR 仅做 “触发” 或 “预处理”:
重量级
-
SPI/I2C 通信中断
-
DMA 传输完成中断
-
CAN 总线中断
-
PWM 捕获中断
-
USART中断
-
处理逻辑复杂,执行时间长
- 包含大量运算、条件判断、多步骤操作,执行时间可能超过系统允许的中断延迟,导致:
- 主程序长期被阻塞,响应变慢;
- 低优先级中断被长期屏蔽(若系统支持中断嵌套,高优先级中断可抢占,但仍可能影响时序)。
- 示例:
- 串口接收中断中,直接解析协议、处理业务逻辑(如解析 JSON 数据、控制多个外设);
- 定时器中断中,执行复杂的算法计算(如滤波、轨迹规划)。
- 包含大量运算、条件判断、多步骤操作,执行时间可能超过系统允许的中断延迟,导致:
-
存在阻塞或等待操作
- 任何可能导致 CPU “等待” 的操作都绝对禁止在 ISR 中出现,例如:
- 调用
printf()(需等待串口发送完成,可能阻塞); - 等待信号量、互斥锁(若资源未就绪,会陷入无限等待);
- 访问需要总线仲裁的外设(如 SD 卡读写,可能等待总线空闲)。
- 调用
- 任何可能导致 CPU “等待” 的操作都绝对禁止在 ISR 中出现,例如:
-
存在资源竞争风险
- 若 ISR 中修改的全局变量同时被主程序或其他中断访问,且未加保护,可能导致数据错乱(如缓冲区溢出、标志位覆盖)。此时应将处理逻辑移至主程序,通过标志位同步。
总结
优先选择,将核心逻辑剥离到主程序中,ISR 仅做 “触发” 或 “预处理”
如何找到对应的中断处理函数
将cubmx配置好之后,保存ctrl+s,在列表中打开相应文件,翻到最底下。

如果没有出现这个函数,就是NVIC的相关中断没有勾选开启
对于轻量级可以直接在此处编写代码
比如:外部中断
如何找到对应的回调函数
通常轻量级中断的处理逻辑简单,直接在中断函数内完成即可,较少需要依赖回调函数;
对于重量级需要回调函数
ctrl对这个函数进行溯源

找到相关的回调函数
回调函数(Callback Function)是一种通过参数传递给其他函数的函数,其核心作用是让被调用的函数在特定时机自动执行回调函数中的逻辑,实现 “事件触发后自动响应” 或 “异步操作完成后处理结果” 的机制。
“你告诉我一段代码,在特定时候我会帮你执行这段代码”

根据需求选择函数
-
需求 1:“发送完成后,做些事情”
想在发送完全结束时(全部字节发完)执行逻辑(如置标志位、启动下一次发送),选_TxCpltCallback。 -
需求 2:“接收完成后,处理收到的数据”
收到指定长度的数据后(比如收完一帧)要解析、处理,选_RxCpltCallback。 -
需求 3:“发送到一半时,提前处理”
想在发送到一半(比如要发 100 字节,发完 50 字节时)做些事(比如填放下半段数据到 DMA 缓冲区),选_TxHalfCpltCallback。 -
需求 4:“接收收到一半时,提前处理”
收到一半长度(比如要收 100 字节,收到 50 字节时)就想处理(比如提前判断数据是否符合协议头),选_RxHalfCpltCallback。 -
需求 5:“UART 出现错误(溢出、校验错等)时,处理异常”
想在 UART 发生错误(比如接收溢出ORE、奇偶校验错PE等)时,记录日志、复位串口,选_ErrorCallback
选择所需要的函数,将弱定义
专门开一个文件对此类函数进行定义或者直接写入main.c中
更多推荐



所有评论(0)