Air32F103学习笔记-5.中断配置NVIC

这篇具有很好参考价值的文章主要介绍了Air32F103学习笔记-5.中断配置NVIC。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

中断是单片机非常重要的功能,也是一个难点,本节单独讲下NVIC,以及NVIC的配置。

一.关于NVIC

NVIC: Nested Vectored Interrupt Controller 内嵌向量中断控制器  是M3内核的一个外设

是用来总控中断的,例如中断优先级设置,中断使能等

下面看下《STM32F10xxx Cortex-M3编程手册-英文版》中关于NVIC的描述:

Air32F103学习笔记-5.中断配置NVIC,学习,笔记

这部分描述了内嵌向量中断控制器以及寄存器的使用,NVIC支持:

  • 最多81个中断(具体数量取决于STM32的型号,请参考数据手册)
  • 每个中断都支持0-15个可编程的优先级。等级越高(标号越大),优先级越低,所以0是优先级最高的。
  • 中断支持电平检测以及边沿检测
  • Dynamic reprioritization of interrupts 中断的动态重新分配优先级(暂且这么翻译)
  • 优先级支持编组,并且分为主优先级和抢占优先级
  • 咬尾中断
  • 1个外部不可屏蔽中断NMI    Non-Mask Interrurt

说了这么多,其实有用的就只有3点:

1. 中断优先级支持0-15优先级,编号越小,优先级越高

2. 中断优先级又分为两组,分别是主优先级和抢占优先级

3. 中断支持电平触发和边沿触发(应该是说外部中断EXIT)

上面2和1是不是有点矛盾?不急我们先往下说:

看下NVIC的相关寄存器,这部分比较无聊,且用固件库编程,无需知道这些,可以略过:

NVIC的寄存器按照功能分为6大类(常用标红):

  • Set-enable 使能
  • Clear-enable 失能
  • Set-pending 设置挂起
  • Clear-pending 清除挂起
  • Active Bits 
  • Interrupt Priority Registers 中断优先级寄存器

那么对应的,用以下简写,以及数组来匹配相应的寄存器;

在手册里是这么描述的,每个数组将对应其寄存器,例如使能,ISER[0]对应ISER0

完整描述看下面:

功能         寄存器全名 数组 寄存器
Set-enable 使能 Interrupt Set Enable Rigister ISER[0],ISER[1],ISER[2] ISER0,ISER1,ISER2
Clear-enable 失能 Interrupt Clear Enable Rigister ICER[0],ICER[1],ICER[2] ICER0,ICER1,ICER2
Set-pending 设置挂起

Interrupt Set Pending

Rigister

ISPR[0],ISPR[1],ISPR[2] ISPR0,ISPR1,ISPR2
Clear-pending 清除挂起 Interrupt Clear Pending Rigister ICPR[0],ICPR[1],ICPR[2] ICPR0,ICPR1,ICPR2
Active Bits Interrupt Active Bits Rigister IABR[0],IABR[1],IABR[2] IABR0,IABR1,IABR2

例如常用的Set-enable 使能ISER,Clear-enable 失能ICER解释如下:

根据core_cm3.h的定义,每个ISER数组都是32位的,每一位控制1个中断的状态,并且是可读可写的。

1是使能,0是无效。复位后全部都是0,即复位后,中断默认全关,要省电嘛~~~

Air32F103学习笔记-5.中断配置NVIC,学习,笔记

ISCR同理

Air32F103学习笔记-5.中断配置NVIC,学习,笔记

中断优先级寄存器Interrupt Priority Registers,简称IP,M3内核的MCU有8位,理论上可以支持2的8次方,0~255,共256级,但是根本用不完,所以厂家阉割了,STM32只用了8位中的高4位用来定义优先级,就是2的4次方即16,所以中断优先级最多支持0-15级。不是16个中断的意思,多个中断可以排在同一优先级上。

但是Air32F103只用了3位定义优先级!!!所以优先级支持0~7,共8级

