打印
[应用相关]

STM32的外部中断管理

[复制链接]
795|11
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
STM32的每个IO都可以作为外部中断输入。以STM32F429为例,它的中断控制器支持 22个外部中断/事件请求。每个中断设有状态位,每个中断/事件都有独立的触发和屏蔽设置。通常供IO口使用的中断线只有16个:EXTI线0~15:对应外部IO口的输入中断。但是有些MCU的IO口却远远不止16个,那么MCU是怎么把16个中断线和IO口一一对应起来的呢?
在STM32上是这样设计的,GPIO的引脚 GPIOx.0-GPIOx.15(x=A,B,C,D,E,F,G,H,I)分别对应中断线0~15。这样每个中断线对应了最多9个IO口。中断线每次只能连接到1个IO口上,这样就需要通过配置来决定对应的中断线配置到哪个GPIO上。GPIO跟中断线的映射关系图如下:

使用特权

评论回复
沙发
wangjiahao88|  楼主 | 2021-11-16 12:34 | 只看该作者

使用特权

评论回复
板凳
wangjiahao88|  楼主 | 2021-11-16 12:36 | 只看该作者
除了上图看到IO与各中断线的对应关系,其它一些中断线也比较常用,如:

EXTI线16连接到PVD输出

EXTI线17连接到RTC闹钟事件

EXTI线18连接到USB唤醒事件

EXTI线19连接到以太网唤醒事件(只适用于互联型产品)等

对于不同型号的STM32来说可能会略有差异,但用法基本一致。

中断事件在不同应用场景也各不相同,比如下面一些常见的中断方式:

1.通过配置上升沿/下降沿触发选择寄存器选择边沿检测电路所要检测的边沿跳变。

2.边沿检测电路根据输入线是否有相应的边沿跳变,检测到则输出信号1,否则输出信号0。

3.通过一个或门,或门以边沿检测电路、软件中断事件寄存器(中断事件可以通过软件产生)作为输入。两者之一有一个产生信号1,或门就输出信号1。

下面来看一下在应用程序中如何来使用这些中断事件,为了更加直观明了这里使用标准库代码为例,演示如何来做一个按键。

首先,初始化一个IO口是必不可少的。

使用特权

评论回复
地板
wangjiahao88|  楼主 | 2021-11-16 12:36 | 只看该作者
void KEY_Init(void)

{

     GPIO_InitTypeDef GPIO_InitStructure;

     RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);   //使能PA端口时钟

     GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;        //端口配置

     GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;   //上拉输入

     GPIO_Init(GPIOC, &GPIO_InitStructure);           //根据设定参数初始化GPIOC

}
接下来要打开IO口的复用功能:使能EXTI外设对应的时钟。注意:当使用EXTI外设时,使能的是AFIO时钟,而不是EXTI外设时钟 。

RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE);

完成上面步骤后,后面需要把中断线和对应的IO口关联上。打开库gpio.h文件,可以看到GPIO_PinSource0到GPIO_PinSource15顺序定义,可对应每一个GPIO。

利用GPIO_EXTILineConfig()将EXTI线0连接到端口GPIOA的第0个针脚上:

GPIO_EXTILineConfig(GPIO_PortSourceGPIOA,GPIO_PinSource0);

下面初始化EXTI。打开库exti.h文件,可以看到所定义的各中断线:

typedef enum

{

     EXTI_Mode_Interrupt = 0x00,  //中断触发

     EXTI_Mode_Event = 0x04     //事件触发

}EXTIMode_TypeDef;

typedef enum

{

     EXTI_Trigger_Rising = 0x08,       //上升沿触发

     EXTI_Trigger_Falling = 0x0C,       //下降沿触发

     EXTI_Trigger_Rising_Falling = 0x10   //高低电平触发

}EXTITrigger_TypeDef;

#define EXTI_Line0       ((uint32_t)0x00001)

#define EXTI_Line1       ((uint32_t)0x00002)

……

#define EXTI_Line18     ((uint32_t)0x40000)

#define EXTI_Line19     ((uint32_t)0x80000)

EXIT初始化代码如下:

void exti_Init(void)

{

      EXTI_InitTypeDef   EXTI_InitStructure;

      RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE);    //外部中断,需要使能AFIO时钟

      GPIO_EXTILineConfig(GPIO_PortSourceGPIOA,GPIO_PinSource0);   //将EXTI线连接到对应的IO端口上

      EXTI_InitStructure.EXTI_Line =   EXTI_Line0;    //常用的就是EXTI_Line0-EXTI_Line015负责gpio管脚的那几个

      EXTI_InitStructure.EXTI_Mode =   EXTI_Mode_Interrupt;  

      EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling;      //下降沿触发

      EXTI_InitStructure.EXTI_LineCmd = ENABLE;             //中断线使能

      EXTI_Init(&EXTI_InitStructure);                       //初始化中断

}

使用特权

评论回复
5
wangjiahao88|  楼主 | 2021-11-16 13:04 | 只看该作者
至此外部中断就已经完成,但这还不能结束。有中断,就要有中断优先级NVIC,不然同时来几个中断那应该先执行哪个呢?我们可以看一下优先级的定义。

