STM32F104x – 中断配置小结
学习目标: 实现 “中断分组设置 + 中断优先级管理”;
- 1.系统运行开始的时候设置中断分组。确定组号,也就是确定抢占优先级和响应优先级
的分配位数。调用函数为 NVIC_PriorityGroupConfig(); - 2.设置所用到的中断的中断优先级别。对每个中断调用函数为 NVIC_Init();
学习内容:
NVIC 中断管理函数主要在 misc.c 文件里面
1.1 中断分组配置
void NVIC_PriorityGroupConfig(uint32_t NVIC_PriorityGroup)
{
assert_param(IS_NVIC_PRIORITY_GROUP(NVIC_PriorityGroup));
SCB->AIRCR = AIRCR_VECTKEY_MASK | NVIC_PriorityGroup; //过设置 SCB->AIRCR 寄存器来设置中断优先级分组
}
- 拆解分析:双击选中函数体里面的“IS_NVIC_PRIORITY_GROUP”然后右键“Go to defition of …”可以查看入口参数结构体
#define IS_NVIC_PRIORITY_GROUP(GROUP) \\分组范围0-4
(((GROUP) == NVIC_PriorityGroup_0) ||
((GROUP) == NVIC_PriorityGroup_1) || \
((GROUP) == NVIC_PriorityGroup_2) || \
((GROUP) == NVIC_PriorityGroup_3) || \
((GROUP) == NVIC_PriorityGroup_4))
- Example:设置系统中断分组优先级为3
NVIC_PriorityGroupConfig(NVIC_PriortyGroup_2); // 可屏蔽中断的IP寄存器组的高四位中,最高3位是抢占优先级,低1位是响应优先级
❗注意:
1.如果两个中断的抢占优先级和响应优先级都是一样的话,则看哪个中断先发生就先执行;
2.高优先级的抢占可以打断正在进行的低优先级抢占中断;而抢占优先级相同的中断,高优先级的响应不可以打断低优先级响应的中断。
1.2 中断优先级管理
void NVIC_Init(NVIC_InitTypeDef* NVIC_InitStruct); //中断初始化函数
- NVIC_InitTypeDef结构体解析
typedef struct
{
uint8_t NVIC_IRQChannel; //在 stm32f10x.h 中找到每个中断对应的名字。例如 USART1_IRQn
uint8_t NVIC_IRQChannelPreemptionPriority; //定义这个中断的抢占优先级别;
uint8_t NVIC_IRQChannelSubPriority; //定义这个中断的(响应优先级子优先级别)
FunctionalState NVIC_IRQChannelCmd; //该中断通道是否使能
} NVIC_InitTypeDef;
- Example:使能串口 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 寄存器
基础回顾:
CM4 内核支持 256 个中断,其中包含了 16 个内核中断和 240 个外部中断,并且具有256 级的可编程中断设置。但 STM32F4 并没有使用 CM4 内核的全部东西,STM32F40xx/STM32F41xx 总共有 92 个中断。
STM32F40xx/STM32F41xx 的 92 个中断里面,包括 10 个内核中断和 82 个可屏蔽中断,具有 16 级可编程的中断优先级,而我们常用的就是这 82 个可屏蔽中断。
在MDK内与NVIC相关寄存器结构体定义如下:
typedef struct
{
__IO uint32_t ISER[8]; /*!< Interrupt Set Enable Register */
uint32_t RESERVED0[24];
__IO uint32_t ICER[8]; /*!< Interrupt Clear Enable Register */
uint32_t RSERVED1[24];
__IO uint32_t ISPR[8]; /*!< Interrupt Set Pending Register */
uint32_t RESERVED2[24];
__IO uint32_t ICPR[8]; /*!< Interrupt Clear Pending Register */
uint32_t RESERVED3[24];
__IO uint32_t IABR[8]; /*!< Interrupt Active bit Register */
uint32_t RESERVED4[56];
__IO uint8_t IP[240]; /*!< Interrupt Priority Register, 8Bit wide */
uint32_t RESERVED5[644];
__O uint32_t STIR; /*!< Software Trigger Interrupt Register */
} NVIC_Type;
- ISER[8]:Interrupt Set-Enable Registers 中断使能寄存器组 ,你要使能某个中断,必须设置相应的 ISER 位为1;
- ICER[8]:Interrupt Clear-Enable Registers 中断除能寄存器组,作用与ISER 相反,用来清除某个中断的使能的;
- ISPR[8]:Interrupt Set-Pending Registers 中断挂起控制寄存器组,通过置 1可以将正在进行的中断挂起,而执行同级或更高级别
的中断。写 0 是无效的; - ICPR[8]:Interrupt Clear-Pending Registers 中断解挂控制寄存器组,作用与 ISPR 相反,置 1,可以将挂起的中断解挂,写 0 无效;
- IABR[8]:Interrupt Active Bit Registers 中断激活标志位寄存器组 ,对应位置 1,表示该位所对应的中断正在执行。通过它可以知道当前在执行的中断是哪一个,在中断执行完了由硬件自动清零。
- ❗ IP[240]:Interrupt Priority Registers 中断优先级控制的寄存器组,IP[81]~IP[0]分别对应中断 81~0,可屏蔽中断占用的 8bit 并没有全部使用,而是只用了高 4 位。这 4 位,又分为抢占优先级和响应优先级。抢占优先级在前,响应优先级在后。