Air32F103学习笔记-5.中断配置NVIC,学习,笔记

第二节关于中断源列出了所有中断表,Air32F103一共67个可编程中断,所以到IP[80]足够用了。

/**
  \ingroup    CMSIS_core_register
  \defgroup   CMSIS_NVIC  Nested Vectored Interrupt Controller (NVIC)
  \brief      Type definitions for the NVIC Registers
  @{
 */

/**
  \brief  Structure type to access the Nested Vectored Interrupt Controller (NVIC).
 */
typedef struct
{
  __IOM uint32_t ISER[8U];               /*!< Offset: 0x000 (R/W)  Interrupt Set Enable Register */
        uint32_t RESERVED0[24U];
  __IOM uint32_t ICER[8U];               /*!< Offset: 0x080 (R/W)  Interrupt Clear Enable Register */
        uint32_t RESERVED1[24U];
  __IOM uint32_t ISPR[8U];               /*!< Offset: 0x100 (R/W)  Interrupt Set Pending Register */
        uint32_t RESERVED2[24U];
  __IOM uint32_t ICPR[8U];               /*!< Offset: 0x180 (R/W)  Interrupt Clear Pending Register */
        uint32_t RESERVED3[24U];
  __IOM uint32_t IABR[8U];               /*!< Offset: 0x200 (R/W)  Interrupt Active bit Register */
        uint32_t RESERVED4[56U];
  __IOM uint8_t  IP[240U];               /*!< Offset: 0x300 (R/W)  Interrupt Priority Register (8Bit wide) */
        uint32_t RESERVED5[644U];
  __OM  uint32_t STIR;                   /*!< Offset: 0xE00 ( /W)  Software Trigger Interrupt Register */
}  NVIC_Type;

 core.cm3.h定义了非常多的中断,IP一共240个数组,能定义240个中断的优先级,牛

关于优先级分组:

Air32F103和STM32103有很大不同,并且固件库里关于分组是错误的!

STM32支持16级中断优先级(4Bits用于设置分组),AIR32F103只支持8级(3Bits用于设置分组),那么固件库里关于分组的信息就是错误的

照抄STM32改个头文件名字就全拿来用了。。。

/** @defgroup MISC_Private_Functions
  * @{
  */

/**
  * @brief  Configures the priority grouping: pre-emption priority and subpriority.
  * @param  NVIC_PriorityGroup: specifies the priority grouping bits length. 
  *   This parameter can be one of the following values:
  *     @arg NVIC_PriorityGroup_0: 0 bits for pre-emption priority
  *                                4 bits for subpriority
  *     @arg NVIC_PriorityGroup_1: 1 bits for pre-emption priority
  *                                3 bits for subpriority
  *     @arg NVIC_PriorityGroup_2: 2 bits for pre-emption priority
  *                                2 bits for subpriority
  *     @arg NVIC_PriorityGroup_3: 3 bits for pre-emption priority
  *                                1 bits for subpriority
  *     @arg NVIC_PriorityGroup_4: 4 bits for pre-emption priority
  *                                0 bits for subpriority
  * @retval None
  */
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;
}

吐槽完,咱们看下优先级该怎么办。。。

首先了解下中断分组,分组分为抢占优先级和子优先级

抢占优先级:中断之间互相打断用的,优先级高的打断优先级低的去执行。如果优先级相同呢,看下面;

子优先级:抢占优先级相同时比较,子优先级,同样遵循标号越低优先级越高原则。

如果抢占优先级和子优先级全部相同时,比较中断标号,标号越低,优先级越高。

CM3权威指南-宋岩   

原则上,CM3支持3个固定的高优先级和多达256级的可编程优先级,并且支持128级抢占(128的来历请见下文分解——译注)。但是,绝大多数CM3芯片都会精简设计,以致实际上支持的优先级数会更少,如8级,16级,32级等。它们在设计时会裁掉表达优先级的几个低端有效位,以减少优先级的级数(可见,不管使用多少位来表达优先级,都是以MSB对齐的——译者注)。

