文章目录
前言
提示:本文主要用作在学习江科大自化协STM32入门教程后做的归纳总结笔记,旨在学习记录,如有侵权请联系作者
本文主要探讨STM32中断系统、NVIC以及EXTI外部中断相关概念。中断系统是管理和执行中断的逻辑结构,外部中断是众多能产生中断的外设之一,本章节就借助外部中断来学习一下中断系统。
一、中断系统
1.1 中断系统简介
所谓的中断就是在主程序运行过程中,出现了特定的中断触发条件(中断源),使得CPU暂停当前正在运行的程序,转而去处理中断程序,处理完成后又返回原来被暂停的位置继续运行。
中断有优先级之分,当有多个中断源同时申请中断时,CPU会根据中断源的轻重缓急进行裁决,优先响应更加紧急的中断源。中断还能嵌套,当一个中断程序正在运行时,又有新的更高优先级的中断源申请中断,CPU再次暂停当前中断程序,转而去处理新的中断程序,处理完成后依次进行返回。
1.2 中断的执行流程
正常情况下,程序就是在主程序中不断循环执行,当中断条件满足时,主程序就会暂停,然后自动跳转到中断程序里运行,中断程序执行完之后,再返回主程序执行。一般中断程序都是在一个子函数里,这个函数不需要我们调用,当中断来临时,由硬件自动调用这个函数,这就是在c语言中中断的执行流程。
1.3 STM32中断
在STM32中一共有68个可屏蔽的中断通道,包含EXTI、TIM、ADC、USART、SPI、I2C、RTC等多个外设。STM32使用NVIC统一管理中断,每个中断通道都拥有16个可编程的优先等级,可对优先级进行分组,进一步设置为抢占优先级和响应优先级。
下图为STM32的中断资源,上面灰色的是内核中断(我们一般不用,了解即可),下面不是灰色的部分就是STM32外设的中断了。
图中最右边是中断的地址,因为程序中的中断函数的地址是由编译器来分配的,是不固定的,但是我们的中断跳转由于硬件的限制只能跳到固定的地址执行程序,所以为了硬件能够跳转到一个不固定的中断函数里,这里就需要在内存中定义一个地址的列表。这个列表的地址是固定的,中断发生后,就跳到这个固定位置,然后在这个固定位置,由编译器,再加上一个跳转到中断函数的代码,这样中断跳转就可以跳转到任意位置了。这个中断地址的列表,就叫中断向量表,相当于中断跳转的一个跳板,不过我们用c编程是不需要管这个中断向量表的,因为编译器都帮我们做好了。
二、NVIC(Nested Vectored Interrupt Controller) 嵌套向量中断控制器
2.1 NVIC简介
在STM32中,NVIC(Nested Vectored Interrupt Controller,嵌套向量中断控制器)是用来统一分配中断优先级和管理中断的。NVIC是一个内核外设,是CPU的小助手。我们刚才看到了,STM32的中断非常多,如果把这些中断全都接到CPU上,那CPU还得引出很多线进行适配,设计上就很麻烦。并且如果很多中断同时申请,或者中断很多,产生了拥堵,CPU也会很难处理,毕竟CPU主要是用来运算的,那这样的话中断分配的任务就放到别的地方吧,所以NVIC就出现了。
2.2 NVIC基本结构
NVIC有很多输入口,你有多少个中断线路都可以接过来。比如这里可以接EXTI、TIM、ADC、USART等等。这里线上画了个斜杠,上面写了个n,这个意思是一个外设可能会同时占用多个中断通道,所以这里有n条线。然后NVIC只有一个输出口,NVIC根据每个中断的优先级分配中断的先后顺序,最后通过右边这一个输出口告诉CPU,你该处理哪个中断。
对于中断先后顺序分配的任务,CPU不需要知道。举个例子,比如这个CPU是一个医生,如果医院只有医生的话,当看病的人很多时,医生就得安排一下先看谁,后看谁。如果有紧急的病人,那还得让紧急的病人最先来,这个安排先后顺序的事情很繁琐,会影响医生看病的效率。所以医院就安排了一个叫号系统,来病人了统一取号,并且根据病人的等级,分配一个优先级,然后叫号系统看一下现在排队的病人,优先叫号紧急的病人,最后叫号系统给医生输出的就是一个一个排好队的病人,医生就可以专心看病了,这个叫号系统在STM32里就是NVIC。
2.3 NVIC优先级分组
为了处理不同形式的优先级,STM32中的NVIC可以对优先级进行分组,分为响应优先级和抢占优先级。那这两种形式的优先级有什么区别呢?我们还来看一下病人叫号这个例子。
对于紧急的病人,其实有两种形式的优先。一种是,上一个病人在看病,外面排队了很多病人,当上一个病人看完后,紧急的病人即使是后来的也会最先进去看病。这种相当于插队的优先级,就叫响应优先级。 响应优先级高的,可以插队提前看病。另一种是,如果这个病人更加紧急,并且此时已经有人在看病了,那他还可以不等上一个人看完病,直接冲到医生的屋里,让上一个病人先靠边站,先给他看病,等他看完了,然后上一个病人再继续,然后上一个病人结束了,叫号系统再看有没有人来,这种形式的优先级就是我们之前讲的中断嵌套了。这种决定是不是可以中断嵌套的优先级,就叫抢占优先级。 抢占优先级高的,可以进行中断嵌套。
那我们刚才说了,每个中断有16个优先级,为了把这个优先级再区分为抢占优先级和响应优先级,就需要对这16个优先级进行分组了。
NVIC的中断优先级由优先级寄存器的4位决定,这里4位二进制可表示0~15的数,对应16个优先级。这个优先级的数值越小,优先级越高,0就是最高优先级。然后呢,这4位可以进行切分,分为高n位的抢占优先级和低4-n位的响应优先级。
抢占优先级高的可以中断嵌套,响应优先级高的可以优先排队,抢占优先级和响应优先级均相同的按中断号排队,这个中断号就是中断向量表里的优先级那一列的数字。当抢占优先级和响应优先级均相同时,就按照这个这个数字进行排队,数字小的优先响应。所以STM32的中断不存在先来后到的排队方式,在任何时候都是优先级高的先响应。
最后再来看一下下面的这个表。
因为优先级总共是4位,所以就有(0,4)、(1,4)、(2,2)、(3,1)、(4,0)这五种分组方式。分组0就是0位的抢占等级,取值只能为0,4位的响应等级,取值可以是0 ~ 15。分组1就是1位的抢占等级,取值是0 ~ 1,3位的响应等级,取值可以是0 ~ 7。然后分组2、3、4都是按这个规律来分配的。这个分组方式在程序中是我们自己来选择的,选好分组方式之后,我们在配置优先级的时候就要注意抢占优先级和响应优先级的取值范围了,不要超出这个表里规定的取值范围。
了解完NVIC这个叫号系统和叫号的规则之后,我们就来看一下第一个病人—EXTI外部中断。
三、EXTI(Extern Interrupt)外部中断
3.1 EXTI简介
EXTI(Extern Interrupt)全称为外部中断,EXTI可以监测指定GPIO口的电平信号。当其指定的GPIO口产生电平变化时,EXTI将立即向NVIC发出中断申请,经过NVIC裁决后即可中断CPU主程序,使CPU执行EXTI对应的中断程序,这就是EXTI的基本功能。简单来说就是,引脚电平变化,发出申请中断。
3.1.1 支持的触发方式
EXTI支持引脚电平的变化类型为上升沿、下降沿、双边沿以及软件触发。
类型 | 描述 |
---|---|
上升沿 | 电平从低电平变到高电平的瞬间触发中断 |
下降沿 | 电平从高电平变到低电平的瞬间触发中断 |
双边沿 | 上升沿和下降沿都可以触发中断 |
软件触发 | 引脚啥事没有,程序里执行一句代码,就能触发中断 |
3.1.2 支持的GPIO口
然后再看一下外部中断支持的GPIO口。它支持所有的GPIO口, 也就是任意的GPIO口都可以当作外部中断的引脚。但相同的Pin不能同时触发中断。这个意思就是,比如PA0和PB0不能同时用,或者PA1、PB1、PC1这样的。端口GPIO_pin一样的只能选1个作为中断引脚。所以你如果有多个中断引脚,要选择不同Pin的引脚,比如PA6和PA7,PA9和PB15,PB0和PB1这样的都可以。
3.1.3 通道数
接着再看一下外部中断占用的通道。其中有16个GPIO_pin(对应GPIO_pin_0到GPIO_pin_15),外加PVD输出、RTC闹钟、USB唤醒以及以太网唤醒,这些加起来总共有20个中断线路。这里的16个GPIO_pin是外部中断的主要功能,后面跟着的四个东西其实是来“蹭网”的。为啥这些东西要来外部中断“蹭网”呢?因为这个外部中断有个功能,就是从低功耗模式的停止模式下唤醒STM32。对于PVD电源电压监测来说,当电源从电压过低恢复时,就需要PVD借助一下外部中断退出停止模式。对于RTC闹钟来说,有时候为了省电,RTC定一个闹钟之后,STM32会进入停止模式,等到闹钟响的时候再唤醒,这也需要借助外部中断。还有USB唤醒、以太网唤醒,也是类似的作用。当然我们本节主要是学习引脚的外部中断,这四个“蹭网”的知道一下就行了。
3.1.4 触发的响应方式
外部中断的触发响应方式可以是中断响应和事件响应。
中断响应就是申请中断,让CPU执行中断函数,而事件响应其实是STM32对外部中断增加的一种额外功能。当外部中断检测到引脚电平发生变化时,正常的流程是选择触发中断,但在STM32中,也可以选择触发一个事件。如果选择触发一个事件,那外部中断的信号就不会通向CPU,而是通向其他外设,用来触发其他外设的操作。比如触发ADC转换、触发DMA等。
所以总结一下就是,中断响应是正常的流程,引脚电平变化触发中断。事件响应不会触发中断,而是触发别的外设操作,属于外设之间的联合工作。
3.2 EXTI结构
3.2.1 EXTI基本结构
那接下来我们就来看一下外部中断的基本结构吧,下面这个图就是外部中断的整体结构图。
首先,最左边是GPIO口的外设,比如GPIOA、GPIOB、GPIOC等等。每个GPIO外设有16个引脚,所以进来16根线。那我们刚才说了,EXTI模块只有16个GPIO通道,但这里每个GPIO外设都有16个引脚,如果每个引脚占用一个通道,那EXTI的16个通道显然就不够用了。所以在这里会有一个AFIO中断引脚选择的电路模块。**这个AFIO就是一个数据选择器,它可以在这前面3个GPIO外设的16个引脚里选择其中一个连接到后面EXTI的通道里。**所以这前面说,相同的Pin不能同时触发中断,因为对于PA0、PB0、PC0这些,通过AFIO选择之后,只有其中一个能接到EXTI的通道0上。同理,PA1、PB1、PC1这些,也只能有一个,连接到通道1上。这就是所有GPIO口都能触发中断,但相同的Pin不能同时触发中断的原因。
然后通过AFIO选择之后的16个通道就接到了EXTI边沿检测及控制电路上了。同时,下边这四个外设(PVD、RTC、USB、ETH)也是并列接进来的。这些加起来,就组成了EXTI的20个输入信号,然后经过EXTI电路之后,分为了两种输出,其中上面的这些接到了NVIC,是用来触发中断的。
这里注意一下,本来20路输出应该有20路中断的输出,但是可能ST公司觉得这20个输出太多了,比较占用NVIC的通道资源,所以就把其中外部中断的9 ~ 5,和 15 ~ 10,给分到一个通道里。也就是说,外部中断的9 ~ 5会触发同一个中断函数,15 ~ 10也会触发同一个中断函数。在编程的时候,我们在这两个中断函数里,需要再根据标志位来区分到底是哪个中断进来的。
然后下面这里,有20条输出线路到了其他外设,这就是用来触发其他外设操作的,也就是我们刚才说的事件响应。
以上就是中断的整体流程了,然后我们再具体地看一下这里AFIO和EXTI的内部电路。先看一下AFIO复用IO口。
3.2.1 AFIO内部结构
下面这个图就是AFIO选择中断引脚的结构图,这个结构图看上去就比较简单了,这里就是一系列的数据选择器。
我们先来看一下第一个,输入时PA0、PB0、PC0等等,一直到PG0,尾号都是0。然后通过数据选择器,最终选择一个接到EXTI0上。上面写的是配置这个寄存器这些位,可以决定选择哪一输入。然后下面的EXTI1到EXTI15都是一样。
总结一下,数据选择器的作用就是,AFIO主要用于引脚复用功能的选择和重定义。在STM32中,AFIO主要完成两个任务,就是复用功能引脚重映射和中断引脚选择。
3.2.2 EXTI内部结构
下图是EXTI的内部框图,这里可以看到,EXTI的右边,就是20根输入线。然后输入线首先进入边沿检测电路,在上面的上升沿寄存器和下降沿寄存器可以选择是上升沿触发还是下降沿触发,或者两个都触发。接着触发信号就进入到这个或门的输入端了,在这里,硬件触发和软件中断寄存器的值就接到了这个或门上,也就是任意一个为1,或门就可以输出1。所以前面我们说支持的触发方式是上升沿、下降沿、双边沿和软件触发。
然后回到这里,触发信号通过这个或门之后就兵分两路,上一路是触发中断的,下一路是触发事件的。触发中断首先会置一个挂起寄存器,这相当于是一个中断标志位了,我们可以读取这个寄存器判断是哪个通道触发的中断。如果中断挂起寄存器置1,它就会继续向左走,和中断屏蔽寄存器共同进入一个与门,然后是至NVIC中断控制器。这里的与门实际上就是开关的作用,因为对于与门来说,1与上任意数x,等于这个任意数x。0与上任意数x,都等于0。这就相当于中断屏蔽寄存器给1,那另一个输入就是直接输出,也就是允许中断。中断屏蔽寄存器给0,那另一个输入无论是什么,输出都是0,相当于屏蔽了这个中断。这就是这个与门的作用,相当于一个开关控制。
接着看一下下一路事件的输出部分。首先也是一个事件屏蔽寄存器进行开关控制,最后通过一个脉冲发生器到其他外设,这个脉冲发生器就是给一个电平脉冲,用来触发其他外设的动作。
最后这个框图剩下的部分,这些画着一个斜杠写着20,表示就是,这是20根线,代表20个通道。上面这些就是外设接口和APB总线,我们可以通过总线访问这些寄存器。那以上这些就是EXTI的内部结构了。
常见逻辑符号:
另外,简单介绍一下几种常见的逻辑符号吧。
这种弯弯的符号是或门。它可以有多个输入,但只能有一个输出,执行的是或的逻辑,在输入端只要有一个是高电平1,那输出就是高电平1。只有全部输入低电平0,输出才为0。
然后还有这种点直边的符号是与门。它同样也可以有多个输入,但只能有一个输出,执行的是与的逻辑。在输入端,只要有一个是低电平0,输出就是0。只有全部输入为1,输出才为1。
另外还有一种三角号加个圈的是非门。它只有一个输入,一个输出,执行的是非得逻辑。输入1就输出0,输入0就输出1。
最后还有一种,就是前面说的数据选择器。它的符号是一个梯形,有多个输入,一个输出。在侧面有选择控制端,根据控制端的数据,从输入选择一个接到输出。这些就是常见的逻辑符号,了解一下。
3.3 EXTI特性和使用场景
对于外部中断来说,我们刚学习完它的原理和结构,那到底什么样的设备需要用到外部中断呢?使用外部中断有什么好处呢?在这里我大概总结了使用外部中断模块的特性。就是对于STM32来说,想要获取的信号是外部驱动的很快的突发信号。
比如旋转编码器的输出信号,我可能很久都不会拧动它,这时不需要STM32做任何事,但是我一拧动它,就会有很多脉冲波形需要STM32接收。这个信号是突发的,STM32不知道它什么时候会来,同时它是外部驱动的,STM32只能被动读取。最后,这个信号非常快,STM32稍微晚一点来读取,就会错过很多波形。所以对于这种情况,就可以考虑使用STM32的外部中断了。有脉冲过来,STM32立即进入中断函数处理,没有脉冲的时候,STM32就专心做其他事情。
另外还有,比如红外遥控接收头的输出,接收到遥控数据之后它会输出一段波形,这个波形转瞬即逝并且不会等你,所以就需要我们用外部中断来读取。
最后还有按键,虽然它的动作也是外部驱动的突发事件,但我并不推荐使用外部中断来读取按键,因为用外部中断不好处理按键抖动和松手检测的问题。对于按键来说,它的输出波形也不是转瞬即逝的,所以要求不高的话可以在主程序中循环读取。如果不想用主循环读取的话,可以考虑一下定时器中断读取的方式,这样既可以做到后台读取按键值不阻塞主程序,也可以很好地处理按键抖动和松手检测的问题。
总结
STM32的中断系统是一个高度可配置的、功能强大的系统,能够响应来自各种内部和外部源的中断请求。通过NVIC的管理,中断可以被有效地排序和响应,确保系统能够及时、有效地处理各种紧急事件。对于嵌入式系统开发者而言,理解和掌握STM32的中断系统是至关重要的。
标签:NVIC,优先级,触发,中断,STM32,EXTI From: https://blog.csdn.net/Mr_Jaychong/article/details/141056337