目录

STM32的中断

NVIC的基本结构

中断的优先级

优先级分组

EXTI(Extern Interrupt)外部中断

支持的触发方式

支持的GPIO口

外部中断占用的通道

外部中断的触发响应方式

外部中断的基本结构

GPIO口的外设

AFIO中断引脚选择

EXTI边沿检测及控制

NVIC选择通道分配中断优先级

AFIO和EXTI的内部电路

AFIO复用lO口

EXTI的内部框图

配合外部中断使用的硬件模块

旋转编码器

查看手册建议


声明:本专栏是本人跟着B站江科大的视频的学习过程中记录下来的笔记,我之所以记录下来是为了方便自己日后复习。如果你也是跟着江科大的视频学习的,可以配套本专栏食用,如有问题可以QQ交流群:963138186

本节要讲的是STM32的中断系统和外部中断。

中断系统是管理和执行中断的逻辑结构外部中断是众多能产生中断的外设之一。

所以本节我们就借助外部中断来学习一下中断系统,在以后学其他外设的时候也是会经常和中断打交道的。

对于中断、中断系统、中断优先级以及中段嵌套的概念,我在51单片机专栏有详细写过,没有基础的学习者可以先去看一下,这里不再赘述。

单片机学习笔记---中断系统(含外部中断)_ex1和ex0随便用一个即可嘛-CSDN博客

有51单片机基础的学习者直接来看STM32的中断。

STM32的中断

68个可屏蔽中断通道(也可以说是中断源),包EXTI外部中断、TIM定时器、ADC模数转换器、USART串口、SPI通信、I2C通信、RTC实时时钟等多个外设通过这一句,我们知道STM32的中断是非常多的,几乎所有的模块都能申请中断。

注:这是F1系列最多的中断数量,对于一个具体的型号,可能没有这么多中断,所以这个数量看看就行。

使用NVIC统一管理中断,每个中断通道都拥有16个可编程的优先等级,可对优先级进行分组,进一步设置抢占优先级和响应优先级

这个NVIC就是STM32中用来管理中断分配优先级的。NVIC的中断优先级总共有16个等级,还可以设置抢占优先级和响应优先级,这个是非常灵活的。

下图就是STM32里的中断资源

上面这些灰色的是内核的中断:

比如第一个复位中断,当产生复位事件时,程序就会自动执行复位中断函数,也就是我们复位后程序开始执行的位置;

然后NMI不可屏蔽中断,硬件失效、存储管理、总线错误、错误应用等等,这些都是内核里面的,一般这些中断都比较高深,我们看上去也挺难理解的,但是这些中断我们一般用不到,所以了解一下即可。

然后下面这些不是灰色的部分,就是STM32外设的中断

第一个窗口看门狗,这个是用来监测程序运行状态的中断,比如你程序卡死了没有及时喂狗,窗口看门狗就会申请中断,让你的程序跳到窗口看门狗的中断程序里,这时你在中断程序里就可以进行一些错误检查,看看出现什么问题了。

然后PVD电源电压监测。如果你供电电压不足,PVD电路就会申请中断。在中断里你就知道现在供电不足,是不是电池没电了,赶紧保存一下重要数据。

接着下面这些也都是类似的功能,

外设电路检测到有什么异常或者事件,需要提示一下CPU的时候,它就可以申请中断,让程序跳到对应的中断函数里运行一次,用来处理这个异常或事件。

EXTI0到EXTI4,还有下面的EXTI9_5和EXTI15-10,就是我们本节要学的外部中断对应的中断资源。

然后表的右边这里还有个中断的地址,

是因为我们程序中的中断函数的地址是由编译器来分配的是不固定的,但是我们的中断跳转由于硬件的限制只能跳到固定的地址执行程序。所以为了能让硬件跳转到一个不固定的中断函数里,这里就需要在内存中定义一个地址的列表。这个列表地址是固定的,中断发生后就跳到这个固定位置。然后在这个固定位置,由编译器,再加上一条跳转到中断函数的代码,这样中断跳转就可以跳到任意位置了。