这是本好书啊,值得读10遍。书中举例用3位表示优先级正好对应Air32F103的情况。

Air32F103学习笔记-5.中断配置NVIC,学习,笔记

也就是说,Air32F103用了高3位来表示优先级,优先级从高倒地依次为0x00,0x20,0x40,0x80,0xA0,0xC0,0xE0

0x1110 0000 0xE0
0x1100 0000 0xC0
0x1010 0000 0xA0
0x1000 0000 0x80
0x0110 0000 0x60
0x0101 0000 0x40
0x0010 0000 0x20
0x0000 0000 0x00

分组咋分呢。。。

分组是在SCB->AIRCR寄存器里的

这里有强调:AIRCR是用来提供分组控制的,如果想要写寄存器,必须在VECTKEY这部分中写入0X05FA,否则芯片将忽略写操作。

VECTKEY是【31:16】位,高16位的值固定了,05FA

Air32F103学习笔记-5.中断配置NVIC,学习,笔记

【15】:写0

【14:11】:写0

【10:8】:用来进行分组,这里PRIGROUP的值很有意思,乍一看不好理解,但是如果我们把这里的所有值都列出来,对比下就清晰了。

分组位置

PRIGROUP

[10:8]

Binary Points

表达抢占优先级的位段

Group priority bits

表达子优先级的位段

Subpriority bits

0b000 0bxxxxxxx.y [7:1] [0:0]
0b001 0bxxxxxx.yy [7:2] [1:0]
0b002 0bxxxxx.yyy [7:3] [2:0]
0b003 0bxxxx.yyyy [7:4] [3:0]
0b004 0bxxx.yyyyy [7:5] [4:0]
0b005 0bxx.yyyyyy [7:6] [5:0]
0b006 0bx.yyyyyyy [7:7] [6:0]
0b007 0byyyyyyyy [7:0](所有位)

其实这里的值代表了,子优先级的位数。

例如当【10:8】全部写0,即0b000,表示子优先级是【0:0】位,即只有0位用来表示子优先级,那么抢占优先级就是【7:0】位了。即分组值0b000,=0时,抢占优先级共7位,子优先级共1位。

但是Air32F103一共才3位用来表示优先级,所以【10:8】位,写0,1,2,3,4结果都是一样的,即抢占优先级用全部高3位表示,子优先级1位也没,所以抢占优先级共二的三次方共8级,子优先级0.

Bit 7 Bit 6 Bit 5 Bit 4 Bit 3 Bit 2 Bit 1 Bit 0
抢占优先级          

那我们根据Air32F103的实际情况再重新写一下:

分组位置

PRIGROUP

[10:8]

Binary Points

表达抢占优先级的位段

Group priority bits

抢占优先级

表达子优先级的位段

Subpriority bits

子优先级
0b004 0bxxx [7:5] 8 0
0b005 0bxx.y [7:6] 4 [5:5] 2
0b006 0bx.yy [7:7] 2 [6:5] 4
0b007 0byyy 0 [7:5](所有位) 8

至此【10:8】的值,我们就能确定了

这里以IP共4位来进行分组示例(因为是STM32的手册)作为对比参考。

Air32F103学习笔记-5.中断配置NVIC,学习,笔记

【7:3】:保留了,需要清除。即写0。

【1】:VECTCLRACTIVE,写时必须置0.

【0】:VECTRESET,写时必须置0.

至此我们能确定AIRCR寄存器的值了,只有【10:8】这三位的值是变化的,其余都是固定的。

Air32F103学习笔记-5.中断配置NVIC,学习,笔记

我们再看下固件库:misc.h,这个头文件定义了几个分组的值,这些是错误的。

分组0,值是7,0位抢占优先级,4位子优先级

分组1,值是6,1位抢占优先级,3位子优先级

