×
单片机 > 单片机程序设计 > 详情

STM32的外部中断EXTI及NVIC中断优先级介绍

发布时间:2020-09-03 发布时间:
|

一、什么是中断?


打断当前的操作,执行中断需要做的事情。


中断的作用:中断机制不仅赋予了系统处理意外情况的能力,就可以“同时”完成多个任务,提高了并发“处理”能力。


和线程的区别:线程是同时执行多个任务,中断是停下来去执行其他的(注意优先级),执行完了再回来执行,


定时器才相当于线程,定一个时间,每到这个时间执行一次



二、中断概述


STM32F4并没有使用CM4内核的全部东西,而是只用了它的一部分。


STM32F40xx/STM32F41xx总共有92个中断


STM32F42xx/STM32F43xx则总共有96个中断


STM32F40xx/STM32F41xx的92个中断里面,包括10个内核中断和82个可屏蔽中断,具有16级可编程的中断优先级,而我们常用的就是这82个可屏蔽中断。


三、外部中断/事件线映射多达140个GPIO。


 

根据图文,发现我们的中断线总共有23根,其中16根是连接PA~PI引脚。 


STM32F4供IO使用的中断线只有16个:EXTI线0~15:对应外部IO口的输入中断。


剩下的七根是分别连接专用设备的:


 另外七根 EXTI 线连接方式如下:


● EXTI 线 16 连接到 PVD 输出


● EXTI 线 17 连接到 RTC 闹钟事件


● EXTI 线 18 连接到 USB OTG FS 唤醒事件


● EXTI 线 19 连接到以太网唤醒事件


● EXTI 线 20 连接到 USB OTG HS(在 FS 中配置)唤醒事件


● EXTI 线 21 连接到 RTC 入侵和时间戳事件


● EXTI 线 22 连接到 RTC 唤醒事件


四、中断服务函数分配


IO口外部中断在中断向量表中只分配了7个中断向量,也就是只能使用7个中断服务函数



从表中看出,外部中断线5~9分配一个中断向量,共用一个服务函数 外部中断线10~15分配一个中断向量,共用一个中断服务函数


中断服务函数列表如下:



四、设置中断优先级的分组


1、中断优先级有两种:


      抢占(占先式)优先级 --》 第一序列                  响应(副)优先级 --》 第二序列


 2、抢占优先级 &响应优先级区别:


       高优先级的抢占优先级是可以打断正在进行的低抢占优先级中断的。


       抢占优先级相同的中断,高响应优先级不可以打断低响应优先级的中断。


       抢占优先级相同的中断,当两个中断同时发生的情况下,哪个响应优先级高,哪个先执行。


       如果两个中断的抢占优先级和响应优先级都是一样的话,则看哪个中断先发生就先执行;



3、中断优先级设置步骤


    ①系统运行后先设置中断优先级分组。调用函数:


void NVIC_PriorityGroupConfig(uint32_t NVIC_PriorityGroup);整个系统执行中只设置一次中断分组。


   ②针对每个中断,设置对应的抢占优先级和响应优先级:


void NVIC_Init(NVIC_InitTypeDef* NVIC_InitStruct);


  ③如果需要挂起/解挂,查看中断当前激活状态,分别调用相关函数即可



五、外部中断的一般配置步骤


①使能SYSCFG时钟:


    RCC_APB2PeriphClockCmd(RCC_APB2Periph_SYSCFG, ENABLE);


②初始化IO口为输入。


    GPIO_Init();


③设置IO口与中断线的映射关系。


    void SYSCFG_EXTILineConfig();//通过设置SYSCFG寄存器,建立IO口和中断线的连接


④初始化线上中断,设置触发条件等。


    EXTI_Init();


⑤配置中断分组(NVIC),并使能中断。


    NVIC_Init();



⑥编写中断服务函数。


    EXTIx_IRQHandler();


且清除中断标志位


EXTI_ClearITPendingBit();//清除中断标志位是为了表示中断已经开始执行,可以接收下一个中断。


----------------------------------------------------------------------------------------------------------------------------------------------------------


代码如下:


/**********************************************

*

*功能:四个按键中断

*

**********************************************/

#include "exti.h"

 

 

//外部中断初始化程序

//初始化PE2~4,PA0为中断输入.

void EXTI4_Init(void)

{

    NVIC_InitTypeDef   NVIC_InitStructure;

    EXTI_InitTypeDef   EXTI_InitStructure;

    GPIO_InitTypeDef  GPIO_InitStructure;

 

 

    RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOE, ENABLE);//使能GPIOA,GPIOE时钟

    RCC_APB2PeriphClockCmd(RCC_APB2Periph_SYSCFG, ENABLE);//使能SYSCFG时钟

 

    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4; //KEY0 KEY1 KEY2对应引脚

    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN;//普通输入模式

    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;//100M

    GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;//上拉

    GPIO_Init(GPIOE, &GPIO_InitStructure);//初始化GPIOE2,3,4

 

    SYSCFG_EXTILineConfig(EXTI_PortSourceGPIOE, EXTI_PinSource4);//PE4 连接到中断线4

 

    /* 配置EXTI_Line2,3,4 */

    EXTI_InitStructure.EXTI_Line = EXTI_Line4;

    EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;//中断事件

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

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

    EXTI_Init(&EXTI_InitStructure);//配置

 

    NVIC_InitStructure.NVIC_IRQChannel = EXTI4_IRQn;//外部中断4

    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x01;//抢占优先级1

    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x02;//子优先级2

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

    NVIC_Init(&NVIC_InitStructure);//配置   

}

 

 

