STM32中断笔记——关于NVIC的两个问题
STM32 中断非常强大,每个外设都可以产生中断,中断也是STM32非常重要的一个内容。
NVIC:嵌套向量中断控制器,属于内核外设,管理着包括内核和片上所有外设的中断相关的功能。
ARM cortex_m3 内核支持 256 个中断(16 个内核+240 外部)和可编程 256 级中断优先级的设置,与其相关的中断控制和中断优先级控制寄存器(NVIC、SYSTICK 等)也都属于cortex_m3 内核的部分。STM32 采用了 cortex_m3 内核,所以这部分仍旧保留使用,但 STM32并没有使用 cortex_m3 内核全部的东西(如内存保护单元 MPU 等),因此它的 NVIC 是cortex_m3 内核的 NVIC 的子集。
这篇文章主要记录我学习中断时关于NVIC的两个问题。
问题1:NVIC_Type和NVIC_InitTypeDef结构体的关系?
NVIC寄存器的定义是在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;
在配置中断的时候我们一般只用 ISER、ICER 和 IP 这三个寄存器,ISER 用来使能中断,ICER用来失能中断,IP 用来设置中断优先级。而初始化这个结构体的函数就是void NVIC_Init(NVIC_InitTypeDef* NVIC_InitStruct),在misc.c中定义,比较复杂,有兴趣可以看看:
/*** @brief Initializes the NVIC peripheral according to the specified* parameters in the NVIC_InitStruct.* @param NVIC_InitStruct: pointer to a NVIC_InitTypeDef structure that contains* the configuration information for the specified NVIC peripheral.* @retval None*/
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初始化函数是通过传递的参数NVIC_InitTypeDef* NVIC_InitStruct来初始化NVIC_Type结构体的,而对NVIC_InitTypeDef结构体的初始化就要看具体情况,比如说普通的按键外部中断等等。
NVIC_InitTypeDef结构体结构体定义在misc.h中:
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_Type和NVIC_InitTypeDef这两个结构体就是通过NVIC_Init函数来联系起来的。即NVIC_Type和NVIC_InitTypeDef的关系就是:先在具体的外部中断里将NVIC_InitTypeDef结构体初始化完成,然后通过NVIC_Init函数,把NVIC_InitTypeDef作为参数,将NVIC_Type结构体初始化。
问题2:关于中断优先级和中断优先级分组的问题,这两个有什么区别?
中断优先级分组的设定是在NVIC_Type和NVIC_InitTypeDef结构体初始化的前面。
中断优先级的设定是NVIC->IPRx寄存器(共8bit,只使用高4bit):
相关函数:NVIC_SetPriority(IRQn_Type IRQn, uint32_t priority) // core_cm3.h 1586行
/*** @brief Set the priority for an interrupt** @param IRQn The number of the interrupt for set priority* @param priority The priority to set** Set the priority for the specified interrupt. The interrupt * number can be positive to specify an external (device specific) * interrupt, or negative to specify an internal (core) interrupt.** Note: The priority cannot be set for every core interrupt.*/
static __INLINE void NVIC_SetPriority(IRQn_Type IRQn, uint32_t priority)
{if(IRQn < 0) {SCB->SHP[((uint32_t)(IRQn) & 0xF)-4] = ((priority << (8 - __NVIC_PRIO_BITS)) & 0xff); } /* set Priority for Cortex-M3 System Interrupts */else {NVIC->IP[(uint32_t)(IRQn)] = ((priority << (8 - __NVIC_PRIO_BITS)) & 0xff); } /* set Priority for device specific Interrupts */
}
即就是上面函数中的NVIC->IP。
中断优先级分组的设定是SCB->AIRCR:PRIGROUP[10:8]
优先级分组是由3个bit来控制,所以可以有2 ^ 3 = 8 个分组,但是STM32只用了五组(即0~4),如下图:
相关函数:void NVIC_PriorityGroupConfig(uint32_t NVIC_PriorityGroup)
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;
}
所以中断优先级和中断优先级分组有什么区别或关系呢?SCB->AIRCR:PRIGROUP[10:8]设置的是中断优先级分组,也就是它的值是NVIC_PriorityGroup_0、NVIC_PriorityGroup_1、NVIC_PriorityGroup_2、NVIC_PriorityGroup_3、NVIC_PriorityGroup_4这五个值,而NVIC->IP设置的是分组中主优先级和子优先级的值,STM32使用高四位,根据不同的分组,主优先级和子优先级占用这四位中不同的位数。
要注意的就是:中断优先级的设置和中断优先级分组的设置是在不同寄存器中设置的,前者是NVIC->IPRx,后者是SCB->AIRCR。
以上就是我遇到的两个问题及其答案,如有错误,欢迎指正。
中断编程的顺序有四个步骤:
①使能中断请求;
②配置中断优先级分组;
③配置NVIC寄存器,初始化NVIC_InitTypeDef;
④编写中断服务函数。
第一个步骤,使能中断请求是配置外设相应的寄存器,配置好外设的中断使能寄存器后,外设就可以触发中断,即可以向CPU发送中断请求,但是要让CPU接受中断请求,还需要配置NVIC(嵌套向量中断控制器)的中断使能位,这个使能位是NVIC结构体的一个成员,即上面结构体中的__IO uint32_t ISER[8]。可以说,外设的中断请求使能是小门,而NVIC(嵌套向量中断控制器)的中断使能是大门,一个大门对应多个小门。
第二个步骤,配置中断优先级分组,为什么要配置中断优先级分组呢?因为STM32有多个外设,所以就有可能产生多个中断请求,这时候就需要解决先处理哪个中断请求这个问题,所以就要配置中断优先级分组,优先级高的先处理。
第三个步骤,当中断优先级分组配置完了,就要配置具体的外部中断了,除了要初始化NVIC_InitTypeDef结构体,还要配置EXTI_InitTypeDef结构体。
第四个步骤,中断服务函数也是在具体的外部中断中配置的,比如EXTI0_IRQHandler函数,具体问题具体分析,这里不再多说。
STM32中断笔记——关于NVIC的两个问题相关推荐
- STM32学习笔记(四)丨TIM定时器及其应用(定时中断、内外时钟源选择)
本篇文章包含的内容 一.TIM 定时器 1.1 TIM 定时器简介 1.2 TIM 定时器类型及其工作原理简介 1.2.1 基本定时器工作原理及其结构 1.2.2 通用定时器工作原理及其结构 1.2. ...
- STM32入门笔记(02):定时器之定时器中断、输入捕获和PWM输出(SPL库函数版)
目录 定时器 8个定时器 定时器功能 定时器中断 常用通用定时器的寄存器 定时器中断实验目的: 定时器库函数及步骤 实验程序讲解 PWM 简介 STM32 PWM工作过程 PWM模式1 与 PWM模式 ...
- STM32中断回调函数定时器-STM32电控学习笔记06
STM32中断&定时器-STM32电控学习笔记06 day6:2022/9/24 [中断概述] 在 STM32 中,对信号的处理可以分为轮询方式和中断方式,轮询方式就是不断去访问一个信号的端口 ...
- STM32学习笔记(三)丨中断系统丨EXTI外部中断(对射式红外传感器计次、旋转编码器计次)
本篇文章包含的内容 一.中断系统 1.1 中断的定义 1.2 中断优先级 1.3 中断的嵌套 1.4 STM32中的中断系统 1.4.1 STM32的中断资源 1.4.2 嵌套中断向量控制器 NVIC ...
- STM32笔记之 NVIC(嵌套向量中断控制器)
写在前面: 本文章旨在总结备份.方便以后查询,由于是个人总结,如有不对,欢迎指正:另外,内容大部分来自网络.书籍.和各类手册,如若侵权请告知,马上删帖致歉. 目录 一.NVIC简单解释 二.抢占优先级 ...
- 009 - STM32学习笔记 - 中断
009 - STM32学习笔记 - 中断 这节的内容,野火的官方视频我反复看了好几次,但是感觉火哥在这块讲解的特别绕,理解起来很吃力,后来在看了一下其他老师的视频,结合一些书本资料和官方手册,才搞清楚 ...
- 【STM32学习笔记】(13)——外部中断详解
EXTI 简介 EXTI(External interrupt/event controller)-外部中断/事件控制器,管理了控制器的 20 个中断/事件线.每个输入线可以独立地配置 ...
- stm32学习笔记-中断系统
文章目录 问题引入 1.中断系统概述. 1.1 为什么要中断(中断意义) 中断和轮询比较: 1.2 中断处理过程 1.3 中断笔试题 1.4 中断服务函数 2.STM32中断的体系结构. 2.1 结构 ...
- STM32学习笔记——EXTI外部中断,光敏传感器控制LED灯
中断系统 中断:在主程序运行过程中,当出现了特定的中断触发条件,CPU就可以暂停当前正在运行的程序去处理中断程序,并把当前程序的地址压入堆栈,中断程序处理完成后把地址弹出堆栈,回到刚刚暂停的位置继续执 ...
最新文章
- 绩效面谈流程,阿里是这样做的
- Tensorflow—交叉熵
- PHP 通过数组判断数组顺序输出是否是二叉排序树的后序遍历结果
- 【PAT甲级 LinkedHashMap】1041 Be Unique (20 分) Java、C++版
- 泡泡玛特通过港交所聆讯 上半年总收益8.18亿元
- cipher java aes 模式_java – 为什么我的AES Cipher在init的DECRYPT_MODE上抛出一个InvalidKeyException...
- 腾讯会议共享PPT使用演讲者模式
- 网页原型设计工具设计_网页设计工具从下往下
- 通达OA流程中心触发器使用实例
- URAL 1389 Roadworks 贪心
- 51CTO学院三周年
- disallow root login remotely 不起作用?
- 大学计算机实践教程课后答案,大学计算机基础实践教程习题答案.pdf
- 朴素贝叶斯算法原理以及python实现
- QWebEngine集成Netron可视化模型
- FleaPHP 学习笔记1
- 又一打脸现场!Fork Bunny 的 Merlin 损失 240 ETH
- 手机刷linux插鼠标U盘,用OTG线连接键盘鼠标U盘 手机瞬间变电脑 自制otg线
- 南宁市二手房直接交易流程(一)
- TPAMI 2022|金字塔池化的骨干网络!南开达摩院联合推出P2T
热门文章
- [数据库基础篇]——关系数据库
- c程序第四堂课后作业
- 做校长当如安县桑枣中学校长叶志平
- 海康威视视频播放插件1.4.100教程
- UnicodeDecodeError: ‘utf-8‘ codec can‘t decode byte 0xbe in position 0: invalid start byte
- docker的安装和卸载
- 实验3:用户与组管理【nyist】
- 【Python数据分析与处理 实训03】 --- 酒类消费信息分析(数据分组聚合 group().agg()应用)
- Python控制安卓手机自动刷短视频实现金币收益
- 分享几个关于AI的网站