STM32F1xx官方资料:
《STM32中文参考手册V10》-第9章 中断和事件

Cortex-M3内核支持256个中断,其中包含了16个内核中断(异常)和240个外部中断,并且具有256级的可编程中断设置。但是,STM32并没有使用CM3内核的全部东西,而是只用了它的一部分。STM32有84个中断,包括16个内核中断(异常)和68个可屏蔽中断,具有16级可编程的中断优先级。而STM32F103系列上面,16个内核中断(异常)不变,而可屏蔽中断只有60个(在107系列才有68个)。

注意一下:CM3的外部中断和STM32的外部中断不是一个概念。CM3:除了内核异常之外的都是外部中断;STM32:外部中断EXTI只有6个

其实,内核中断也叫内核异常。

  • 中断是指系统停止当前正在运行的程序转而其他服务,可能是程序接收了比自身高优先级的请求,或者是人为设置中断,中断是属于正常现象。
  • 异常是指由于cpu本身故障、程序故障或者请求服务等引起的错误,异常属于不正常现象。

因此,下面就直接介绍一下STM32F103系列的16个内核中断(异常)、60个中断:

在中断向量表中从优先级7-66(中断号从0-59)代表着STM32F103的60个中断。优先级号越小,优先级越高。当表中的某处异常或中断被触发,程序计数器指针(PC)将跳转到该异常或中断的地址处执行,该地址处存放这一条跳转指令,跳转到该异常或中断的服务函数处执行相应的功能。因此,异常和中断向量表只能用汇编语言编写。

在MDK中,有标准的异常和中断向量表文件可以使用(startup_stm32f10x_hd.s),在其中标明了中断处理函数的名称,不能随意定义。而中断通道NVIC_IRQChannel(即IRQn_Type类型)是在stm32f10x.h文件中进行了宏定义。

什么是NVIC?即嵌套向量中断控制器(Nested Vectored Interrupt Controller)。CM3的中有一个强大而方便的NVIC,它是属于Cortex内核的器件,中断向量表中60个中断都由它来处理。NVIC是Cortex-M3核心的一部分,关于它的资料不在《STM32的技术参考手册》中,应查阅ARM公司的《Cortex-M3技术参考手册》Cortex-M3的向量中断统一由NVIC管理。

NVIC的核心功能是中断优先级分组、中断优先级的配置、读中断请求标志、清除中断请求标志、使能中断、清除中断等,它控制着STM32中断向量表中中断号为0-59的60个中断!!外部中断信号从核外发出,信号最终要传递到NVIC(嵌套向量中断控制器)。NVIC跟内核紧密耦合,它控制着整个芯片中断的相关功能。

STM32中断优先级分组

中断优先级分组寄存器

这60个中断,怎么管理呢?这就涉及到STM32的中断分组。STM32可以将中断分成5个组,分别为组0-4;同时,对每个中断设置一个抢占优先级和响应优先级。分组配置是由SCB->AIRCR寄存器的bit10-8来定义的。SCB->AIRCR是在哪里的呢?由于这是CM3内核定义的,在文档《Cortex-M3权威指南(中文)》中能查找到。

具体的分配关系如下所示:

AIRCR中断分组设置表
AIRCR[10:8] IP bit[7:4]分配情况 分配结果
0 111 0:4 0位抢占优先级,4位响应优先级
1 110 1:3 1位抢占优先级,3位响应优先级
2 101 2:2 2位抢占优先级,2位响应优先级
3 100 3:1 3位抢占优先级,1位响应优先级
4 011 4:0 4位抢占优先级,0位响应优先级

其中AIRCR寄存器来确定是用哪种分组,IP寄存器是相对应于那种分组抢占优先级和响应优先级的分配比例。例如组设置成3,那么此时所有的60个中断优先寄存器高4位中的最高3位是抢占优先级,低1位为响应优先级。CM3中定义了8个Bit用于设置中断源的优先级,而STM32只选用其中的4个Bit。

抢占优先级的级别高于响应优先级,而数值越小所代表的的优先级越高。

介绍一下抢占优先级、响应优先级的区别:

  1. 高优先级的抢占优先级是可以打断正在进行的低抢占优先级中断的;
  2. 抢占优先级相同的中断,高响应优先级不可以打断低响应优先级的中断;
  3. 抢占优先级相同的中断,当两个中断同时发生的情况下,哪个响应优先级高,哪个先执行;
  4. 如果两个中断的抢占优先级和响应优先级都是一样的话,则看哪个中断先发生就先执行;

除此之外有两点需要注意:

  1. 打断的情况只会与抢占优先级有关, 和响应优先级无关!
  2. 一般情况下,系统代码执行过程中,只设置一次中断优先级分组,比如分组2,设置好分组之后一般不会再改变分组。随意改变分组会导致中断管理混乱,程序出现意想不到的执行结果。