void EXTI3_Init(void)

{

    NVIC_InitTypeDef   NVIC_InitStructure;

    EXTI_InitTypeDef   EXTI_InitStructure;

    GPIO_InitTypeDef  GPIO_InitStructure;

 

 

    RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOE, ENABLE);//使能GPIOA,GPIOE时钟

    RCC_APB2PeriphClockCmd(RCC_APB2Periph_SYSCFG, ENABLE);//使能SYSCFG时钟

 

    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3; //KEY0 KEY1 KEY2对应引脚

    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN;//普通输入模式

    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;//100M

    GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;//上拉

    GPIO_Init(GPIOE, &GPIO_InitStructure);//初始化GPIOE2,3,4

 

    SYSCFG_EXTILineConfig(EXTI_PortSourceGPIOE, EXTI_PinSource3);//PE4 连接到中断线4

 

 

    /* 配置EXTI_Line2,3,4 */

    EXTI_InitStructure.EXTI_Line = EXTI_Line3;

    EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;//中断事件

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

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

    EXTI_Init(&EXTI_InitStructure);//配置

 

    NVIC_InitStructure.NVIC_IRQChannel = EXTI3_IRQn;//外部中断4

    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x01;//抢占优先级1

    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x02;//子优先级2

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

    NVIC_Init(&NVIC_InitStructure);//配置   

}

 

 

void EXTI2_Init(void)

{

    NVIC_InitTypeDef   NVIC_InitStructure;

    EXTI_InitTypeDef   EXTI_InitStructure;

    GPIO_InitTypeDef  GPIO_InitStructure;

 

    RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOE, ENABLE);//使能GPIOA,GPIOE时钟

    RCC_APB2PeriphClockCmd(RCC_APB2Periph_SYSCFG, ENABLE);//使能SYSCFG时钟

 

    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2; //KEY0 KEY1 KEY2对应引脚

    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN;//普通输入模式

    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;//100M

    GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;//上拉

    GPIO_Init(GPIOE, &GPIO_InitStructure);//初始化GPIOE2,3,4

 

    SYSCFG_EXTILineConfig(EXTI_PortSourceGPIOE, EXTI_PinSource2);//PE4 连接到中断线4

 

 

    /* 配置EXTI_Line2,3,4 */

    EXTI_InitStructure.EXTI_Line = EXTI_Line2;

    EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;//中断事件

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

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

    EXTI_Init(&EXTI_InitStructure);//配置

 

    NVIC_InitStructure.NVIC_IRQChannel = EXTI2_IRQn;//外部中断4

    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x01;//抢占优先级1

    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x02;//子优先级2

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

    NVIC_Init(&NVIC_InitStructure);//配置   

}

 

 

void EXTI0_Init(void)

{

    NVIC_InitTypeDef   NVIC_InitStructure;

    EXTI_InitTypeDef   EXTI_InitStructure;

    GPIO_InitTypeDef  GPIO_InitStructure;

 

 

    RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE);//使能GPIOA,GPIOE时钟

    RCC_APB2PeriphClockCmd(RCC_APB2Periph_SYSCFG, ENABLE);//使能SYSCFG时钟

 

    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0; //KEY0 KEY1 KEY2对应引脚

    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN;//普通输入模式

    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;//100M

    GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;//上拉

    GPIO_Init(GPIOA, &GPIO_InitStructure);//初始化GPIOE2,3,4

 

    SYSCFG_EXTILineConfig(EXTI_PortSourceGPIOA, EXTI_PinSource0);//PE4 连接到中断线4

 

 

    /* 配置EXTI_Line2,3,4 */

    EXTI_InitStructure.EXTI_Line = EXTI_Line0;

    EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;//中断事件

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

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

    EXTI_Init(&EXTI_InitStructure);//配置

 

    NVIC_InitStructure.NVIC_IRQChannel = EXTI0_IRQn;//外部中断4

    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x01;//抢占优先级1

    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x02;//子优先级2

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

    NVIC_Init(&NVIC_InitStructure);//配置   

}

 

 

//外部中断4服务程序

void EXTI4_IRQHandler(void)

{

     if(EXTI_GetITStatus(EXTI_Line4) != RESET)//判断是否置位

    {} 

    EXTI_ClearITPendingBit(EXTI_Line4);//清除LINE4上的中断标志位  

}

 

 

//外部中断3服务程序

void EXTI3_IRQHandler(void)

{

    delay_ms(15);

 

    EXTI_ClearITPendingBit(EXTI_Line4);//清除LINE4上的中断标志位  

}

 

 

//外部中断2服务程序

void EXTI2_IRQHandler(void)

    EXTI_ClearITPendingBit(EXTI_Line4);//清除LINE4上的中断标志位  

}

 

 

//外部中断0服务程序

void EXTI0_IRQHandler(void)

    EXTI_ClearITPendingBit(EXTI_Line4);//清除LINE4上的中断标志位  

}





『本文转载自网络,版权归原作者所有,如有侵权请联系删除』

热门文章 更多
ARM 汇编的必知必会