STM32之NVIC的深入详解

STM32之NVIC的深入详解STM32NVIC中断嵌套

大家好,又见面了,我是你们的朋友全栈君。

  朋友们,如果你需要在STM32上移植RTOS,那么首先必须深入理解它的中断系统。什么是NVIC?即嵌套向量中断控制器(Nested Vectored Interrupt Controller)STM32的中有一个强大而方便的NVIC,它是属于Cortex内核的器件,不可屏蔽中断 (NMI)和外部中断都由它来处理,而SYSTICK不是由 NVIC来控制的。

  特性:

  60个可屏蔽中断通道(不包含16Cortex-M3的中断线)

  16个可编程的优先等级(使用了4位中断优先级)

  低延迟的异常和中断处理;

  电源管理控制;

  系统控制寄存器的实现;


1.中断优先级分组

  STM32(Cortex-M3)中有两个优先级的概念抢占式优先级和响应优先级,有人把响应优先级称作亚优先级副优先级,每个中断源都需要被指定这两种优先级。 

      具有高抢占式优先级的中断可以在具有低抢占式优先级的中断处理过程中被响应,即中断嵌套,或者说高抢占式优先级的中断可以嵌套在低抢占式优先级的中断中。

      当两个中断源的抢占式优先级相同时,这两个中断将没有嵌套关系,当一个中断到来后,如果正在处理另一个中断,这个后到来的中断就要等到前一个中断处理完之后才能被处理。如果这两个中断同时到达,则中断控制器根据他们的响应优先级高低来决定先处理哪一个;如果他们的抢占式优先级和响应优先级都相等,则根据他们在中断表中的排位顺序决定先处理哪一个。

    Cortex内核具有强大的异常响应系统,它把能够打断当前代码执行流程的事件分为异常(exception)和中断(interrupt),并把它们用一个表管理起来,编号为0~15的称为内核异常,而16以上的则称为外部中断,这个表就称为中断向量表。

       正是因为每个中断源都需要被指定这两种优先级,就需要有相应的寄存器位记录每个中断的优先级;在Cortex-M3中定义了8个比特位用于设置中断源的优先级,这8个比特位可以有8种分配方式,如下:

1. 所有8位用于指定响应优先级 

2. 最高1位用于指定抢占式优先级,最低7位用于指定响应优先级

3. 最高2位用于指定抢占式优先级,最低6位用于指定响应优先级

4. 最高3位用于指定抢占式优先级,最低5位用于指定响应优先级

5. 最高4位用于指定抢占式优先级,最低4位用于指定响应优先级

6. 最高5位用于指定抢占式优先级,最低3位用于指定响应优先级

7. 最高6位用于指定抢占式优先级,最低2位用于指定响应优先级

8. 最高7位用于指定抢占式优先级,最低1位用于指定响应优先级

       以上便是优先级分组的概念,但是Cortex-M3允许具有较少中断源时使用较少的寄存器位指定中断源的优先级。

      而STM32对这个表重新进行了编排,把编号从-36的中断向量定义为系统异常,编号为负的内核异常不能被设置优先级,如复位(Reset)、不可屏蔽中断 (NMI)、硬错误(Hardfault)。从编号 7开始的为外部中断,这些中断的优先级都是可以用户更改的。详细的 STM32中断向量号可以在startup_stm32f10x_XX.s中查找。

因此STM32把指定中断优先级的寄存器位减少到4位,这4个寄存器位的分组方式如下:

0组:所有4位用于指定响应优先级(16种)

1组:最高1位用于指定抢占式优先级,最低3位用于指定响应优先级(8)

2组:最高2位用于指定抢占式优先级,最低2位用于指定响应优先级(4)

3组:最高3位用于指定抢占式优先级,最低1位用于指定响应优先级(2)

4组:所有4位用于指定抢占式优先级

  这里便对于于文章最前提到的固件库里相关的函数了——NVIC_PriorityGroupConfig(u32 NVIC_PriorityGroup),函数的参数共有5种:

这个函数的参数(NVIC_PriorityGroup)有下列5种:

NVIC_PriorityGroup_0 => 选择第0

NVIC_PriorityGroup_1 => 选择第1

NVIC_PriorityGroup_2 => 选择第2

NVIC_PriorityGroup_3 => 选择第3

NVIC_PriorityGroup_4 => 选择第4

      这其实也很好理解,比如选择NVIC_PriorityGroup_1,那么抢占式优先级便占一位,也就是说可以有2^1个级别,可以设置为01,而响应优先级则占3位,也就是说可以有2^3个选择,可以设置为0~7;总共来说就可以区别>16种优先级了。

 //NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;

 //NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;

        举个例子吧,假如现在有4个外部中断,还有一个EXTI9_5中断,那么如果选择优先级分组为第1组,那么抢占式优先级便只有两种,5个中断就至少有3个在抢占式优先级上是相同的优先级上,其他两个在令一优先级别。接着设置响应优先级可以有8种选择;假如现在同时有两个抢占式优先级别相同的中断发生,那么处理的顺序是谁的响应优先级高则谁优先进入中断,另外这点是需要注意的,如果此时进入这个中断之后又来了一个抢占式优先级相同但是响应优先级更高的中断,这时也是不会打断已有的中断的