这个中断地址的列表就叫中断向量表相当于中断跳转的一个跳板。不过我们用C语言编程的话是不需要管这个中断向量表的。因为编译器都帮我们做好了。

NVIC的基本结构

然后接下来我们来看一下NVIC的基本结构。

NVIC的名字叫做嵌套中断向量控制器STM32它是用来统一分配中断优先级和管理中断的。

NVIC是一个内核外设CPU的小助手我们刚才看到了STM32的中断非常多,如果把这些中断全都接到CPU上,CPU还得引出很多线进行适配,设计上就很麻烦。并且如果很多中断同时申请或者中断很多产生了拥堵,CPU也会很难处理,毕竟CPU主要是用来运算的,所以中断分配的任务就放到别的地方,所以NVIC就出现。

NVIC有很多输入口,你有多少个中断线路都可以接过来,比如上面的基本结构图中接到EXTI、TIM、ADC、USART等等。

这里线上画了个斜杠,上面写个n,这个意思是一个外设可能会同时占用多个中断通道,所以这里有n条线。

中断的优先级

NVIC只有一个输出口,NVIC根据每个中断的优先级分配中断的先后顺序,之后通过右边这一个输出口告诉CPU该处理哪个中断。对于中断先后顺序分配的任务,CPU不需要知道。

举个例子,假设这个CPU是一个医生,如果医院只有医生的话,当看病的人很多时,医生就得安排一下先看谁后看谁,如果有紧急的病人,还得让紧急的病人最先来这个安排,先后次序的任务很繁琐,会影响医生看病的效率,所以医院就安排了一个叫号系统,让病人统一取号,并且根据病人的等级分配一个优先级。然后叫号系统看一下现在在排队的病人优先叫号紧急的病人。最后叫号系统给医生输出的就是一个一个排好队的病人。医生就可以专心看病了,这个叫号系统在STM32里就是NVIC。

然后我们看一下中断的分组,为了处理不同形式的优先级STM32的NVIC,可以对优先级进行分组。

每个中断有16个优先级,为了把这个优先级再区分为抢占优先级和响应优先级,就需要对这16个优先级进行分组了。

NVIC的中断优先级由优先级寄存器的4位(四位二进制可以表示0~15的数对应16个优先级,这个优先级的数是值越小优先级越高0就是最高优先级决定,这4位可以进行切分,分为高n位的抢占优先级和低4-n位的响应优先级

这两种形式的优先级有什么区别?我们再来看一下病人叫号的这个例子,对于紧急的病人,其实有两种形式的优先,一种是上一个病人在看病,外面排队了很多病人,当上一个病人看完后紧急的病人即使是后来的也会最先进去看病。这种相当于插队的优先级就叫响应优先级响应优先级高的,可以插队提前看病。

另外,如果这个病人更加紧急,并且此时已经有人在看病了,他还可以不等上一个人看完,直接冲到医生的屋里,让上一个病人先靠边站先给他看病。等他看完了,上一个病人再继续。然后上一个病人结束了,叫号系统再看看有没有人来,这种形式的优先级,就是我们之前讲的中断嵌套这种决定是不是可以中断嵌套的优先级就叫抢占优先级。

抢占优先级高的可以中断嵌套,响应优先级高的可以优先排队

当两个中断同时响应时,抢占优先级谁高谁先中断;
当抢占优先级相同时,谁的响应优先级高谁先响应;
当抢占优先级相同时,低响应优先级已经进入中断函数,高响应优先级不可打断低优先级)

抢占优先级和响应优先级均相同的,按中断号排队。当抢占优先级和响应优先级均相同时,就按照这里的这个数字来排队,数值小的优先响应。这个中断号就是这里这个表里的这栏数字。

所以STM32的中断不存在先来后到的排队方式,在任何时候都是优先级高的先响应。

优先级分组