中断优先级分组库函数

CM3核的优先级分组方式,使用的设置函数NVIC_SetPriorityGrouping()

接下来介绍STM32的中断优先级分组函数NVIC_PriorityGroupConfig(),用来进行中断分组设置的,此函数是在固件库下misc.c文件中(文件目录是:

STM32F10x_StdPeriph_Lib_V3.5.0\Libraries\STM32F10x_StdPeriph_Driver\src\misc.c):

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;
}

函数的参数的取值,是在同文件中进行宏定义的:

#define NVIC_PriorityGroup_0         ((uint32_t)0x700) /*!< 0 bits for pre-emption priority4 bits for subpriority */
#define NVIC_PriorityGroup_1         ((uint32_t)0x600) /*!< 1 bits for pre-emption priority3 bits for subpriority */
#define NVIC_PriorityGroup_2         ((uint32_t)0x500) /*!< 2 bits for pre-emption priority2 bits for subpriority */
#define NVIC_PriorityGroup_3         ((uint32_t)0x400) /*!< 3 bits for pre-emption priority1 bits for subpriority */
#define NVIC_PriorityGroup_4         ((uint32_t)0x300) /*!< 4 bits for pre-emption priority0 bits for subpriority */

STM32中断优先级管理

中断优先级设置寄存器

分组设置好了之后,怎么设置单个中断的抢占优先级和响应优先级?

MDK为与NVIC相关的寄存器定义了如下的结构体,控制着中断向量表中60个中断(由于与中断内核有关,定义在core_cm3.h文件中):

typedef struct
{__IO uint32_t ISER[8];                      /*!< Offset: 0x000  Interrupt Set Enable Register           */uint32_t RESERVED0[24];                                   __IO uint32_t ICER[8];                      /*!< Offset: 0x080  Interrupt Clear Enable Register         */uint32_t RSERVED1[24];                                    __IO uint32_t ISPR[8];                      /*!< Offset: 0x100  Interrupt Set Pending Register          */uint32_t RESERVED2[24];                                   __IO uint32_t ICPR[8];                      /*!< Offset: 0x180  Interrupt Clear Pending Register        */uint32_t RESERVED3[24];                                   __IO uint32_t IABR[8];                      /*!< Offset: 0x200  Interrupt Active bit Register           */uint32_t RESERVED4[56];                                   __IO uint8_t  IP[240];                      /*!< Offset: 0x300  Interrupt Priority Register (8Bit wide) */uint32_t RESERVED5[644];                                  __O  uint32_t STIR;                         /*!< Offset: 0xE00  Software Trigger Interrupt Register     */
}  NVIC_Type;     

我们依次介绍一下这些寄存器:

先介绍几个寄存器组长度为8,这些寄存器是32位寄存器。由于STM32只有60个可屏蔽中断,8个32位寄存器中只需要2个就有64位了,每1位控制一个中断。

  • ISER[8](Interrupt Set-Enable Registers):中断使能寄存器。其中只使用到了ISER[0]和ISER[1],ISER[0]的bit0~bit31分别对应中断0~31。ISER[1]的bit0~27对应中断32~59。要使能某个中断,就必须设置相应的ISER位为1,使该中断被使能(这仅仅是使能,还要配合中断分组、屏蔽、I/O口映射等设置才算完整)。具体每一位对应哪个中断参考stm32f103x.h里面第140行。
  • ICER[8](Interrupt Clear-Enable Registers):中断移除寄存器。该寄存器的作用于ISER相反。这里专门设置一个ICER来清除中断位,而不是向ISER位写0,是因为NVIC的寄存器写1有效,写0无效。
  • ISPR[8](Interrupt Set-Pending Registers):中断挂起控制寄存器。通过置1可以将正在进行的中断挂起,执行同级或者更高级别的中断。写0无效。
  • ICPR[8](Interrupt Clear-Pending Registers):中断解挂控制寄存器。通过置1可以将正在挂起的中断解挂。写0无效。
  • IABR[8](Interrupt Active-Bit Registers):中断激活标志位寄存器。这是一个只读寄存器,可以知道当前在执行的中断是哪一个(为1),在中断执行完后硬件自动清零。

最后,介绍一个寄存器组长度为240,这个寄存器为8位寄存器。240个8位寄存器,每个中断使用一个寄存器来确定优先级。由于CM3由240个外部中断,所以这个寄存器组的数目就是240(注意与上面寄存器的区别,一个是一个寄存器控制一个,一个是一位控制一个)。

  • IP[240](Interrupt Priority Registers):中断优先级控制的寄存器。这是用来控制每个中断的优先级。由于STM32F10x系列一共60个可屏蔽中断,故使用IP[59]~IP[0]。其中每个IP寄存器的高4位[7:4]用来设置抢占和响应优先级(根据分组),低4位没有用到。而两个优先级各占几个位又要由上面讲到的中断优先级分组决定。

