3、中断响应流程:中断请求、中断判优、中断响应、中断处理、中断返回的完整生命周期

各位工程师朋友,咱们今天聊聊中断的完整生命周期。说白了,就是CPU怎么知道外设有事找它,它怎么决定先处理谁,然后怎么去干活,干完活怎么回来继续原来的工作。这五个环节,一个都不能少。

我刚开始做数控系统那会儿,总觉得中断就是个“来了就处理”的事儿。后来有一次,机床在高速切削时突然丢步,查了三天才发现是中断响应时序出了问题。嗯,从那以后,我对这个流程就再也不敢马虎了。

3.1 中断请求——谁在敲门?

中断请求,就是外设告诉CPU:“我有急事,你来看看。” 这个信号可以是电平触发,也可以是边沿触发。

我个人习惯在CNC系统中用边沿触发,尤其是急停信号。为什么?因为电平触发容易受噪声干扰,万一信号抖动一下,CPU可能误判成多次中断。你想想看,机床正在切削,突然来个误中断,刀具一抬,工件就废了。

中断请求的两种形式:

  • 电平触发:信号保持高/低电平,直到CPU响应。适合慢速设备,比如按键。
  • 边沿触发:检测上升沿或下降沿,只触发一次。适合高速设备,比如编码器Z信号。

我在项目中遇到过一个问题:某款伺服驱动器的报警信号是电平触发,但它的电平保持时间只有几个微秒。CPU还没来得及响应,信号就消失了。后来我加了一个D触发器做展宽,才把问题解决。说白了,硬件设计时一定要看外设的数据手册,确认信号的最小脉宽。

3.2 中断判优——谁更急?

多个中断同时来了怎么办?CPU得有个优先级判断机制。这就是中断判优。

CNC系统里,中断优先级通常是这样的:

优先级 中断源 说明
最高 急停、超程 安全相关,必须立即响应
伺服报警、主轴报警 设备保护,需快速处理
位置反馈、编码器 实时控制,周期要求严格
通信、显示刷新 非实时任务,可延迟

我曾经犯过一个错误:把编码器中断优先级设得比伺服报警还高。结果伺服过流了,CPU还在处理编码器数据,等它反应过来,驱动器已经烧了。嗯,血的教训。优先级设计,一定要从系统安全角度出发。

判优方式有两种:

  • 固定优先级:硬件决定,简单可靠。适合中断源固定的系统。
  • 可编程优先级:软件可调,灵活但复杂。适合需要动态调整的场景。

我个人建议,CNC系统用固定优先级为主,安全类中断永远最高。别搞什么动态调整,万一调错了,机床撞了算谁的?

3.3 中断响应——CPU开始行动

中断判优结束后,CPU就开始响应了。这个过程是硬件自动完成的,不需要软件干预。

响应流程大致如下:

  1. CPU保存当前正在执行的指令地址(PC指针)到堆栈。
  2. CPU保存当前的状态寄存器(PSW)到堆栈。
  3. CPU根据中断向量表,找到对应的中断服务程序入口地址。
  4. CPU跳转到该地址,开始执行中断服务程序。

避坑指南:我曾经在ARM Cortex-M3上遇到过一个问题:中断响应后,堆栈指针没有正确对齐,导致压栈时数据错位。后来发现是编译器优化选项的问题。建议大家在中断服务程序入口处,手动检查堆栈对齐情况。

这里有个关键点:中断响应时间。从中断请求到CPU开始执行第一条中断指令,这个时间叫中断延迟。CNC系统对实时性要求高,中断延迟必须可控。我记得有一次,客户反映机床在高速加工时有周期性停顿,一查发现是中断延迟抖动太大,原因是某个外设的中断处理时间过长,阻塞了其他中断。

3.4 中断处理——干活!

中断服务程序开始执行了。这里要注意,中断处理要快!快!快!

我一般把中断处理分成两部分:

  • 上半部(Top Half):处理紧急事务,比如读取硬件状态、清除中断标志。这部分必须在中断上下文中完成,不能阻塞。
  • 下半部(Bottom Half):处理非紧急事务,比如数据解析、状态更新。这部分可以放到任务队列里,等主循环慢慢处理。

中断服务程序编写原则:

  • 尽量短小精悍,别在里面做复杂计算。
  • 别调用可能阻塞的函数,比如printf、malloc。
  • 别关中断太久,否则其他中断会丢失。
  • 记得清除中断标志,否则会反复触发。

我曾经见过一个同事,在中断服务程序里做了个浮点运算,结果CPU卡了200微秒。200微秒啊,对于1ms的伺服周期来说,直接导致位置环失控。嗯,从那以后,我规定中断服务程序里不准用浮点运算,所有计算都放到主循环里做。

3.5 中断返回——从哪里来,回哪里去

中断处理完了,CPU得回到原来的工作。这个过程叫中断返回。

返回流程:

  1. CPU从堆栈恢复之前保存的状态寄存器(PSW)。
  2. CPU从堆栈恢复之前保存的程序计数器(PC)。
  3. CPU继续执行被中断的指令。

看起来简单,但这里有个坑:如果中断服务程序修改了通用寄存器,返回前必须恢复原值。否则,主程序会莫名其妙地出错。

重要提醒:我曾经在调试一个CNC系统时,发现主轴转速偶尔会突变。查了三天,最后发现是中断服务程序里修改了R0寄存器,但返回前没有恢复。主程序里的转速计算正好用了R0,结果算出来的值就错了。从那以后,我写中断服务程序时,第一件事就是保存所有会用到的寄存器,返回前再恢复。

另外,中断返回指令也有讲究。有些CPU用RETI(中断返回),有些用RET。千万别搞混了。RETI会重新使能中断,而RET不会。如果你用RET代替RETI,中断就再也进不来了。

3.6 完整生命周期流程图

下面我用一张SVG图,把整个中断响应流程串起来。你一看就明白了。

中断响应完整生命周期 1. 中断请求 2. 中断判优 3. 中断响应 4. 中断处理 5. 中断返回 返回断点 关键说明: • 中断请求:外设发出信号,CPU检测到中断 • 中断判优:多个中断时,CPU选择优先级最高的处理 • 中断响应:CPU保存现场,跳转到中断服务程序 • 中断处理:执行中断服务程序,处理具体事务 • 中断返回:恢复现场,继续执行被中断的程序

这张图把五个环节串起来了。你注意看那个虚线箭头,表示中断返回时CPU要回到原来的断点。这个“从哪里来,回哪里去”的机制,是中断能够正常工作的基础。

3.7 实际项目中的注意事项

最后,我总结几个实际项目中容易踩的坑:

  • 中断嵌套:高优先级中断可以打断低优先级中断。但嵌套层数别太多,否则堆栈会溢出。我一般限制最多3层。
  • 中断丢失:如果CPU正在处理一个中断,另一个同优先级的中断来了,可能会丢失。解决办法是用中断排队机制,或者提高中断处理速度。
  • 临界区保护:中断服务程序和主程序共享的数据,一定要用关中断或信号量保护。否则会出现数据不一致。

个人经验:我在做五轴联动CNC系统时,把位置环中断的优先级设得最高,周期设为100微秒。但有一次发现,位置环偶尔会抖动。排查后发现是中断服务程序里访问了共享变量,而主程序也在同时修改这个变量。后来加了关中断保护,问题就解决了。嗯,共享数据保护,再怎么强调都不为过。

好了,中断响应流程就讲到这里。记住这五个环节,你的CNC系统中断处理就不会出大问题。


专注资料整理