然后看一下下面的这个表,

因为优先级总共是四位,所以就有五种分组方式。

分组0就是0位的抢占等级,取值只能为0。

4位的响应等级取值可以是0~15。

分组1是1位的抢战等级,取值是0~1;

3位的响应等级取值是0~7,然后分组2、3、4都是按照这个规律来分配的。

这个分组方式在程序中是我们自己来选择的,选好分组方式之后,我们在配置优先级的时候,就要注意抢占优先级和响应优先级的取值范围了,不要超出这个表里规定的取值范围。

不明白没关系,下一篇代码演示的时候就明白了是怎么回事了。

了解完NVIC这个叫号系统和叫号的规则,我们就来看一下第一个病人:EXTI外部中断。

EXTI(Extern Interrupt)外部中断

EXTI可以监测指定GPIO口的电平信号,当其指定的GPIO口产生电平变化时,EXTI将立即向NVIC发出中断申请,经过NVIC裁决后即可中断CPU主程序,使CPU执行EXTI对应的中断程序。

支持的触发方式

支持的触发方式:上升沿/下降沿/双边沿上升沿和下降沿都可以触发中断/软件触发就是引脚啥事也没有,程序里执行一句代码就能触发中断

支持的GPIO口

支持的GPIO口:所有GPIO口但相同的Pin不能同时触发中断(比如PA0和PB0不能同时用,或者PA1、PB1、PC1这样的即端口GPIOO_Pin一样的,只能选择一个作为中断引脚。所以如果有多个中断引脚,要选择不同Pin的引脚,比如PA6、PA7、PA9和PB15、PB0和PB1这样的都可以

外部中断占用的通道

再看一下外部中断占用的通道:

通道数:16个GPIO_Pin(对应GPIO_Pin_0到GPIO_Pin_15),外加PVD输出、RTC闹钟、USB唤醒、以太网唤醒,这些加起来总共有20个中断线路。16个GPIOO_Pin外部中断的主要功能后面跟着的这四个东西(外加PVD输出、RTC闹钟、USB唤醒、以太网唤醒)其实是来蹭网的。

为啥这些东西要来外部中断蹭网?

因为这个外部中断有个功能,就是从低功耗模式的停止模式下唤醒STM32,对PVD电源电压监测。

当电源从电压过低恢复时,就需要PVD借助一下外部中断退出停止模式。对于RTC闹钟来说,有时候为了省电,RTC定一个闹钟之后,STM32会进入停止模式,等到闹钟响的时候再唤醒。这也需要借助外部中断。还有USB唤醒,以太网唤醒也都是类似的作用。当然我们本节主要学习引脚的外部中断。这四个蹭网的知道一下就行了。

外部中断的触发响应方式

外部中断的触发响应方式:中断响应/事件响应。

中断响应好理解,就是申请中断,让CPU执行中断函数。

事件响应其实是STM32对外部中断增加的一种额外的功能,当外部中断检测到引脚电平变化时,正常的流程是选择触发中断。但在STM32中也可以选择触发一个事件如果选择触发事件外部中断的信号就不会通向CPU而是通向其他外设用来触发其他外设的操作比如触发ADC转换触发DMA等。总结就是中断响应是正常的流程,引脚电平触发中断事件响应不会触发中断而是触发别的外设操作属于外设之间的联合工作。

外部中断的基本结构

接下来我们就来看一下外部中断的基本结构。

GPIO口的外设

这个图就是外部中断的整体结构图。首先最左边是GPIO口的外设

每个GPIO外设有16个引脚,所以每个外设进来16根线。

AFIO中断引脚选择

我们刚才这里说了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不能同时触发中断的原因。

EXTI边沿检测及控制

然后通过AFIO选择之后的16个通道就接到了EXTI边沿检测及控制电路上。同时下面这4个蹭网的外设,也是并列进来的。这些加起来就组成了EXTI的20个输入信号。

NVIC选择通道分配中断优先级

然后经过EXTI电路之后,分为了两种输出,其中上面的这些接到了NVIC,是用来触发中断的。

这里注意一下,本来20路输入,应该有20路中断的输出。但是可能ST公司觉得这20个输出太多了,比较占用NVIC的通道资源。所以就把其中外部中断的9~5,15~10给分配到了一个通道里。

也就是说外部中断的9~5会触发同一个中断函数15~10也会触发同一个中断函数。在编程的时候我们在这两个中断函数里需要再根据标志位来区分到底是哪个中断进来的

然后下面这里有20条输出线路到了其他外设,这就是用来触发其他外设操作的,也就是我们刚才说的事件响应。

AFIO和EXTI的内部电路

然后我们再具体的看一下这里AFIO和EXTI的内部电路。

AFIO复用lO口

先看一下AFIO复用lO口:

上图是AFIO选择中断引脚的结构图,这里就是一系列的数据选择器。

第一个输入是PA0、PB0、PC0等等,一直到PG0,尾号都是零,然后通过数据选择器,最终选择一个接到EXTI0上。配置AFIO_EXTICR1寄存器的EXIT0可以决定选择哪一个输入。

其他的是同样的道理。

AFIO主要用于引脚复用功能的选择和重定义也就是数据选择器的作用。

在STM32中,AFIO主要完成两个任务复用功能引脚重映射中断引脚选择

其中复用功能引脚重映射就是当我们想把这些默认复用功能的引脚换到重定义的这个位置来,就是用AFIO来完成的,这也是AFIO的一大主要功能。

另外一个功能就是我们刚才提到的中断引脚选择这个也是用AFIO来完成的。

EXTI的内部框图

下面看EXTI的内部框图

这里可以看到EXTI的右边就是20根输入线。然后输入线首先进入边沿检测电路,在上面的上升沿寄存器和下降沿寄存器可以选择是上升沿触发还是下降沿触发,或者两个都触发。接着触发信号就进入到这个或门的输入端了。

在这里硬件触发和软件中断寄存器的值接到了这个或门上,也就是任意一个为1。或门就可以输出1,所以才支持多种触发方式,如上升沿、下降沿、双边沿和软件触发。

触发信号通过这个或门之后就分两路,上一路是触发中断的,下一路是触发事件的。

触发中断首先会置一个挂起寄存器,这就相当于是一个中断的标志位,我们可以读取这个寄存器,判断是哪个通道触发的中断。如果中断挂起寄存器,置1,它就会继续向左走。

然后和中断屏蔽寄存器共同进入一个与门,然后是至NVIC中断控制器。

这里的门实际上就是开关的作用因为对于与门来说,1与上任意的数x都等于这个任意的输入x,0与上任意的数x都等于0。这就相当于中断屏蔽寄存器给1,那另一个输入就是直接输出也就是允许中断。中断屏蔽寄存器给0另一个输入无论是什么输出都是0相当于屏蔽了这个中断。这就是这个与门的作用,相当于一个开关控制。

接着看下一路事件的输出部分。

首先也是一个事件屏蔽寄存器进行开关控制。

最后通过一个脉冲发声器到其他外设。

这个脉冲发生器就是给一个电平脉冲,用来触发其他外设的动作。

然后这个框图画一个斜杠写着20表示的就是这是20根线,代表20个通道。

上面这些就是外设接口和APB总线,我们可以通过总线访问这些寄存器

这些就是EXTI的内部结构了。

到这里有关中断系统、NVIC中断控制器和EXTI外部中断的内容就讲完了。

配合外部中断使用的硬件模块

最后看一下配合外部中断我们所使用的硬件模块。

到底什么样的设备需要用到外部中断?使用外部中断有什么好处?

在这里大概总结了使用外部中断模块的特性,就是对于STM32来说,想要获取的信号是外部驱动的很快的突发信号。

比如旋转编码器的输出信号

我们可能很久都不会拧它,这时不需要STM32做任何事,但是我们一拧它就会有很多脉冲波形,需要STM32接收。这个信号是突发的,STM32不知道什么时候会来,同时它是外部驱动的,STM32只能被动读取,而且这个信号非常快,STM32稍微晚来一点读取就会错过很多波形。所以对于这种情况来说,就可以考虑使用STM32的外部中断了。一有脉冲过来,STM32立即进入中断函数处理。没有脉冲的时候,STM32就专心做其他事情。

另外还比如红外遥控接收头的输出,接收到遥控数据之后,它会输出一段波形。这个波形转瞬即逝,并且不会等你,所以就需要我们用外部中断来读取。

最后还有按键,虽然它的动作也是外部驱动的突发事件,但并不推荐使用外部中断来读取按键因为外部中断不好处理按键抖动和松手检测的问题,对于按键来说,它的输出波形也不是转瞬即逝的。所以要求不高的话,可以在主程序中循环读取。如果不想用主循环读取的话,可以考虑一下定时器中断读取的方式。这样既可以做到后台读取按键值不阻塞主程序,也可以很好的处理按键抖动和松手检测的问题。

了解完外部中断的适用场景之后,我们就来看一下这个编码器介绍。

旋转编码器

旋转编码器是用来测量位置、速度或旋转方向的装置。当其旋转轴旋转时,其输出端可以输出与旋转速度和方向对应的方波信号。读取方波信号的频率和相位信息即可得知旋转轴的速度和方向。

旋转编码器的类型:机械触点式,霍尔传感器式,光栅式等类型。

旋转编码器是怎么工作的?

首先看一下这个东西

它是一种最简单的编码器样式了,这里使用的也是对射式红外传感器来测速的。为了测速还需要配合一个这样的光栅编码盘。

当这个编码盘转动时红外传感器的红外光就会出现遮挡透过遮挡透过这样的现象

对应模块输出的电平就是高低电平交替的方波。方波的个数代表了转过的角度方波的频率代表转速。我们就可以用外部中断来捕获这个方波的边沿以此判断位置和速度。

不过这个模块只有一路输出,正转反转输出波形没法区分。所以这种测速方法只能测位置和速度不能测量旋转方向。

为了进一步测量方向,我们就可以用这几种编码器:

第一个图片就是我们套件里的旋转编码器了,左边是它的外观,右边是它的内部拆解结构。

它内部是用金属触点来进行通断的,所以它是一种机械触点式编码器,这里左右是两部分开关触点。

其中内侧的两根细的触点都是和中间的这个引脚连接的。

外侧的触点,左边的接在这个引脚,右边的接在这个引脚,这就是这些触点的连接方式。

然后中间这个圆的金属片是一个按键,

我们这个旋转编码器的轴是可以按下去的,

这个按键的两根线就在上面引出来

按键的轴按下,则上面两根线短路。松手则上面两根线断开。

然后再看一下编码盘

它也是一系列像光栅一样的东西,

只不过这是金属触点,在旋转时依次接通和断开两边的触点。

并且还有个关键的部分是这个金属盘的位置是经过设计的,它能让两侧触点的通断产生一个九十度的相位差,最终配合一下外部电路,这个编码器的两个输出就会输出这样的波形:

当正转时,A侧引脚输出一个方波信号,同时B相引脚输出一个和它相位相差90度的波形。

也就是正向旋转时,B相输出是滞后90度

反向旋转时A相还是方波信号,B相就会提前90度

这样正转和反转就可以区分开了。

这种相位相差九十度的波形就叫正交波形波形信号输出的编码器是可以用来测方向的这就是单向输出和两正交输出的区别。

当然还有的编码器不是输出正交波形,而是一个引脚输出方波信号代表转速,另一个输出高低电平代表旋转方向。这种不是正交输出的编码器,但也是可以测量方向。

然后接着看一下第二个图,

这种是直接附在电机后面的编码器,是霍尔传感器形式的编码器

中间是一个圆形磁铁

边上有两个位置错开的霍尔传感器。

当磁铁旋转时通过霍尔传感器就可以输出正方波信号。

最后一个就是独立的编码器元件,

它的输入轴转动时输出就会有波形,

这个也是可以测速和测方向的,具体用法再看相应的手册。

第二个图里的这个编码器一般是用来进行调节的,

比如音响调节音量这样的用途,因为它是触点接触的形式,所以不适合电机这种高速旋转的地方,另外几种都是非接触的形式,可以用于电机测速。电机测速在电机驱动的应用中还是非常常见的。

我们下节就用这种旋转编码器模块来学习一下外部中断。本节先学习一下外部中断读取编码器计次数据的用法。以后我们学了定时器,还会再来看一下编码器测速的用途的。

接下来我们看一下这个旋转编码器的硬件电路

这个是模块的电路图

这个图里中间这个就是旋转编码器

上面按键的两根线,这个模块并没有使用,是悬空的。

下面的这里就是编码器内部的两个触点

旋转轴旋转时,这两个触点以相位相差九十度的方式交替导通。因为这只是个开关信号,所以要配合外围电路才能输出高低电平。

看一下左边,这里接了一个10k的上拉电阻。

默认没旋转的情况下,这个点被上拉为高电平,通过R3这个电阻输出到A端口的就也是高电平。

当旋转时内部这里触点导通,这个点就直接被拉低到GND了

再通过R3输出A端口就是低电平的

R3是一个输出限流电阻,它是为了防止模块引脚电流过大的。

C1是输出滤波电容,可以防止一些输出信号抖动。

然后右边的这一部分电路和左边的也是一模一样的。

最后中间这里可以看到这个模块的C端口就直接接到了GND。

下图就是这个模块的外部图

A相输出和B相输出接到STM32的两个引脚比如PB0和PB1。注意引脚的GPIO_Pin编号不要一样就行了。

然后中间的C引脚就是GND,我们暂时不用。

查看手册建议

最后说明一下,虽然我们是用库函数来实现应用的,但是最终还是落实到寄存器的配置上的,所以建议大家看看这两份手册,大概看一下每个外设在手册里的介绍。

首先是NVIC,因为NVIC是内核外设,所以要在这个Cortex_M3编程手册里找

这个Cortex_M3编程手册里就是内核和内核外设的详细介绍。如果你想研究一下内核的运转细节,可以看一下这个手册。

里面我们可以找到NVIC的一些寄存器,包括中断使能寄存器、中断清除使能寄存器、中断设置挂起寄存、中断清除挂起寄存器、中断活动位寄存器、中断优先级寄存器,这个中断优先级寄存器就是用来设置每个中段的优先级的、接着还有一个软件触发中断寄存器。

每一个寄存器的内容可以自己翻看手册去了解一下。

另外这些NVIC寄存器里还少了一个东西,就是中断分组的配置,中断分组的配置寄存器是被分配到了这个SCB里面的。在SCB_AIRCR里,这三位就是用来配置中断分组的

然后我们再打开这个STM32的参考手册

里面会有中断系统和外部中断的介绍以及NVIC的概述,然后是中断相量表,接着就是外部中断EXTI的介绍。还有一些框图,和外部中断唤醒事件的说明、外部中断的功能说明。

还有中断的线路映象,也就是中断引脚选择,这一部分实际上是在AFIO里的。

最后就是外部中断的寄存器描述,这里有中断屏蔽寄存器、事件屏蔽寄存器、上升沿触发选择寄存器、下降沿触发选择寄存器、软件触发寄存器、挂起寄存器。

手册里还介绍了AFIO外设,在这个目录里找到GPIOO和AFIO打开AFIO这一节。

本节中断系统和外部中断的理论部分就到这里,下一小节我们再来学习一下外部中断的代码部分。

QQ交流群:963138186

本篇就到这里,下篇继续!欢迎点击下方订阅本专栏↓↓↓

Logo

开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!

更多推荐