分组2,值是5,2位抢占优先级,2位子优先级

分组3,值是4,3位抢占优先级,1位子优先级

分组4,值是3,4位抢占优先级,0位子优先级

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

我们根据上面的表格,写个对的:

#define NVIC_PriorityGroup_0         ((uint32_t)0x700) /*!< 0 bits for pre-emption priority
                                                            3 bits for subpriority */
#define NVIC_PriorityGroup_1         ((uint32_t)0x600) /*!< 1 bits for pre-emption priority
                                                            2 bits for subpriority */
#define NVIC_PriorityGroup_2         ((uint32_t)0x500) /*!< 2 bits for pre-emption priority
                                                            1 bits for subpriority */
#define NVIC_PriorityGroup_3         ((uint32_t)0x400) /*!< 3 bits for pre-emption priority
                                                            0 bits for subpriority */

也就是说,我们可以使用分组0,1,2,3,分别对应 

分组0,值是7,0位抢占优先级,3位子优先级

分组1,值是6,1位抢占优先级,2位子优先级

分组2,值是5,2位抢占优先级,1位子优先级

分组3,值是4,3位抢占优先级,0位子优先级

关于分组设定的库函数,我们看下原型:

Air32F103学习笔记-5.中断配置NVIC,学习,笔记

1.先用断言检查了下中断分组库函数的形参是否在范围内,超范围会警告,严谨。

2.SCB->AIRCR = AIRCR_VECTKEY_MASK | NVIC_PriorityGroup;

这句是在配置SCB-AIRCR的值,这个将决定中断分组。

我们查下AIR_VECKEY_MASK的值

这个掩码的值太熟悉了,0x05FA是手册中要求我们写AIRCR寄存器时,必须要写在高16位的值,并且除了【10:8】位,其余位都为0。

所以NVIC_PriorityGroup的值上AIRCR_VECTKEY_MASK的值,就是我们将要配置的结果。

换句话说,NVIC_PriorityGroup定义了【10:8】的值,其余无关位用掩码的形式和他或在一起即可,简单可靠。

中断分组设置只需要设置1次即可,一般放在main函数里:

例如,我们想要设置中断优先级分组为0组,即0位抢占优先级,3位子优先级。

NVIC_PriorityGroupConfig(NVIC_PriorityGroup_0);

二.关于中断源

Air32F103 有8个可编程的优先等级(使用了3位中断优先级)

中断源及中断优先级如下:红字为内核中断,其余为芯片厂商的外设中断(自己设计的,即使都用M3内核,但每个厂商的中断可能不同,具体要看用户手册)

位置 优先级 优先级类型 名称 说明 地址
- - 保留  0x0000_0000
-3 固定 Reset 复位  0x0000_0004
-2 固定     NMI 不可屏蔽中断 RCC时钟安全系统(CSS)连接到NMI 向量 0x0000_0008
-1 固定 硬件失效 (HardFault) 所有类型的失效 0x0000_000C
0 可设置 存储管理 (MemManage) 存储器管理 0x0000_0010
1 可设置 总线错误 (BusFault) 预取指失败,存储器访问失败 0x0000_0014
2 可设置 错误应用 (UsageFault) 未定义的指令或非法状态 0x0000_0018
- - - 保留

0x0000_0018

~0x0000_002B

3 可设置 SVCall 通过SWI指令的系统服务调用 0x0000_002C
4 可设置 调试监控 (DebugMonitor) 调试监控器 0x0000_0030
- - - 保留 0x0000_0034
5 可设置 PendSV 可挂起的系统服务 0x0000_0038
6 可设置 SysTick 系统滴答定时器 0x0000_003C
0 7 可设置 WWDG 窗口看门狗中断 0x0000_0040
1 8 可设置 PVD 连接到EXTI的电源电压检测(PVD) 中断 0x0000_0044
忽略 忽略 忽略 忽略 忽略
59 66 可设置 DMA2通道4_5 DMA2通道4和DMA2通道5全局中断 0x0000_012C

