【STM32F407学习笔记】中断优先级管理与外部中断

这篇具有很好参考价值的文章主要介绍了【STM32F407学习笔记】中断优先级管理与外部中断。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。


计算机系统中中断占有极其重要的地位,在嵌入式系统中更是如此。中断机制能让计算机有效合理的发挥效能和提高效率。
涉及外设:EXIT外部中断,NVIC内嵌向量中断控制器。

1. 中断介绍

1.1 中断的概念

计算机在执行程序的过程中,当出现异常情况或特殊情况时,计算机停止现在程序的运行,转向对这些异常情况或特殊请求的处理,处理结束后再返回到现在程序的间断处,这就是“中断”。
中断优先级:当有多个中断源同时申请中断时,CPU会根据中断源的轻重缓急进行裁决,优先响应更加紧急的中断源。

1.2 中断的产生

CPU处理数据的速度是很快的,但是与CPU相连的外设速度却很慢。比如打印机的速度就和CPU的速度相差很多,在没有中断技术时当打印机在执行打印操作时CPU就只能等待打印机操作完成,它才能处理其他事情,这样CPU的效率将大大降低。有了中断技术后CPU将立即返回主程序处理其他的事情,这样大大提高了CPU的效率。
stm32f4 中断等级,STM32学习,stm32,单片机,学习
其实中断技术不仅仅是为了适应外部设备速度不匹配问题,它还在实时控制系统中,要求CPU能即时响应外来信号的请求,并能完成各种相应的操作。也就是说,中断还可以处理一些比较紧急的事情,STM32中的中断一般都是用于此情况,例如STM32怎么及时的检测按键的按下,串口接收数据怎么及时处理,都是通过中断实现的。

1.3 中断处理的流程

不同设备的中断处理方法不同,但是它们程序的流程却是类似的,一般中断处理的流程分为四大部分:保护现场、中断服务、恢复现场和中断返回。中断处理流程图如图所示:
stm32f4 中断等级,STM32学习,stm32,单片机,学习

  • 保护现场
    保护现场有两个含义:其一时保存程序的断点;其二是保存通用寄存器和状态寄存器的内容(压栈)。在STM32中这一步不需要操作,由硬件实现。
  • 中断服务
    不同的中断,中断服务程序处理方法也不同。中断服务程序也是我们需要重点设计和编写的。
  • 恢复现场
    这是中断程序的结尾部分,要求在退出服务程序前,将原程序中断时的“现场”恢复到原来的寄存器(出栈)。在STM32中这一步不需要操作,由硬件实现。
  • 中断返回
  • 中断服务程序的最后一条指令通常是一条中断返回指令,使其返回到原程序的断点处,以便继续执行原程序。

2. STM32内嵌向量中断控制器

对于微控制器(MCU),中断也是一种常见的特性。MCU中的终端一般是由硬件(如外部和外部输入引脚)产生的事件,当外设或硬件需要处理器的服务,一般会出现下面的流程:
1)处理器确认外设的中断请求。
2)处理器暂停执行当前的任务。
3)处理器执行外设的中断服务程序(ISR),若有必要可以选择由软件清楚中断请求。
4)处理器继续执行之前暂停的任务。
所有CortexM处理器都会提供一个用于中断处理的嵌套向量中断控制寄存器(NVIC)。除了中断请求,还有其它服务的事件,将其称为“异常”。异常的概念很广泛,中断其实就是异常的一种,也可以说中断就是异常。NVIC接收多个中断源产生的中断请求如图中所示:
stm32f4 中断等级,STM32学习,stm32,单片机,学习
Cortex-M4的NVIC支持最多240个IRQ(中断请求)1个不可屏蔽中断(NMI)一个SysTick定时器中断以及多个系统异常,一共256个中断。多数IRQ由定时器、I/O端口和通信接口(如USART)等外设产生。NMI通常由看门狗定时器或掉电检测器等外设产生,其余的异常则是来自处理器内核,中断还可以利用软件生成。