中断优先级设置库函数

接下来介绍如何使用库函数实现中断优先级管理,这里使用NVIC_Init()函数来进行对每个中断优先级的设置(misc.c文件中):

void NVIC_Init(NVIC_InitTypeDef* NVIC_InitStruct)
{uint32_t tmppriority = 0x00, tmppre = 0x00, tmpsub = 0x0F;/* Check the parameters */assert_param(IS_FUNCTIONAL_STATE(NVIC_InitStruct->NVIC_IRQChannelCmd));assert_param(IS_NVIC_PREEMPTION_PRIORITY(NVIC_InitStruct->NVIC_IRQChannelPreemptionPriority));  assert_param(IS_NVIC_SUB_PRIORITY(NVIC_InitStruct->NVIC_IRQChannelSubPriority));if (NVIC_InitStruct->NVIC_IRQChannelCmd != DISABLE){/* Compute the Corresponding IRQ Priority --------------------------------*/    tmppriority = (0x700 - ((SCB->AIRCR) & (uint32_t)0x700))>> 0x08;tmppre = (0x4 - tmppriority);tmpsub = tmpsub >> tmppriority;tmppriority = (uint32_t)NVIC_InitStruct->NVIC_IRQChannelPreemptionPriority << tmppre;tmppriority |=  NVIC_InitStruct->NVIC_IRQChannelSubPriority & tmpsub;tmppriority = tmppriority << 0x04;NVIC->IP[NVIC_InitStruct->NVIC_IRQChannel] = tmppriority;/* Enable the Selected IRQ Channels --------------------------------------*/NVIC->ISER[NVIC_InitStruct->NVIC_IRQChannel >> 0x05] =(uint32_t)0x01 << (NVIC_InitStruct->NVIC_IRQChannel & (uint8_t)0x1F);}else{/* Disable the Selected IRQ Channels -------------------------------------*/NVIC->ICER[NVIC_InitStruct->NVIC_IRQChannel >> 0x05] =(uint32_t)0x01 << (NVIC_InitStruct->NVIC_IRQChannel & (uint8_t)0x1F);}
}

其中,NVIC_InitTypeDef为一个结构体,它的成员变量为

typedef struct
{uint8_t NVIC_IRQChannel;                    /*!< Specifies the IRQ channel to be enabled or disabled.This parameter can be a value of @ref IRQn_Type (For the complete STM32 Devices IRQ Channels list, pleaserefer to stm32f10x.h file) */uint8_t NVIC_IRQChannelPreemptionPriority;  /*!< Specifies the pre-emption priority for the IRQ channelspecified in NVIC_IRQChannel. This parameter can be a valuebetween 0 and 15 as described in the table @ref NVIC_Priority_Table */uint8_t NVIC_IRQChannelSubPriority;         /*!< Specifies the subpriority level for the IRQ channel specifiedin NVIC_IRQChannel. This parameter can be a valuebetween 0 and 15 as described in the table @ref NVIC_Priority_Table */FunctionalState NVIC_IRQChannelCmd;         /*!< Specifies whether the IRQ channel defined in NVIC_IRQChannelwill be enabled or disabled. This parameter can be set either to ENABLE or DISABLE */
} NVIC_InitTypeDef;

NVIC_InitTypeDef结构体有4个成员变量:

  1. NVIC_IRQChannel:定义初始化的是哪一个中断,这个可以在stm32f10x.h文件中查到每个中断对应的名字,如USART1_IRQn;
  2. NVIC_IRQChannelPreemptionPriority:定义此中断的抢占优先级别;
  3. NVIC_IRQChannelSubPriority:定义此中断的响应优先级别;
  4. NVIC_IRQChannelCmd:该中断是否使能。

其实我们看NVIC_Init()函数内部使能中断,也是通过ISER寄存器配置的。这与我么之前的内容并不矛盾。函数内部使用NVIC->ISER,而NVIC是一个宏定义,

#define NVIC     ((NVIC_Type *) NVIC_BASE)     /*!< NVIC configuration struct         */

也就是直接操作结构体来实现操作ISER寄存器。具体原理见【STM32】MDK中寄存器地址名称映射分析。

比如,使能串口1中断,抢占优先级为1,响应优先级为2,初始化的方法为:

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

总结与分析

最后总结一下中断优先级设置的步骤:

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

void NVIC_PriorityGroupConfig(uint32_t NVIC_PriorityGroup);