我数了一下,一共有70个中断源,除了前三个是固定的优先级,剩下67个都是可自己设置使用的。

结合上一节:

Air32F103学习笔记-4.看看SDK中startup_air32f10x.s, .sct, .map-CSDN博客

我看下启动文件关于中断向量表的地址:

; Vector Table Mapped to Address 0 at Reset
                AREA    RESET, DATA, READONLY    //开辟了1个区域,名字叫REST,数据类型,只读
                EXPORT  __Vectors
                EXPORT  __Vectors_End
                EXPORT  __Vectors_Size

__Vectors       DCD     __initial_sp               ; Top of Stack
                DCD     Reset_Handler              ; Reset Handler
                DCD     NMI_Handler                ; NMI Handler
                DCD     HardFault_Handler          ; Hard Fault Handler
                DCD     MemManage_Handler          ; MPU Fault Handler
                DCD     BusFault_Handler           ; Bus Fault Handler
                DCD     UsageFault_Handler         ; Usage Fault Handler
                DCD     0                          ; Reserved
                DCD     0                          ; Reserved
                DCD     0                          ; Reserved
                DCD     0                          ; Reserved
                DCD     SVC_Handler                ; SVCall Handler
                DCD     DebugMon_Handler           ; Debug Monitor Handler
                DCD     0                          ; Reserved
                DCD     PendSV_Handler             ; PendSV Handler
                DCD     SysTick_Handler            ; SysTick Handler

发现没,启动文件中关于中断的,关于中断向量的顺序和手册里的一模一样,因为启动文件是根据手册写的。

AREA 定义一块代码段,段名字是RESET,READONLY 表示只读。

还记得上一节的分散加载吗? RESET段放在最前面,从哪里开始?从外部存储器,即FLASH的起始地址开始放中断向量表。起始地址是0x8000 0000

#1.sct

LR_IROM1 0x08000000 0x00040000  {    ; load region size_region
  ER_IROM1 0x08000000 0x00040000  {  ; load address = execution address
   *.o (RESET, +First)               //RESET段放在最前面
   *(InRoot$$Sections)
   .ANY (+RO)
  }
  RW_IRAM1 0x20000000 0x00018000  {  ; RW data
   .ANY (+RW +ZI)
  }
}

例如:

启动文件,第一行: DCD     __initial_sp               ; Top of Stack      栈顶地址

手册第二行,保留,地址是0x8000 0000,会被映射到0x0000 0000,作为启动后的第一条命令,即MSP的地址。上一节我们知道了,MSP指向了0x2000 0400,即栈顶地址;

启动文件,第二行: DCD     Reset_Handler              ; Reset Handler  复位中断

手册第二行,复位,地址是0x8000 0004,会被映射到0x0000 0004,作为启动后读取的第二条命令,指向了Reset_Handler,即0x8000 023D

以此类推,剩余的中断向量表的名字,依次+4字节往下顺序移动文章来源地址https://www.toymoban.com/news/detail-793654.html

到了这里,关于Air32F103学习笔记-5.中断配置NVIC的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

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

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