2.1 NVIC控制器的寄存器

Cortex-M4的NVIC共支持256个中断,其中包含16个内核中断和240个外部中断。但是STM32F4并没有使用Cortex-M4内核的所有中断,而是只使用了92个中断,其中有10个不可屏蔽中断,82个可屏蔽中断,具有16级可编程中断优先级,82个可屏蔽中断的打开与关闭、挂起等,都是被寄存器控制,这些寄存器都已被标准封装成NVIC_Type的结构体,如图所示:
stm32f4 中断等级,STM32学习,stm32,单片机,学习
ISER[8]Interrupt Set-Enable Registers 中断使能寄存器组。STM32F4的可屏蔽中断最多只有82个,所以对我们来说,有用的就是三个(ISER[0~2]),总共可以表示96个中断。STM32F4只用了前82个。ISER[0]的bit0 ~ 31分别对应中断0 ~ 31;ISER[1[的bit0 ~31 对应终端32 ~63;ISER[2]的bit0 ~17对应中断64 ~ 81;总共82个中断。要使能某个中断,必须设置相应的ISER位为1,使该中断被使能(仅仅是使能,还要配合中断分组、屏蔽、IO口映射等设置才算是一个完整的中断设置)。
ICER[8]Interrupt Clear-Enable Registers 中断失能寄存器组。该寄存器的作用与ISER的作用是相反的,用来清除某个中断的使能的。这里要专门设置一个ICER来清除中断位,而不是向ISER写0来清除,这是因为NVIC的这些寄存器都是写1有效,写0是无效的。
ISPR[8]Interrupt Set-Pending Registers 中断挂起寄存器组。每个位对应的中断和ISER是相同的。通过写1,可以将正在进行的中断挂起,而执行同级或更高优先级的中断。写0是无效的。
ICPR[8]Interrupt Clear-Pending Registers 中断解挂寄存器组。该寄存器的作用与ISPR的作用是相反的。通过写1,可以将挂起的中断解挂。
IABR[8]Interrupt Active Bit Registers 中断激活标志位寄存器组。如果某位为1,则表示该位所对应的中断正在被执行。这是一个只读寄存器,通过它可以知道当前正在执行的中断是哪一个。中断执行完了之后由硬件自动清0。
IP[240]Interrupt Priority Registers 中断优先级控制的寄存器组。这个寄存器组相当重要!STM32F4的中断分组与这个今存其密切相关。IP寄存器由240个8bit的寄存器组成,每个可屏蔽中断占用8bit,这样总共可以表示240个可屏蔽中断。而STM32F4只用到了其中的82个。IP[0] ~ IP[81]分别对应中断0 ~ 81。而每个可屏蔽中断占用的8bit并没有全部使用,而是只用了高4位,这4位又分为抢占优先级响应优先级。抢占优先级在前,响应优先级在后。而这两个优先级各占几个位又要根据SCB->AIRCR中的中断分组设置来决定。

2.2 中断管理方法

STM32F4将中断分为5组,组0 ~ 4。该分组的设置是由SCB->AIRCR寄存器的bit10 ~ 8来确定的。设置了这个寄存器后,可以确定每个中断响应优先级,和抢占优先级占多少位。对于每个中断都有一个IP寄存器,位 [ 7 : 4 ]在SB->AIRCR确定好分组后,就可以确定分配结果。
具体分配关系如图所示:
stm32f4 中断等级,STM32学习,stm32,单片机,学习
中断优先级定义

  • 优先级的数值越小优先级的级别越高
  • 抢占优先级的优先级始终高于响应优先级
  • 高级别的抢占优先级可以打断低级别抢占优先级中断
  • 两个中断抢占优先级相同时,高级别的响应优先级不能打断低级别响应优先级,但处理器优先处理响应优先级最高的。
  • 两个中断抢占优先级相同,响应优先级相同,根据中断先发生就先执行。
    举例:
    设置中断优先级分组为2(2位抢占优先级,2位响应优先级)
    中断A:抢占优先级2,响应优先级1
    中断B:抢占优先级3,响应优先级0
    中断C:抢占优先级2,响应优先级0
    那么这三个中断的优先级顺序为:中断C>中断A>中断B。并且中断A和C都可以打断中断B,而中断A和C不可以互相打断。

2.3 中断的配置

中断管理的具体配置流程:

  1. 配置中断优先级分组(一个程序中,中断优先级分组只能配置一次,程序执行时中断分组不能更改)
  2. 配置对应外设中断(中断引脚,优先级)
  3. 编写对应的中断服务函数(对中断进行处理)
    中断分组管理函数如下
    void NVIC_PriorityGroupConfig(uint32_t NVIC_PriorityGroup)
    {
      /* Check the parameters */
      assert_param(IS_NVIC_PRIORITY_GROUP(NVIC_PriorityGroup));
      
      /* Set the PRIGROUP[10:8] bits according to NVIC_PriorityGroup value */
      SCB->AIRCR = AIRCR_VECTKEY_MASK | NVIC_PriorityGroup;
    }
    

STM32F4的中断优先级可以分为以下五组:
stm32f4 中断等级,STM32学习,stm32,单片机,学习
设置好了系统中断分组,对于每个中断我们需要确定它们的抢占优先级和响应优先级,通过中断初始化函数进行设置:

void NVIC_Init(NVIC_InitTypeDef* NVIC_InitStruct)

其中NVIC_InitTypeDef是一个结构体,成员变量如下:
stm32f4 中断等级,STM32学习,stm32,单片机,学习
这些成员变量的含义为:

  • NVIC_IRQChannel:定义初始化的是哪个中断:
    如图中所示为STM32F40的所有中断请求(IRQ)
    stm32f4 中断等级,STM32学习,stm32,单片机,学习
  • NVIC_IRQChannelPreemptionPriority:该中断的抢占优先级
  • NVIC_IRQChannelSubPriority:该中断的响应优先级
  • NVIC_IRQChannelCmd:该中断的中断通道是否使能

3. EXTI外部中断

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

  • 支持的触发方式:上升沿/下降沿/双边沿/软件触发
  • 支持的GPIO口:所有GPIO口,但是相同的Pin不能同时触发中断(比如:PA1, PB1 不能同时触发中断)
  • 通道数:23个包括:16个GPIO_Pin,外加PVD输出 、RTC闹钟、USB OTG HS唤醒、以太网唤醒、RTC入侵和时间戳事件、RTC唤醒事件。
  • 触发响应方式:中断响应/事件响应

3.1 EXTI基本结构

EXTI的基本结构如图中所示:stm32f4 中断等级,STM32学习,stm32,单片机,学习
首先是GPIOA,GPIOB,…外部中断输入GPIO口,而且每个GPIO口都有16个引脚,如果每个引脚都对应EXTI的一个通道,那么EXTI的16个GPIO_Pin通道就不够用了。因此有一个中断引脚选择的电路模块(一个数据选择器)(在STM32F1中为AFIO),而在STM32F4中为SYSCFG_EXTICRx,它可以在从前面的GPIO口外设的16个引脚里面选择其中一个GPIO口的引脚连接到后面的EXTI的通道里。经过EXTI边沿检测及控制电路后,分为了两种输出,一部分是用来触发NVIC中断,一部分用于其他外设。

3.2 SYSCFG_EXTICRx 外部中断配置寄存器

如图中所示为SYSCFG_EXTICR外部中断配置寄存器的结构
stm32f4 中断等级,STM32学习,stm32,单片机,学习
如图中所示SYSCFG_EXTICR1寄存器的EXTIx[3:0]:EXTIx配置(x=0到3)这些位通过软件写入,用以选择EXTIx外部中断源的输入。

  • 0000:PA[x]引脚
    0001:PB[x]引脚

    1000:PI[x]引脚
  • SYS_CFG_EXTICR2寄存器的EXTIx[3:0]:EXTIx配置(x=4到7)这些位通过软件写入,用以选择EXTIx外部中断的输入。
    0000:PA[x]引脚
    0001:PB[x]引脚

    1000:PI[x]引脚
  • SYS_CFG_EXTICR3寄存器的EXTIx[3:0]:EXTIx配置(x=8到11)这些位通过软件写入,用以选择EXTIx外部中断的输入。
    0000:PA[x]引脚
    0001:PB[x]引脚

    1000:PI[x]引脚
  • SYS_CFG_EXTICR4寄存器的EXTIx[3:0]:EXTIx配置(x=12到15)这些位通过软件写入,用以选择EXTIx外部中断的输入。
    0000:PA[x]引脚
    0001:PB[x]引脚

    0111:PH[x]引脚
    注意PI[15:12]未使用
    在STM32F4的库函数中对于这个配置的库函数为:
SYSCFG_EXTILineConfig()

3.3 EXTI 框图

stm32f4 中断等级,STM32学习,stm32,单片机,学习
EXTI的右边是23个输入线,输入信号先进入边沿检测电路,选择上升沿触发或下降沿触发或者两个都触发,接着触发信号进入或门与软件中断事件信号相或(这里就是说软件中断事件也可以触发EXTI中断),然后信号兵分两路。首先是上方,当中断屏蔽寄存器给1,则允许中断,然后进入挂起请求寄存器,最后进入NVIC中断控制器。下方信号,当事件屏蔽寄存器为1,则允许事件触发,通过脉冲发生器(输出一个脉冲,用来触发其他外设的动作)输出到其他外设。
在STM32F4的库函数中,外部中断EXTI的中断请求有:EXTI0_IRQn、EXTI1_IRQn、EXTI2_IRQn、EXTI3_IRQn、EXIT4_IRQn、EXTI9_5_IRQn(即GPIOx_Pin_5 ~ GPIOx_Pin_9都是一个中断请求)、EXTI15_10_IRQn(即GPIOx_Pin_15 ~ GPIOx_Pin_10都是一个中断请求)。

4. 软件设计

使用外部中断触发中断服务。整个流程如下所示:

  • 首先是中断分组和中断优先级设置
  • 初始化EXTI外部中断:
    • 使能SYSCFG时钟,在使用外部中断时一定要先使能SYSCFG时钟
    • 初始化GPIO口,用于外部中断输入:
      • 使能GPIO时钟
      • 配置GPIO:配置引脚,输入模式,上下拉(上拉检测下降沿,下拉检测上升沿)
    • 初始化EXTI:
      • 使能EXTI时钟
      • 配置EXTI:设置EXTI外部中断源输入通道,设置中断触发,设置触发方式,使能中断
    • 设置IO口与中断线的映射关系

具体程序如下所示,程序配置PA1的下降沿触发中断,并在触发中断时通过串口向电脑打印。

/// @brief 设置中断分组和优先级
/// @param  None
void NVIC_Config(void)
{
    NVIC_InitTypeDef NVIC_InitStructure;
    NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); // 配置NVIC分组为2

    NVIC_InitStructure.NVIC_IRQChannel = EXTI1_IRQn;          // 外部中断通道1
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2; // 抢占优先级
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 2;        // 响应优先级
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;           // 外部中断通道1使能

    NVIC_Init(&NVIC_InitStructure);
}

/// @brief 初始化EXTI外部中断
/// @param  None
void EXTI_init(void)
{
    EXTI_InitTypeDef EXTI_InitStructure;
    GPIO_InitTypeDef GPIOInitStructure;

    // 使能GPIOA的时钟
    RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE);
    // 使能外设EXIT的时钟
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_EXTIT, ENABLE);
    // 使能SYSCFG时钟,在使用外部中断的时候一定要先使能SYSCFG的时钟
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_SYSCFG, ENABLE);

    GPIOInitStructure.GPIO_Pin = GPIO_Pin_1;    // 引脚号
    GPIOInitStructure.GPIO_Mode = GPIO_Mode_IN; // 输入
    GPIOInitStructure.GPIO_PuPd = GPIO_PuPd_UP; // 上拉(不工作时位高电平),检测低电平
    GPIO_Init(GPIOA, &GPIOInitStructure);

    EXTI_InitStructure.EXTI_Line = EXTI_Line1;              // EXTI1
    EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;     // 中断触发
    EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling; // 下降沿触发
    EXTI_InitStructure.EXTI_LineCmd = ENABLE;               // 使能中断
    EXTI_Init(&EXTI_InitStructure);

    SYSCFG_EXTILineConfig(EXTI_PortSourceGPIOA, EXTI_PinSource1); // 设置IO口与中断线的映射关系
}