在NVIC有一个专门的寄存器:中断优先级寄存器NVIC_IPRx用来配置外部中断的优先级,IPR宽度为8bit,原则上每个外部中断可配置的优先级为0~255,数值越小,优先级越高。在STM32F4中,只使用了高4bit,就是每个外部中断可配置的优先级为0-15。用于表达优先级的这 4bit,又被分组成抢占优先级和子优先级(也叫响应优先级)。如果有多个中断同时响应,抢占优先级高的就会比抢占优先级低的优先得到执行,如果抢占优先级相同,就比较子优先级。如果抢占优先级和子优先级都相同的话,就比较他们的硬件中断编号,编号越小,优先级越高。

NVIC_PriorityGroupConfig有两种分组:NVIC_PriorityGroup_4和NVIC_PriorityGroup_2

如果是第一种,那系统就分配了4位抢占优先级,0位响应优先级,同等优先级的情况下先发生就先执行。

如果是第二种,系统就分配了2位抢占优先级,2位响应优先级,那么当两个中断同时发生的时候就会首先响应外部中断2,因为外部中断2子优先级高于外部中断1的子优先级,数值越小优先级越高。配置示例如下:

NVIC_InitStructure.NVIC_IRQChannel = EXTI2_IRQn;         //使能外部中断通道

NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2;  //抢占优先级2 因为为分组为4 这里可以设置为0-3

NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;      //响应优先级0

NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;   //使能外部中断通道

NVIC_Init(&NVIC_InitStructure);       //根据NVIC_InitStruct中指定的参数初始化外设NVIC寄存器

由上面我们可以看到,每个IO口与中断线要对应起来,除此之外还要对应中断函数,在库函数EXTI0_IRQn,EXTI1_IRQn,EXTI2_IRQn,EXTI3_IRQn,EXTI4_IRQn,EXTI9_5_IRQn(EXTI5-EXTI9都对应这个中断),EXTI15_10_IRQn(EXITI10-EXTI15都对应这个中断函数)。如STM32F4在stm32f4xx.h中用了一个枚举结构体包含了这些中断通道。

到此, STM32中断管理的内容也大致介绍完了,后面再完整的给出中断配置代码,这样也更为直观方便,相信大家结合代码再回想前面的内容,对外部中断有更好的理解。

使用特权

评论回复
6
wangjiahao88|  楼主 | 2021-11-16 13:05 | 只看该作者
void key_exti_init(void)

{

      GPIO_InitTypeDef GPIO_InitStructure;

      EXTI_InitTypeDef EXTI_InitStructure;  

      NVIC_InitTypeDef NVIC_InitStructure;



      RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE);    //外部中断,需要使能AFIO时钟

      RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);   //使能PA端口时钟

      GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;           //端口配置

      GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;      //上拉输入

      GPIO_Init(GPIOA, &GPIO_InitStructure);    //根据设定参数初始化GPIOA

      //注意:如果配置的针脚是0号,那么参数必须是GPIO_PinSource0 如果配置的针脚是3号,那么参数必须是GPIO_PinSource3  

      GPIO_EXTILineConfig(GPIO_PortSourceGPIOA,GPIO_PinSource0);//将EXTI线连接到对应的IO端口上

      //注意:如果配置的0号针脚,那么EXTI_Line0是必须的 如果配置的针脚是3号,那么参数必须是EXTI_Line3

      EXTI_InitStructure.EXTI_Line = EXTI_Line0;   //常用的就是EXTI_Line0-EXTI_Line015负责gpio管脚的那几个

      EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;  

      EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling;    //下降沿触发

      EXTI_InitStructure.EXTI_LineCmd = ENABLE;

      EXTI_Init(&EXTI_InitStructure);     //初始化中断



      NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);     //设置NVIC中断分组2:2位抢占优先级,2位响应优先级

      NVIC_InitStructure.NVIC_IRQChannel = EXTI0_IRQn;   //使能外部中断通道

      NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2;   //抢占优先级2 因为为分组为2 这里可以设置为0-3

      NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;   //响应优先级0

      NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;   //使能外部中断通道

      NVIC_Init(&NVIC_InitStructure);       //根据NVIC_InitStruct中指定的参数初始化外设NVIC寄存器

}

使用特权

评论回复
7
nawu| | 2021-12-10 11:52 | 只看该作者
最多可以多少个中断来着

使用特权

评论回复
8
qcliu| | 2021-12-10 11:54 | 只看该作者
软硬件配合啊

使用特权

评论回复
9
tfqi| | 2021-12-10 12:09 | 只看该作者
那得需要多少个中断啊

使用特权

评论回复
10
wiba| | 2021-12-10 12:10 | 只看该作者
看看是不是需要优化啊

使用特权

评论回复
11
zljiu| | 2021-12-10 12:11 | 只看该作者
这个其实很关键啊

使用特权

评论回复
12
小叶三千| | 2021-12-10 13:02 | 只看该作者
感谢分享,中断优先级在项目产品中很关键,搞不好要出大问题

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

462

主题

7477

帖子

29

粉丝