STM32中断优先级配置详解
在STM32微控制器中,中断优先级的配置对于系统的稳定性和可靠性至关重要。正确地配置中断优先级可以确保重要中断的及时响应,提高系统的性能。本文将介绍STM32中断优先级配置的方法,帮助初学者轻松上手。
1. 中断优先级的原理
中断优先级分为抢占优先级和子优先级两部分,用于确定中断的响应顺序和执行顺序。抢占优先级用于确定中断的响应优先级,而子优先级用于确定中断的实际执行优先级。当多个中断同时触发时,系统会优先处理抢占优先级较高的中断,而在相同抢占优先级的情况下,会根据子优先级来确定中断的执行顺序。
NVIC的中断优先级由优先级寄存器NVIC_IPRx的4位决定,这4位可以进行切分,分为高n位的抢占优先级和低4-n位的响应优先级抢占优先级高的可以中断嵌套,响应优先级高的可以优先排队,抢占优先级和响应优先级均相同的按中断号排队
比如如果选择分组1,那么抢占优先级只能选择0,1二个值,响应优先级只能在0-7中取值。值越小优先级越高。简单的说,就是设置中断优先级时先设置分组,然后设置抢占优先级和响应优先级。
2. 配置方法
以下是配置中断优先级的步骤:
步骤 1:选择中断优先级分组
优先级设置的位数和分配方式由中断优先级分组决定,这是通过SCB_AIRCR寄存器来配置的。
通过设置SCB_AIRCR寄存器的10-8位来确定中断的优先级分组。
程序中设置优先级的调用函数
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
代码中对分组的定义:
#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 */
步骤 2:确定中断的优先级
根据中断的重要性和响应时序,确定中断的抢占优先级和响应优先级。一般情况下,抢占优先级用于区分不同中断的响应顺序,而响应优先级则用于同一抢占优先级下的中断执行顺序。
NVIC_IPRx寄存器是一组32位的寄存器,其中的每个8位对应一个中断优先级。例如,NVIC_IPR0寄存器的高4位(bit 7-4)对应中断0的抢占优先级和响应优先级,低4位(bit 3-0)是无效位。根据分组来解释每个中断的抢占优先级和响应优先级。
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2;//抢占优先级
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1; //响应优先级
3.完整中断程序
#include "stm32f4xx.h"
void EXTI0_IRQHandler(void)
{
// 中断处理代码
// ...
EXTI_ClearITPendingBit(EXTI_Line0); // 清除中断标志位
}
void EXTI_Config(void)
{
GPIO_InitTypeDef GPIO_InitStruct;
EXTI_InitTypeDef EXTI_InitStruct;
NVIC_InitTypeDef NVIC_InitStruct;
// 使能外部中断时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_SYSCFG, ENABLE);
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE);
// 配置GPIO引脚
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_0;
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IN;
GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_NOPULL;
GPIO_Init(GPIOA, &GPIO_InitStruct);
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
// 配置外部中断线
EXTI_ClearITPendingBit(EXTI_Line0);
EXTI_InitStruct.EXTI_Line = EXTI_Line0;
EXTI_InitStruct.EXTI_Mode = EXTI_Mode_Interrupt;
EXTI_InitStruct.EXTI_Trigger = EXTI_Trigger_Falling;
EXTI_InitStruct.EXTI_LineCmd = ENABLE;
EXTI_Init(&EXTI_InitStruct);
// 配置中断优先级
NVIC_InitStruct.NVIC_IRQChannel = EXTI0_IRQn;
NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 0x01; // 抢占优先级
NVIC_InitStruct.NVIC_IRQChannelSubPriority = 0x01; // 子优先级
NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStruct);
}
int main(void)
{
// 初始化外部中断
EXTI_Config();
while (1)
{
// 主循环代码
// ...
}
}