void NVIC_Config(void)

{

    NVIC_InitTypeDef NVIC_InitStructure;

    #ifdef  VECT_TAB_RAM

    //Set the Vector Table base location at 0x20000000 

    NVIC_SetVectorTable(NVIC_VectTab_RAM, 0x0);

    #else

    //Set the Vector Table base location at 0x08000000 

    NVIC_SetVectorTable(NVIC_VectTab_FLASH, 0x0); 

    #endif

    NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);  //中断优先级组 1组(整个系统为同一组)

    // 设置抢占优先级0~1,响应优先级0~7

    NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQn;             // TIM2 全局中断

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

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

    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;             // IRQ通道被使能

    NVIC_Init(&NVIC_InitStructure);

    //* Enable the TIM3 Interrupt

    NVIC_InitStructure.NVIC_IRQChannel = TIM3_IRQn;             // TIM3 全局中断

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

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

    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;             // IRQ通道被使能

    NVIC_Init(&NVIC_InitStructure);

    NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;           // USART1 全局中断

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

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

    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;             // IRQ通道被使能

    NVIC_Init(&NVIC_InitStructure);

}

说明:假如TIM3是正在运行的中断,如果USART1中断也发生了,则优先处理,TIM3被嵌套并挂起;如果TIM2中断发生了,则需要等到TIM3处理完之后再处理TIM2。这就是抢占优先级和响应优先级的区别。

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/140230.html原文链接:https://javaforall.net

(0)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • win10系统显示打印机未连接到服务器,win10系统无法连接到打印机的解决方法

    win10系统显示打印机未连接到服务器,win10系统无法连接到打印机的解决方法很多小伙伴都遇到过win10系统无法连接到打印机的困惑吧,一些朋友看过网上零散的win10系统无法连接到打印机的处理方法,并没有完完全全明白win10系统无法连接到打印机是如何解决的,今天小编准备了简单的解决办法,只需要按照1、右键点击开始菜单,选择弹出菜单中的“控制面板”,2、在控制面板里点击“管理工具”,如果找不到的话先将右上角的查看那方式修改为【小图标】或【大图标】的顺序即可轻松解决…

    2022年6月9日
    70
  • 解决Win10中WerFault错误报告问题

    解决Win10中WerFault错误报告问题解决Win10中的WerFault错误报告问题

    2022年6月16日
    36
  • 树的高度和深度 | 结点的高度和深度「建议收藏」

    树的高度和深度 | 结点的高度和深度「建议收藏」有个缺点,看到什么东西不管是不是重点只要说不通总是爱钻牛角尖。对于树的高度和深度(以及结点的高度和深度)看了几本不同的书,都有各自的说法,多方查证吧,花了很多时间,最后归纳一个能说服我的说法吧。(´。•ᵕ•。`)♡树的高度和深度深度是从上往下定义的,从根结点开始数,高度是从下往上定义的,从叶子结点开始数。这个涉及到结点的层数,有的教材规定根结点在第0层,有的则规定根结点在第一层。…

    2022年5月25日
    37
  • java 命令 native2ascii_java native2ascii.exe命令

    java 命令 native2ascii_java native2ascii.exe命令native2ascii.exe是Java的一个文件转码工具native2ascii.exe的语法格式:native2ascii[-reverse][-encoding编码][输入文件[输出文件]]说明:-reverse:将Unicode编码转为本地编码。-reverse-encoding编码:将指定编码转为本地编码。-encoding编码:转换为指定编码。空:转换为Unic…

    2025年10月29日
    3
  • Python爬虫常用:谷歌浏览器驱动——Chromedriver 插件安装教程

    Python爬虫常用:谷歌浏览器驱动——Chromedriver 插件安装教程我们在做爬虫的时候经常要使用谷歌浏览器驱动,今天分享下这个Chromedriver插件的安装方法。第一步、打开谷歌浏览器打开设置面板第二步、查看当前谷歌浏览器版本号第三步、点击插件下载,进去这个界面,找到跟自己谷歌浏览器版本号最相近的那一个。下载地址:插件下载这里有许多的版本,注意icons/向下的版本是无用的。选择icons/以上的版本,越靠近icons/的版本越新。第四步、找到对应版本后点击它计进入这个页面,点击notes.txt查看与Chrome版本是否对应。第五步、回

    2022年5月11日
    62
  • pytest指定用例_文件夹排列顺序自定义

    pytest指定用例_文件夹排列顺序自定义前言测试用例在设计的时候,我们一般要求不要有先后顺序,用例是可以打乱了执行的,这样才能达到测试的效果.有些同学在写用例的时候,用例写了先后顺序,有先后顺序后,后面还会有新的问题(如:上个用例返回

    2022年7月29日
    5

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号