/// @brief EXTI1中断服务函数
/// @param  
void EXTI1_IRQHandler(void)
{
  // 判断中断线中断状态,查看中断是否发生 
  if(EXTI_GetFlagStatus(EXTI_Line1)==SET)
  {
    printf("[it]EXTI1\r\n");
  }
  // 清除中断标志
  EXTI_ClearITPendingBit(EXTI_Line1);
}

5. 总结

外部中断常用的函数:

//设置IO口与中断线的映射关系
void SYSCFG_EXTILineConfig(uint8_t EXTI_PortSourceGPIOx, uint8_t EXTI_PinSourcex);
//初始化中断线:触发方式等
void EXTI_Init(EXTI_InitTypeDef* EXTI_InitStruct);
//判断中断线中断状态,是否发生
ITStatus EXTI_GetITStatus(uint32_t EXTI_Line);
//清除中断线上的中断标志位
void EXTI_ClearITPendingBit(uint32_t EXTI_Line);
//使能SYSCFG时钟
//这个函数非常重要,在使用外部中断的时候一定要先使能SYSCFG时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_SYSCFG, ENABLE);

外部中断的一般配置步骤:文章来源地址https://www.toymoban.com/news/detail-783484.html

  1. 配置中断分组(NVIC),并使能中断。
    NVIC_Init();
  2. 使能SYSCFG时钟:
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_SYSCFG, ENABLE);
  3. 初始化IO口为输入。
    GPIO_Init();
  4. 设置IO口与中断线的映射关系。
    void SYSCFG_EXTILineConfig();
  5. 初始化线上中断,设置触发条件等。
    EXTI_Init();
  6. 编写中断服务函数。
    EXTIx_IRQHandler();
  7. 清除中断标志位
    EXTI_ClearITPendingBit();