整个系统执行过程中,只设置一次中断分组;

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

void NVIC_Init(NVIC_InitTypeDef* NVIC_InitStruct);

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

【STM32】NVIC中断优先级管理(中断向量表)相关推荐

  1. 关于嵌入式学习随笔-6《NVIC中断优先级管理》

    1.中断技术概述 在单片机应用系统中,中断技术主要用于时时检测与控制,也就是要求单片机能感及时地响应中断请求源提出的服务请求,进行快速响应并及时处理,这些工作是由单片机片内的中断系统来实现的.当中断请 ...

  2. 21.NVIC中断优先级管理

    NVIC中断优先级管理 笔记基于正点原子官方视频 视频连接https://www.bilibili.com/video/BV1Wx411d7wT?p=71&spm_id_from=333.10 ...

  3. 【STM32】NVIC 中断优先级管理,抢占优先级,响应优先级,中断寄存器

    文章目录 抢占优先级和响应优先级 抢占 响应 NVIC 的优先级组 中断寄存器 ISER[8] ICER[8] ISPR[8] ICPR[8] IABR[8] IP[240] 中断优先级设置步骤总结 ...

  4. STM32外部中断与(NVIC)中断优先级管理

    文章目录 1.中断介绍 1.中断的概念 2.中断的产生 3.中断处理的流程 2.STM32内嵌向量中断控制器NVIC 1.NVIC控制器的寄存器 2.STM32中断配置 3.STM32外部中断EXIT ...

  5. 【STM32】 NVIC 中断优先级管理

    目录 中断解释 相关寄存器组介绍 设计逻辑 配置方法 总结 中断解释 NVIC:向量中断控制器. 中断可以看作是一个事件. 举例来说,你正在家里学习,突然来了电话,你只能停下当前的学习去接电话,在接电 ...

  6. STM32F4 HAL库开发 -- NVIC 中断优先级管理

    一.中断寄存器 STM32F429xx的96个中断里面,包括10个内核中断和91个可屏蔽中断,具有16级可编程的中断优先级,而我们常用的就是这91个可屏蔽中断.在MDK内,与NVIC相关的寄存器,MD ...

  7. 【STM32】中断优先级管理

    00. 目录 文章目录 00. 目录 01. 概述 02. 结构体声明 03. 中断分组 04. 相关类型 05. 相关函数 06. 附录 07. 声明 01. 概述 CM4 内核支持 256 个中断 ...

  8. STM32F1笔记(四)NVIC中断优先级管理

    STM32将中断分为5个组,组0~4.配置代码如下: NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); 在标准库里,分组的定义如下: /** @defgr ...

  9. NVIC中断优先级管理

最新文章

  1. js自己定义插件-选项卡
  2. 收获单季最大营收,“半死不活”特斯拉再续命一秒?
  3. Excel技巧之——英文大小写转换(转)
  4. 毕业后的五年拉开大家差距的原因在哪里
  5. 计算机科学与技术的深度研究,专业深度分析--计算机科学与技术.docx
  6. 二分图的判定(模板)
  7. Hibernate 二级缓存
  8. codis配置_分布式缓存Codis集群安装手册
  9. python画圣诞树代码解读_实战 | 教你用Python画各种版本的圣诞树
  10. 人活着,就应该对其他人贡献价值
  11. java 构造器(constructor)是否可被重写(override)?
  12. Linux脚本实战之SSH执行远端脚本
  13. 点云配准(三) 传统点云配准算法概述
  14. PLC编程语言入门,常用指令集汇总分享
  15. 什么是负边沿触发_边沿触发 - FreeSaber - 博客园
  16. 国外著名英文搜索引擎大全及分类
  17. oracle12c性能测试,Oracle12c IMO 测试
  18. ERROR: Cannot uninstall ‘PyYAML‘. It is a distutils installed project and thus we cannot...
  19. uniapp 在h5 模式下扫码
  20. Windows平台下搭建Qt编译环境(VS2008)

热门文章

  1. HTML5开发系列(4) 之 样式表的三种类型
  2. 一个假冒的序列号被用来注册Internet Download Manager。IDM正在退出...解决办法
  3. 基于SSM的小区物业管理系统JAVA【数据库设计、论文、源码、开题报告】
  4. 相似度计算常用方法综述
  5. Java学习笔记系列-入门篇-计算机基础
  6. Unity使用全局钩子
  7. 风应力旋度 matlab,热带气旋对南海上层海洋影响研究
  8. AIT Worldwide Logistics与卡利塔航空建立民航预备队合作伙伴关系
  9. windows改键软件——sharpkeys
  10. .COMBO勒索病毒解密恢复 .xx4444 勒索病毒数据库恢复 .ALCO勒索病毒解密恢复