3、STM32EXIT外部中断(STM32)

STM32中断

(中断,对于引脚来说,相当于引脚发生了电平跳变,对于定时器来说,可以是定时的时间到了。 

中断嵌套:把中断程序再次中断,就叫做中断嵌套)

(被暂停的地方称为断点)

为了程序能在中断返回时继续原来的工作,在中断执行前,会对程序的现场进行保护,中断执行后,会再还原现场,这样可以保证主程序即使被中断了,回来后也能继续运行,当然我们用c语言编程,保护现场和还原现场的工作并不需要我们去做,编译器自动帮我们做好了,这里了解一下即可。

一般中断程序都是在一个子函数里的,这个函数不需要我们调用,当中断来临时,由硬件自动调用这个函数。

       STM32中断:有68个可屏蔽中断通道(中断通道即中断源,68格是F1系列最多的中断数量),stm32包含EXTI外部中断、TIM定时器、ADC模数转换器、USART串口、SPI通信、I2C通信、RTC实时时钟等多个外设;
      使用NVIC统一管理中断,每个中断通道都拥有16个可编程的优先等级,可对优先级进行分组,进一步设置抢占优先级和响应优先级。(NVIC是STM32用来管理中断、分配优先级的,NVIC的中断优先级总共有16个等级,还可以设置抢占优先级,这个是非常灵活的)

下面就是STM32里的中断资源了,了解一下即可,灰色为内核中断(比较高深),其他就是STM32的外设中断了,比如第一个,窗口看门狗,这个是用来监测程序运行状态的中断,那比如你的程序卡死了,没有及时喂狗,窗口看门狗就会申请中断,让你的程序跳到窗口看门狗的中断程序里,那你在中断程序里就可以进行一些错误检查,看看出现什么问题了。

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

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

(地址的作用:程序中的中断函数的地址是由编译器来分配的,是不固定的,但是我们的中断跳转,由于硬件的限制,只能跳到固定的地址执行程序,所以为了能让硬件跳转到一个不固定的中断函数里,这里就需要在内存中定义一个地址的列表,这个列表的地址是固定的,中断发生后,就跳到这个固定位置,然后在这个固定位置,由编译器再加上一条跳转到中断函数的代码,这样中断跳转就可以跳转到任意位置了,这个中断地址的列表就叫中断向量表,相当于中断跳转的一个跳板,不过我们用c语言编程的话是不需要这个中断向量列表的,因为编译器已经做好了)

NVIC(嵌套中断向量控制器)

接下来看NVIC的基本结构

       在STM32中,使用NVIC统一管理中断,每个中断通道都拥有16个可编程的优先等级,可对优先级进行分组,进一步设置抢占优先级和响应优先级。(NVIC是STM32用来管理中断、分配优先级的,NVIC的中断优先级总共有16个等级,还可以设置抢占优先级,这个是非常灵活的),它是一个内核外设(CPU小助手)。

        图中中断与NVIC连接的地方有一斜杠加一个n,表示一个外设可能会同时占用多个中断通道,所以这里有n条线,然后NVIC只有一个输出口,NVIC根据每个中断的优先级分配中断的先后顺序,最后通过右边一个输出口告诉CPU要处理哪一个中断。

NVIC优先级分组

         优先级分为响应优先级和抢占优先级:

(1)响应优先级:相当于插队的优先级(例子:上一个人在看病,外面排队了很多病人,当上一个病人看完后,紧急的病人即使是后来的,也会最先进去看病,这种相当于插队的优先级叫做响应优先级)

(2)抢占优先级:(例子:上一个人在看病,外面排队了很多病人,当上一个病人看完甚至还在看的时候,如果下一个病人更加紧急,那他甚至可以不等上一个人看完,他可以直接冲进去让上一个病人靠边站,先给他看病,等他看完后,然后上一个病人再继续。这种形式的优先级就是中断嵌套,这种决定是不是可以中断嵌套的优先级就叫抢占优先级,抢占优先级高的可以进行中断嵌套)

补充:响应优先级高的可以优先排队,抢占优先级和响应优先级均相同的按中断号(表里第二列)排队,数值小的优先响应

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

(值越小,优先级越高,0是最高级优先级)

接下来开始第一个病人:

一、EXIT(Extern Interrupt)外部中断

1、简介

(简单来说,就是引脚电平变化,申请中断)

(1)触发方式:

        上升沿:就是电平从低电平变到高电平的瞬间触发中断。

        下降沿:就是电平从高电平变到低电平的瞬间触发中断。

        双边沿:上升沿和下降沿都可以触发中断

        软件触发:就是引脚啥事没有,程序里执行一句代码就能触发中断。

注意:•支持的GPIO口:所有GPIO口,但相同的Pin不能同时触发中断,意思比如PA0和PB0不能同时用。

(2)通道数:16GPIO_Pin,外加PVD输出、RTC闹钟、USB唤醒、以太网唤醒;总共有20个中断线路,前16个为外部中断的主要功能,后四个相当于“蹭网”(一、因为外部中断有一个功能,就是从低功率模式的停止模式下唤醒STM32,那对于PVD电源电压监测,当电源从电压过低恢复时,就需要PVD借助一下外部中断退出模式;二、有时为了省电,RTC定一个闹钟后,STM32会进入停止模式,等到闹钟饷时候再唤醒,这也需要借助外部中断......知道一下就行)

