十三、中断原理介绍
1. 中断基础知识
1.1 什么是中断
首先说一下中断是什么,大概就是说,单片机只有一个核,就是只有一个大脑,他无法一核二用地做事,但有时候迫不得已需要去响应一些紧急的命令,就好比你打游戏开团了,你妈喊你去吃饭,不出意外的话吃饭就会触发你的“中断”功能。放在单片机上,进行中断操作需要以下几个条件:拥有中断源、中断控制器正常工作、触发中断、保护现场、响应中断、恢复现场。灵活的使用系统中断可以大大提高单片机对随机事件的实时处理能力,进而提高单片机的工作效率。
看这些术语可能会比较抽象,下面就具体解释一下。
1.2 中断源
中断源,单片机上会有很多的中断源,也就是有很多办法、或者说“渠道”去触发中断,中断可以来自某个IO引脚,也可以来自某个高级外设,这些能够发出中断请求的硬件设备就是中断源。
1.3 中断控制器
中断控制器,这个东西是一个物理存在于单片机内核里面的一块数字电路,这一块电路的功能就是用来管理中断的。对于一些老旧型号的单片机,比如C51单片机,他内部也有这个东西,这个控制器只扮演了“总闸”这样的角色。再看CW32这种32位单片机,使用cortex-M0+内核,拥有可编程的中断控制器,单片机上会有很多个中断源,但这是内核可以使用和管理的部分,芯片制造厂使用这一款内核制造单片机,并不会用到所有的中断资源,不只是搭载的功能有限,还受限于封装,很多中断资源会被闲置(即使内核可以管理一万个中断,用它制造的芯片也不一定就必须有一万个中断源)。但是只要使用芯片的中断,都必须正确配置内核里面的中断控制器,否则中断是无法工作的,因为不论单片机外设设计的如何天花乱坠,外设只负责触发中断,而响应中断的一定是内核。
1.4 中断的触发
中断的触发,前面提到了中断源,一个指定的中断只能由特定的、与其绑定的中断源触发,一个中断可能绑定多个中断源,但是只会有一个与中断绑定的中断服务函数,至于什么是中断服务函数,后文会解释。那这个时候肯定会有长得漂亮又聪明的读者问了“那单片机如何在一个中断里面区分不同的中断源呢?”,单片机对不同的中断源,都设计了中断标志位,假设有ABC三个中断源,那他们就对应了3个标志位(3比特位),没触发中断的时候,ABC的中断标志位就是默认值0,如果触发中断,电路硬件会对其对应的标志比特位进行置位操作,也叫置1操作,该比特位会变成1。这个置位行为会直接反馈到内核的中断控制器,随后内核会对中断信号进行响应。
假设ABC三个中断源都绑定了同一个中断,他们共用一个中断服务函数,A、B、C的中断功能可以单独配置,并且拥有单独的标志位,当A触发中断时,A的中断标志位变成1,单片机会进入中断,但是单片机此时还无法区分到底是A、B、C哪一个中断源触发的中断,所以需要进行比特位的比较,当仅A触发中断时,ABC的二进制值是“100”,在判定成功后即可认为是A触发的中断。
1.5 保护现场
保护现场,看名字似乎和编程关系不大,这个名词在教科书上的中断章节会高频出现。由于我们无法预测中断会在什么时候到来,CPU也不会一直傻傻地等中断到来,所以不需要响应中断的时候,CPU还是照常工作的。想象现在CPU正在执行一个函数function(),倘若函数还未执行完成,中断被触发,CPU应该怎么做?是放下function函数不管不顾直接去响应,抑或是先做点什么?显而易见,后者更好更合理,需要做的,正是保护现场,函数执行到哪一步,CPU就会把执行到这一步的CPU数据(不只是我们要看的数据,还包括了程序执行的情况)存放到堆栈中,在中断响应完成之前,这些数据都会被封存,以避免响应完成后数据的丢失。
1.6 响应中断和中断服务函数
响应中断,这个是大部分人最关心的部分,因为这个部分直接涉及到中断服务函数的编写。在一切准备就绪后,CPU会放弃下一条需要执行的语句并直接进入中断服务函数,这里需要理解“中断服务函数”它仍然是个函数,初学者可能会认为,C语言的函数需要调用才会被执行,这里没被调用却被执行了,那肯定不是函数。实际上看过单片机原理或者了解过计算机原理的小伙伴会告诉你,CPU内部会有一个程序指针,程序指针会按照代码编译之后的逻辑去依次指向需要被执行的函数(函数作为代码的一部分,在存储器中有自己的函数地址),单片机进入中断服务函数的原理就是直接设置这个指针指向中断服务函数,之后CPU就能执行中断函数里面的代码来响应中断了。
中断服务函数可以写在工程的任意位置,只要满足条件,单片机就会自动跳转并执行该函数,一般情况下会把单片机外设的中断都集中在一个.c文件中,这个文件会叫“xxx_it.c”或“xxx_interrupt.c”,其中xxx是单片机的型号。如果你不喜欢在这个集中的文件中翻找中断服务函数,也可以不使用这个文件,只需要使用中断向量表中的终端名创造一个不需要在头文件中声明的空返回值空形参函数即可,如:void xxxxx_handler(void);。
1.7 恢复现场
恢复现场,对应于保护现场,CPU必须在响应中断之后回到之前被中断打断的语句那里继续执行,取出原路堆栈中的数据就完成了恢复。
1.8 中断优先级
每一个中断都有4位可配置的优先级位,可以通过分组设置抢占优先级和响应优先级的位数。
所有可编程的中断都需要指定抢占优先级和响应优先级,抢占优先级决定是否可以产生中断嵌套,响应优先级决定中断响应顺序,**若两种优先级一样则看中断在中断向量表中的位置,位置越靠前越先响应。抢占优先级高(值小)的中断可以中断抢占优先级低(值大)的中断处理函数(级别为0的优先级高于级别为1的优先级)。**当两个中断的抢占优先级相同时,即这两个中断没有嵌套关系,当一个中断到来后,若此时CPU正在处理另一个中断,则后到来的中断就要等前一个中断处理函数处理完毕后才能被处理,当两个中断同时到达,则中断控制器会根据它们的响应优先级决定先处理哪个。
通常中断优先级分组只设置一次,它针对的是系统中所有的中断。后续设置某个中断的中断优先级时,只需要设置在这个分组内的抢占优先级和响应优先级。
1.9 中断的工作流程
在打开并配置好对应的中断功能之后,中断会在中断源请求之后被触发,具体流程如下:
中断源满足条件发出中断请求--->单片机硬件将中断标志位置位--->内核根据标志位和中断优先级响应中断--->程序的执行被打断--->程序跳转到中断服务函数并执行--->中断服务函数执行完毕--->跳出中断服务函数并继续执行因中断请求被打断的程序。
2. 外部中断
外部中断,顾名思义,中断的实际触发由单片机外部电路实现,对于一个IO而言,他的状态只会有高电平和低电平两种状态,外部中断就是用硬件去监测这种状态变化(功能与扫描按键类似但由硬件完成),当IO电平发生某种指定变化时,触发IO的中断请求,随后CPU响应中断。
2.1 中断触发源
每个 GPIO 在设置为数字输入模式时,可作为外部中断信号源,产生中断的信号源可以设置为高电平、低电平、上升沿、下降沿 4 种。中断触发方式可组合使用,但共用同一个中断标志位。
总的来说想要用外部中断实现功能,一定要根据实现需求来选择触发方式,适合的才是最好的。