stm32的中断资源非常多,只要是外设就有中断,设置起来也很复杂,除了必须要事先配置好NVIC外,用到哪个外设还要专门对该外设再做一次初始化配置。广播操式的配置代码在很多教程里都做了说明,大同小异,但同时也都在罗列代码时回避了(有意或无意的)中断源的一些关键性知识,本文旨在结合8051寄存器编程的先修课程知识解释stm32中罕有人涉及的关于中断向量入口的知识点,同时也设计了一个按键中断的实验,相信比同类大路货实验更能反映stm32中断的本质。
1.但凡是中断,必须要有入口
从这个意义上来说,8051和stm32是一样的。所以8051会有一张中断向量入口表,而stm32与所有中断相关的总统领起名叫NVIC(Nested Vectored Interrupt Controller),光是字面意思就足以解释其中断机制了。
我们自己编写的中断服务子程序就放在这个入口处,一旦硬件上触发了某个中断,PC就会临时打断其顺序执行的使命,转而载入该中断向量入口地址,从而实现中断程序的执行,中断入口和8051汇编伪指令的跳转标号异曲同工,作用近似,只是后者是在我们的计划之中的,而前者却是意料之外的。这正是中断和跳转的区别:跳转——我们知道会发生以及何时发生;中断——我们知道有可能发生以及不确定何时发生。
2.中断向量入口是否固定
8051中断源很少(8051什么都很少),只有6-7个,相邻向量入口地址相差8字节,一般来说,为了不影响到这些中断的使用,我们会让main的位置越过这片区域,所以经常会有ORG 30H的写法。可见,即便我们一个中断也用不上,也顶多浪费30H个字节的ROM空间,相较于4k Bytes的程序存储器空间,还承受得起,所以8051的中断向量入口是固定不变的设计还是合理的。但是stm32中断源非常多,一个项目中能用得上的中断数目了了,如果还按固定间隔排列好所有的中断向量入口,浪费就比较可观了,即便有几百k的Flash,但地主家也没有余粮,所以stm32的设计,严格的说是Cotex-M3的设计,就比较高杆,直到编译完成那一刻才最终确定中断向量入口位置,用到的中断和没用到的中断泾渭分明,截然分开,从而节省了大量资源。而且同时解决了8051中断子程序超过8 Bytes就必须用跳转的不便(其本质也还是一种浪费)。
3.中断向量入口(“中断请求话事人”)是在哪里定义的
在编写自己的中断函数库时,头文件中会先对中断相关参数进行自定义,其中用到的某IRQHandler,从标准库中是找不到定义的,需要打开启动文件(该文件用汇编语言编写)startup_stm32f10x_md.s才能找到,但要注意这只是默认分配的空间顺序,编译后会发生上文中所示的变化。
4.谁能中断谁
很多教程里对于外部中断的举例非常简略,用一个或多个按键作为外部中断触发信号,实现点灯功能,而按键之间并没有发生嵌套关系,因此对于优先级分组(Priority Group)、抢占优先级(Preemption Priority)、次优先级(Sub-Priority)等概念仅停留在拾人牙慧的层面,甚至存在从事过所谓项目开发后仍然理解错误的人且毁人不倦https://blog.csdn.net/dahailinan/article/details/80693781。需要再次强调的是,优先级分组仅能设置一次,决定中断之间谁可以嵌套谁的是(且仅是)抢占优先级的高低(数字越小级别越高)。
5.能够体现中断嵌套关系的按键中断实验
要对得起NVIC的’N’,我们至少需要两个按键,且二者的抢占优先级有高低之分。设计思路如下:
i. 在没有中断发生时,LED1正常闪烁,LED2常亮
ii. KEY1触发中断时,LED1被中断,LED2闪烁数次后常亮,LED1恢复正常闪烁
iii. KEY2触发中断时,LED1被中断,LED2熄灭较长一段时间后,LED1恢复正常闪烁
iV. KEY2触发中断后且中断程序运行过程中,KEY1又触发中断,LED1被中断,LED2先是熄灭然后闪烁,闪烁结束后接续熄灭,直到完成KEY2中断程序,LED1恢复正常闪烁
v. KEY2触发中断后且中断程序运行过程中,KEY1又触发中断,LED1被中断,LED2闪烁直到结束后又熄灭,LED1恢复正常闪烁