相关文章

  • STM32F103学习笔记 | 4.STM32F103芯片介绍

    STM32F1入门学习将使用STM32F103C8T6开发板最小系统板。小R为什么选择它来入门呢?咳咳~首先,ST官方提供强大且易用的标准库函数,使得开发过程方便快捷;其次,网上的教程资料多也十分详细。所以呢,它对高校学生和广大初学者入门都是一个非常好的选择。 开发板的实物图

    2024年04月25日
    浏览(29)
  • STM32f103入门(5)定时器中断

    STM32 TIM(定时器/计数器)模块的中断流程如下: 配置TIM寄存器:首先,通过配置TIM相关的寄存器来设置计时器的基本参数,例如预分频系数、计数模式、计数器周期等。 使能TIM中断:使用TIM_ITConfig函数或者直接操作TIM的相关寄存器,将所需的中断使能位置1。可以选择使能不

    2024年02月11日
    浏览(26)
  • STM32F103学习笔记(5.1)——定时器时钟

    STM32F103RCT6上总共有8个定时器,其中TIM1和TIM8是高级定时器,它们挂载在APB2高速总线上。而TIM2、TIM3、TIM4、TIM5是通用定时器,TIM6、TIM7是基本定时器,它们都挂载在APB1上,基本定时器的功能最少,高级定时器功能最多。所以以学习通用定时器为主。 需要参考手册第二章存储器

    2024年02月15日
    浏览(30)
  • GD32F103串口DMA收发(空闲中断 + DMA)

    GD32F103串口DMA收发(空闲中断 + DMA) 代码如下:

    2024年02月12日
    浏览(34)
  • stm32f103c8t6的外部中断

    在单片机中存在着中断系统,这个系统的逻辑和功能在51单片机中已经有所了解。 1.在32单片机中的内核有一个nvic 里面存放许多优先级的设定,外接许多中断源,比如“exti、tim、adc、usart等”接入之后,nvic再通过中断优先级进行排队,再内接入cpu中进行处理,这样子大大减少

    2024年02月09日
    浏览(35)
  • STM32f103入门(4)对射式红外传感器计次(外部中断)

    中断:在主程序运行过程中,出现了特定的中断触发条件 (中断源),使得CPU暂停当前正在运行的程序,转而去处理中断程序处理完成后又返回原来被暂停的位置继续运行 中断优先级:当有多个中断源同时申请中断时,CPU会根据中断源的轻重缓急进行裁决,优先响应更加紧急的中

    2024年02月11日
    浏览(29)
  • 初步了解STM32的学习笔记(以STM32F103C8T6为例)

      STM32F103C8T6属于主流系列STM32F1 内核是ARM Cortex-Mex3 主频为72Hz RAM:20K(SRAM) ROM:64K(Flash) 封装:LQFP48 供电:2~3.6V(一般为3.3) (注意:以前51用的是5V,而USB也是5V,所以直接插上,而stm32会加上一个稳压芯片,让电压为3.3V) (所有图都是用的是B站上整理过的)  表里面

    2024年02月05日
    浏览(32)
  • STM32F103C8T6的USART串口通信及中断

    一、串口通信 (一)串口协议和RS-232标准 1.串口通信协议 串口通信是指串口按位(bit)发送和接收字节。尽管比特字节(byte)的串行通信慢,但是串口可以在使用一根线发送数据的同时用另一根线接收数据。 串口通信协议是指规定了数据包的内容,内容包含了起始位、主体

    2024年02月02日
    浏览(71)
  • HAL库(STM32CubeMX)之外部中断(STM32F103C8T6)

    HAL库(STM32CubeMX)——ADC学习总结(包含单次/连续模式下的轮询/中断/DMA)(蓝桥杯STM32G431RBT6) HAL库(STM32CubeMX)——DAC学习(STM32G431RBT6) HAL库(STM32CubeMX)——USART配置(中断接收/STM32G431RBT6) HAL库(STM32CubeMX)——基本定时器、PWM、输入捕获、输出比较、互补式PWM等综合学习(STM32

    2024年02月06日
    浏览(33)
  • 2.基于正点原子STM32F103的定时器中断实验(HAL库实现)(cubeMX)

      基本上每一款MCU都会配备定时器这个外设,STM32 的每个通用定时器都是完全独立的,没有互相共享的任何资源。 同样,STM32F1系列的定时器功能也很强大,包括: TIM1和TIM8两个高级定时器; TIM2~TIM5是个通用寄存器; TIM7,TIM8,两个基本定时器。 由于本次实验适用于新手入门

    2023年04月26日
    浏览(150)

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

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

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

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

二维码1

领取红包

二维码2

领红包