到了这里,关于【STM32F407学习笔记】中断优先级管理与外部中断的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • STM32F407的CAN2无法进入can接收中断的解决办法

    这个问题困扰了我两天,今天偶然看到一篇文章有讲这个:STM32 CAN1 CAN2 不能同时工作,最后原因竟然是。。。。 看了之后恍然大悟。下面贴上我的初始化代码: 主函数进行中断优先级分组和CAN初始化调用及使能 初始化代码: 中断服务函数: 效果展示:  CAN逻辑分析仪数据

    2024年02月13日
    浏览(39)
  • 基于STM32CubeMX和keil采用STM32F407的基本定时器中断实现LED闪烁

    定时器有三种,基本定时器,通用定时器,以及高级定时器。 这篇博客以最简单的基本定时器为例,实现LED的闪烁。 后面两种定时器的用法后面再写。 实现功能: TIM6控制LED每隔0.5s变一次状态。 TIM7控制LED1常量2s后熄灭。 因为都是用到LED,所以和上一篇基于STM32CubeMX与keil采

    2024年02月04日
    浏览(53)
  • STM32F407移植OpenHarmony笔记1

    参考文档: OpenAtom OpenHarmony width=device-width,initial-scale=1.0 https://docs.openharmony.cn/pages/v3.2/zh-cn/device-dev/get-code/gettools-acquire.md/ 搭建环境 安装linux系统: Ubuntu 22.04.2 LTS (GNU/Linux 5.15.0-91-generic x86_64) 下载源代码:我选择的是V3.2.4版本 https://repo.huaweicloud.com/openharmony/os/3.2.4/code-v3.2.4-Rele

    2024年01月25日
    浏览(46)
  • STM32F407系列硬件I2C笔记

    STM32F407系列有3个硬件I2C: I2C1:该接口位于GPIOB引脚上,包括PB6(I2C1_SCL)和PB7(I2C1_SDA)。 I2C2:该接口位于GPIOB引脚上,包括PB10(I2C2_SCL)和PB11(I2C2_SDA)。 I2C3:该接口位于GPIOA和GPIOC引脚上,包括PA8(I2C3_SCL)和PC9(I2C3_SDA)。   硬件I2C的速度比软件I2C更快,硬件I2C通常可以

    2024年02月04日
    浏览(40)
  • 洋桃电子STM32F407单片机入门教程笔记九:低功耗模式

      此文档作为对洋桃电子STM32F407单片机视频的整理,B站链接: 第28集)低功耗模式_哔哩哔哩_bilibili         在之前的程序里应用程序在while(1)主循环中反复执行,ARM内核以100%的功率工作。这样的设计简单稳定,内核全速运行的功耗也只有几十毫安,对于外接电源的设备

    2024年01月23日
    浏览(51)
  • 洋桃电子STM32F407单片机入门教程笔记一:RCC时钟设置

    此文档作为对洋桃电子STM32F407单片机视频的整理,B站链接:2023更新 STM32入门F4= STM32F407单片机入门教程=WIFI连接阿里云物联网+CubeMX+HAL库+TFT彩屏+杜洋主讲_哔哩哔哩_bilibili 由于单片机内部的时钟结构都是相互关联的,一个时钟源出发可以供给多个功能,类似于树根、树杆、树

    2024年02月04日
    浏览(37)
  • 从STM32F407到AT32F407(一)

    雅特力公司的MCU有着性能超群,价格优越的巨大优势,缺点是相关资料少一些,我们可以充分利用ST的现有资源来开发它。 我用雅特力的STM32F437开发板,使用原子 stm32f407的开发板自带程序,测试串口程序,原设定串口波特率为115200,但是输出乱码,波特率改成230400,串口输

    2024年02月02日
    浏览(50)
  • stm32f407VET6 系统学习 day01 GPIO 配置

    GPIO,即通用I/O(输入/输出)端口,是STM32可控制的引脚。STM32芯片的GPIO引脚与外部设备连接起来,可实现与外部通讯、控制外部硬件或者采集外部硬件数据的功能。 STM32F407有7组IO。分别为GPIOA~GPIOG,每组IO有16个IO口,共有112个IO口  通常称为 PAx、PBx、PCx、PDx、PEx、PFx、PGx,其中

    2023年04月09日
    浏览(41)
  • 【STM32】BLDC驱动&控制开发笔记 | 07_SPI通信测试 - STM32F407用SPI配置DRV8323驱动芯片

    最近在埋头搞STM32 + 无刷直流电机控制,想实现用自己的STM32F407VGT6芯片板子,外加一块驱动板(目前选用到TI的DRV8302或者DRV8323驱动芯片),搞定电机驱动,最后实现比较好的控制效果。如果不是同一块芯片的同学也不用急着走,大体上都是可借鉴哒~ 本文主要实现使用SPI通信

    2024年02月08日
    浏览(46)
  • STM32F407的介绍

    内核 32位 高性能ARM Cortex-M4处理器 时钟: 高达168MHz,实际还可以超频一点点 stm32f407的主频通过PLL倍频后能够达到168MHz,而且芯片内置一个16MHz的晶振和一个32KHz的晶振,可以满足不同功耗的需求。 支持FPU(浮点运算)和DSP指令 144引脚 114个IO口 存储器容量: 1024K FLASH, 192K

    2024年02月10日
    浏览(42)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包