(3)触发响应方式:

中断响应:正常的流程,引脚电平变化触发中断。

事件响应:不会触发中断,而是触发别的外设操作,属于外设之间的联合工作。

(4)EXIT外部中断的基本结构

AFIO:实际是数据选择器,将前面3个外设的GPIO外设引脚里选择其中一个连接到后面EXTI的通道里,(所以前面说”所有GPIO口可以触发中断,相同的PIN不能同时触发中断“,因为这些只有其中一个能被接到EXTI的通道0上)

EXTI连接NVIC通道中,9到5被放在用一个通道会触发同一个中断函数,15到10也会触发同一个中断函数,在编程的时候,我们在这两个中断函数,需要再根据标志位来区分到底是哪个中断进来。下面20那连的其他外设就是事件响应。

2、AFIO复用IO口

这里的重定义即把这些默认复用功能的引脚换到重定义的这个位置来:

(右边两列)

3、EXTI框图

这里说一下,中间第二个“请求挂起寄存器”相当于一个中断标志位,我们可以读取这个寄存器判断是哪个通道触发的中断,如果中断挂起寄存器,它就会继续向左走,和中断屏蔽寄存器共同进入一个与门,然后是NVIC中断控制器。(这里的与门相当于开关的作用,中断屏蔽寄存器给1,那么另一个输入就是直接输入,也就是允许中断;中断屏蔽器给0,那另一个输入无论是什么,都为0,相当于屏蔽了这个中断)下面事件屏蔽寄存器同理,最后通过脉冲发生器连接其他外设,这个脉冲发生器就是给一个电平脉冲,用来触发其他外设的动作。

EXTI配置

AFIO口的库函数包含在GPIO函数文件里,打开之前12个函数附近,可以看到后面六个函数,其中后五个是AFIO口的配置,加上之前第二个函数一共六个AFIO配置函数:

这个函数是用来复位AFIO口的。

后六个函数名如下:(只用第五个)

第一个(361)GPIO_PinLockConfig函数是设定GPIO配置的,调用这个函数,参数指定某个引脚,防止意外更改;

第二个和第三个(362-363)GPIO_EventOutputConfig和GPIO_EventOutputCmd函数是用来配置AFIO的事件输出功能的

第四个(364)GPIO_PinRemapConfig函数可以用来进行引脚重映射

第五个是重点, GPIO_EXTILineConfig函数可以配置AFIO的数据选择器,来选择我们想要的中断引脚,打开这个函数可以看到里面是操作的AFIO的寄存器。

第六个是以太网外设

开始用EXIT中断:

只需要把这个外部中断,从GPIO到NIVC这一路出现的外设模块都配置好,把这条信号电路打通即可,外部中断配置步骤如下:

第一步:配置RCC,把我们这里涉及的外设时钟都打开,让其工作;

第二步:配置GPIO,选择我们的端口为输入模式;

第三步:配置AFIO,选择我们用的这一路GPIO,连接到后面的EXTI;

第四步:配置EXTI,选择边沿触发方式,比如上升沿、下降沿或者双边沿,还有选择触发响应方式,可以选择中断响应和事件响应(一般中断响应);

第五步:配置NVIC,给我们这个中断选择一个合适的优先级,最后通过NVIC,外部中断信号就能进入CPU了。CPU收到中断信号,会跳到中断函数里执行中断程序

**配置EXTI:

1、void EXTI_DeInit(void);//把EXTI的配置调整,恢复成上电默认状态
2、void EXTI_Init(EXTI_InitTypeDef* EXTI_InitStruct);//EXTI外设参数配置
3、void EXTI_StructInit(EXTI_InitTypeDef* EXTI_InitStruct);//把参数传递的结构体变量赋一个默认值
4、void EXTI_GenerateSWInterrupt(uint32_t EXTI_Line);//用来软件触发外部中断(调用这个函数,  参数给一个指定的中断线,就能软件触发一次这个外部中断,如果程序需要这个功能,就可以使用这个函数,如果你只需要外部引触发中断,那就不需要用这个函数了)
5、FlagStatus EXTI_GetFlagStatus(uint32_t EXTI_Line);
6、void EXTI_ClearFlag(uint32_t EXTI_Line);
7、ITStatus EXTI_GetITStatus(uint32_t EXTI_Line);
8、void EXTI_ClearITPendingBit(uint32_t EXTI_Line);

剩下这四个函数,也就是库函数的模板函数,很多模块都有这四个函数模块,因为在外设运行的过程中,会产生一些状态标志位。比如外部中断来了,是不是会有一个挂起寄存器置了一个标志位,对于其他外设,比如串口收到数据,会置标志位,定时器时间到,也会置标志位。这些标志位都是放在状态寄存器的,当程序想要看这些标志位时,就可以用这四个函数。

详说:

           第五个函数可以获取指定的标志位是否被置1了。

           第六个函数可以对置1的标志位进行清除。

           第七个函数可以获取中断标志位是否被置1了。

           第八个函数可以清除中断挂起标志位

所以想在主程序里查看和清除标志位时,可以用第五六个函数;如果想在中断程序里查看和清除标志位,就用下面的第七八个函数。这四个函数本质上都为对状态寄存器的读写。

二、TIM定时中断

附:STM32中断资源: