6-STM32之NVIC 嵌套向量中断控制器

简介: 6-STM32之NVIC 嵌套向量中断控制器

6.1 NVIC简介


6.1.1 什么是中断


举个例子,中断就相当于你现在要去烧开水,在你烧水的过程中,你突然要去吃饭。这个过程就叫做中断,其实说白了中断就是做某件事中停一下去做 其他的事情。


6.1.2 嵌套向量中断控制器

( Nested Vectored Interrupt Controller )


NVIC和M4内核可以说是紧密相连的。不仅仅支持向量中断,而且对自动保存和处理器状态恢复,优先级等都有很大的管理,这里推荐你们如果有兴趣的话可以看一下,清华大学出版社出版的《ARM Cortex-M3与RM Cortex-M4权威指南》。当然了呀。这点知道就行了,反正又不是上大学,考试啥的,主要是代码,待会给你们好好屡屡。下面来介绍一下:


1)、

CM4内核支持256个中断,其中包含了16个内核中断和240个外部中断,并且具有256级的可编程中断设置。

2)、

STM32F4并没有使用CM4内核的全部中断定义,而是只用了它的一部分。-STM32F42xx/STM32F43xx则总共有96个中断

3)、

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


6.1.2 中断类型


STM32F4系列中系统异常有 10 个和91个外部中断,具有可编程的中断优先级有16个。除了个别异常的优先级被定死外,其它异常的优先级(用4位表示中断的优先级)都是可编程的。有关具体的系统异常和外部中断可在标准库文件 stm32f4xx.h 这个头文件看到,在 IRQn_Type 这个结构体里面包含了 这个系列全部的异常声明。大家可以去看看。


1-10个异常中断


从上面这个图中可以看到,Reset、NMI、HardFault异常的优先级是固定不变的,但是剩余的优先级都是可以更改的。

有一点大家需要知道的是,STM32中断优先级只使用了M4内核的高四位,低四位是保留的这点大家要清楚。

640.png


2、外设可屏蔽中断

这个图具体的大家可以看一下数据手册。


6.1.3 NVIC中断管理方法


1、中断优先级分组


STM32系列的单片机有优先级管理这个概念,咋说呢,举个例子来说吧,比如从1到10,数字越大代表的优先级越低,那么加入我的数字小,你的数字大,就说明有吃的喝的先给我,至于你等着,等我吃饱喝足在赏赐给你点,如果中间我不愿意让你吃了,再给你抢回来(谁让我级别比你高呢,其实就和平时的阶级一个概念)(可能不太恰当,但就是这个意思吧)。这就是优先级。

其实吧,STM32又加了一个,一个是抢占优先级、一个是响应优先级。抢占优先级救赎主优先级,响应优先级就是次优先级也可以叫做子优先级。都是先执行抢占优先级在执行响应优先级。就是我上面说的那个意思。

抢占优先级的概念等同于51单片机中的中断。假设有两中断先后触发,已经在执行的中断先占优先级如果没有后触发的中断先占优先级更高,就会先处理先占优先级高的中断。也就是说又有较高的先占优先级的中断可以打断先占优先级较低的中断。这是实现中断嵌套的基础。

响应(子)优先级只在同一抢占优先级的中断同时触发时起作用,先占优先级相同,则优先执行响应(子)优先级较高的中断。响应(子)优先级不会造成中断嵌套。如果中断的两个优先级都一致,则优先执行位于中断向量表中位置较高的中断(也就是标号越小,优先级越高)。

如下图:优先级:

分组配置是在寄存器SCB_AIRCR(Application interrupt and reset control register:应用中断和复位控制寄存器)中配置:


640.png


2、中断优先级管理方法


这个在上面已经说过了这里进行了一个总结:

1)抢占优先级较高的中断是可以打断正在进行的抢占优先级较低的中断;

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

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

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

5)如果两个中断的抢占优先级和响应优先级都是一样的话,且同时请求,则根据中断表中的排位顺序决定。


所以就可以得到下面这个图:

在这里在举个例子吧。


在这里特别说明一点:


6.2 常用库函数


1、中断优先级分组:

这里操作的是寄存器:SCB_ AIRCR[10:8]位段


void NVIC_PriorityGroupConfig(uint32_t NVIC_PriorityGroup);

具体内部函数是这样子的:


void NVIC_PriorityGroupConfig(uint32_t NVIC_PriorityGroup){  assert_param(IS_NVIC_PRIORITY_GROUP(NVIC_PriorityGroup));  SCB->AIRCR = AIRCR_VECTKEY_MASK | NVIC_PriorityGroup;}


    NVIC_PriorityGroup : 组用的屏蔽字。定义如下:#define NVIC_PriorityGroup_0         ((uint32_t)0x700) /*!< 0 抢占优先级的位                                                            4 响应优先级位 */#define NVIC_PriorityGroup_1         ((uint32_t)0x600) /*!< 1 抢占优先级的位                                                            3 响应优先级 */#define NVIC_PriorityGroup_2         ((uint32_t)0x500) /*!< 2 抢占优先级的位                                                            2 响应优先级 */#define NVIC_PriorityGroup_3         ((uint32_t)0x400) /*!< 3 抢占优先级的位                                                            1 响应优先级 */#define NVIC_PriorityGroup_4         ((uint32_t)0x300) /*!< 4 抢占优先级的位                                                            0 响应优先级 */例如:中断优先级寄存器定义优先级高3位,抢占优先级占1位,响应优先级占3位。NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1)这时候中断优先级可以是0或者1,响应优先级可以是0~7;


    2、中断优先级设置


    中断优先级设置以及使能函数用于配置中断向量表中的一个抢占优先级和响应优先级。


      void NVIC_Init(NVIC_InitTypeDef* NVIC_InitStruct);

      这是一NVIC个结构体指针的初始化,具体的寄存器定义和初始化定义如下:

        typedef struct{  __IO uint32_t ISER[8];                    uint32_t RESERVED0[24];                                     __IO uint32_t ICER[8];                           uint32_t RSERVED1[24];                                      __IO uint32_t ISPR[8];                            uint32_t RESERVED2[24];                                     __IO uint32_t ICPR[8];                          uint32_t RESERVED3[24];                                     __IO uint32_t IABR[8];                            uint32_t RESERVED4[56];                                     __IO uint8_t  IP[240];                            uint32_t RESERVED5[644];                                    __O  uint32_t STIR;                         }  NVIC_Type;

        涉及到的寄存器:这里看看就行,咱就是来操作库函数的,所以知道就行

          __IO uint8_t  IP[240]; //中断优先级控制的寄存器组__IO uint32_t ISER[8]; //中断使能寄存器组__IO uint32_t ICER[8]; //中断失能寄存器组__IO uint32_t ISPR[8]; //中断挂起寄存器组__IO uint32_t ICPR[8]; //中断解挂寄存器组__IO uint32_t IABR[8]; //中断激活标志位寄存器组typedef struct{  uint8_t NVIC_IRQChannel; //设置中断通道  uint8_t NVIC_IRQChannelPreemptionPriority;//设置抢占优先级  uint8_t NVIC_IRQChannelSubPriority; //设置响应优先级  FunctionalState NVIC_IRQChannelCmd; //使能/禁止} NVIC_InitTypeDef;

          举个例子:

          比如我设置串口一的中断,抢占优先级为1,响应优先级是2,那就应该这样设置:

            NVIC_InitTypeDef   NVIC_InitStructure;NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;// 37 串口1中断NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=1;// 抢占优先级为1NVIC_InitStructure.NVIC_IRQChannelSubPriority = 2;//响应优先级为2NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;//IRQ通道使能NVIC_Init(&NVIC_InitStructure);  //根据上面指定的参数初始化NVIC寄存器


            6.3 举个小栗子


            1-中断优先级设置步骤

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


            void NVIC_PriorityGroupConfig(uint32_t NVIC_PriorityGroup);

            整个系统执行过程中,只设置一次中断分组。这个要知道。

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


            void NVIC_Init(NVIC_InitTypeDef* NVIC_InitStruct);

            3)如果需要挂起/解挂,查看中断当前激活状态,分别调用相关函数即可。用的不多!

            一般情况下片上外设中断管理只需要第1步和第2步!


            2-小栗子

            1-编写NVIC中断初始化程序实现如下功能:

            1、设置中断优先级组为1组

            2、设置外部中断1的抢占优先级为0,响应优先级为2

            3、设置定时器1的溢出更新中断的抢占优先级为1,响应优先级为4

            4、设置USART1的抢占优先级为1,响应优先级为5

            并说明当同时出现以上3个中断请求时,中断服务程序执行的顺序?


            640.png

            640.png




            640.png


            相关文章
            |
            6月前
            |
            芯片
            STM32F103标准外设库——中断应用/事件控制器(七)
            STM32F103标准外设库——中断应用/事件控制器(七)
            434 0
            STM32F103标准外设库——中断应用/事件控制器(七)
            |
            6月前
            毕业设计 基于stm32舞台彩灯控制器设计app控制系统
            毕业设计 基于stm32舞台彩灯控制器设计app控制系统
            115 0
            |
            传感器 开发工具 C语言
            EXTI外部中断介绍(内置1.中断系统+2.中断执行流程+3.STM32中断+4.NVIC基本结构+5.NVIC优先级分组+6.EXTI简介+7.EXTI基本结构...)
            EXTI外部中断介绍(内置1.中断系统+2.中断执行流程+3.STM32中断+4.NVIC基本结构+5.NVIC优先级分组+6.EXTI简介+7.EXTI基本结构...)
            322 0
            EXTI外部中断介绍(内置1.中断系统+2.中断执行流程+3.STM32中断+4.NVIC基本结构+5.NVIC优先级分组+6.EXTI简介+7.EXTI基本结构...)
            |
            4月前
            stm32f407探索者开发板(十五)——NVIC中断优先级管理
            stm32f407探索者开发板(十五)——NVIC中断优先级管理
            201 0
            |
            芯片
            stm32的NVIC是什么?
            stm32的NVIC是什么?
            192 0
            【STM32】 DMA模块控制器的保姆笔记总结
            DMA 全称Direct Memory Access,即直接存储器访问。 DMA传输将数据从一个地址空间复制到另一个地址空间。
            【STM32】 DMA模块控制器的保姆笔记总结
            |
            内存技术
            《stm32嵌入式系统开发实战指南》一1.3 STM32互联型嵌入式控制器
            本节书摘来自华章出版社《stm32嵌入式系统开发实战指南》一书中的第1章,第1.3节,作者 李志明 檀永 徐石明,更多章节内容可以访问云栖社区“华章计算机”公众号查看
            2482 0
            |
            5月前
            使用STM32F103标准库实现定时器控制LED点亮和关闭
            通过这篇博客,我们学习了如何使用STM32F103标准库,通过定时器来控制LED的点亮和关闭。我们配置了定时器中断,并在中断处理函数中实现了LED状态的切换。这是一个基础且实用的例子,适合初学者了解STM32定时器和中断的使用。 希望这篇博客对你有所帮助。如果有任何问题或建议,欢迎在评论区留言。
            450 2
            |
            4月前
            stm32f407探索者开发板(十七)——串口寄存器库函数配置方法
            stm32f407探索者开发板(十七)——串口寄存器库函数配置方法
            722 0
            |
            5月前
            |
            IDE 开发工具
            使用STM32F103标准库实现自定义键盘
            通过本文,我们学习了如何使用STM32F103标准库实现一个简单的自定义键盘。我们首先初始化了GPIO引脚,然后实现了一个扫描函数来检测按键状态。这个项目不仅能够帮助我们理解STM32的GPIO配置和按键扫描原理,还可以作为进一步学习中断处理和低功耗设计的基础。希望本文对你有所帮助,祝你在嵌入式开发的道路上不断进步!
            510 4