NVIC(Nested vectoredinterrupt controller)嵌套向量中断控制器;
中断管理办法:
对STM32中断进行分组,组0-4,对每一个中断设置一个抢占优先级和响应优先级。
中断优先级设置步骤:
1、系统运行后先设置中断优先级分组
void NVIC_PriorityGroupConfig(uint32_t NVIC_Priority_Group);
2、对于每个中断,设置相应的抢占优先级和响应优先级;
NVIC_Init(NVIC_InitTypeDef* NVIC_InitStruct)
typedef struct NVIC_InitTypeDef{
uint8_t NVIC_IRQChannel; //中断通道
uint8_t NVIC_IRQChannelPreemptionPriority; //抢占优先级
uint8_t NVIC_IRQChannelSubPriority; //响应优先级
FunctionalState NVIC_IRQChannelCmd; //中断通道使能
}
1)抢占优先级越小,优先级越高;相同抢占优先级的中断不能嵌套;
2)相同抢占优先级N个中断发生时,响应优先级越小的中断首先执行(不能嵌套),如果响应优先级也均相同,则根据各中断对应向量表的位置来确定,向量表中越靠前的中断先响应
void NVIC_Init(NVIC_Init TypeDef* NVIC_InitStruct);
NVIC基础知识:
1. cortex-m3支持256个中断,其中包含了16个内核中断,240个外部中断。(本博文只介绍60个外部可屏蔽中断)
2. stm32只有84个中断,包括16个内核中断和68个可屏蔽中断
3. stm32f103上只有60个可屏蔽中断,f107上才有68个中断
4. 先占优先级也就是抢占优先级,概念等同于51单片机中的中断。假设有两中断先后触发,已经在执行的中断先占优先级如果没有后触发的中断 先占优先级更高,就会先处理先占优先级高的中断。也就是说又有较高的先占优先级的中断可以打断先占优先级较低的中断。这是实现中断嵌套的基础。
次占优先级,也就是响应优先级,只在同一先占优先级的中断同时触发时起作用,先占优先级相同,则优先执行次占优先级较高的中断。次占优先级不会造成中断嵌套。 如果中断的两个优先级都一致,则优先执行位于中断向量表中位置较高的中断。
NVIC是嵌套向量中断控制器;用于为中断分组,从而分配抢占优先级和响应优先级;
中断相关寄存器:
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 用来设置中断优先级;
中断优先级和中断优先级分组的区别在于:
中断优先级分组的设定是在NVIC_Type和NVIC_InitTypeDef结构体初始化的前面。
中断优先级的设定是NVIC->IPRx寄存器(共8bit,只使用高4bit)
中断编程的步骤:
1、使能中断请求;
2、配置中断优先级分组;
3、配置NVIC寄存器,主要运用NVIC_InitTypeDef函数;
4、编写中断服务函数;
typedef struct
{
uint8_t NVIC_IRQChannel;
uint8_t NVIC_IRQChannelPreemptionPriority;
uint8_t NVIC_IRQChannelSubPriority;
FunctionalState NVIC_IRQChannelCmd;
}NVIC_InitTypeDef;
贴一段例程:
//外部中断初始化函数
void EXTIX_Init(void)
{
EXTI_InitTypeDef EXTI_InitStructure;
NVIC_InitTypeDef NVIC_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE);//外部中断,需要使能AFIO时钟
KEY_Init();//初始化按键对应io模式
//三个按键分别连到了PC5、PA15、PA0,以下对三个引脚进行配置
//GPIOC.5 中断线以及中断初始化配置
GPIO_EXTILineConfig(GPIO_PortSourceGPIOC,GPIO_PinSource5);
EXTI_InitStructure.EXTI_Line=EXTI_Line5;//上面说了PA0,PB0为EXTI0,这里PC5中断线应该为EXTI5
EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;
EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling;//下降沿触发
EXTI_InitStructure.EXTI_LineCmd = ENABLE;
EXTI_Init(&EXTI_InitStructure); //根据EXTI_InitStruct中指定的参数初始化外设EXTI寄存器
//GPIOA.15 中断线以及中断初始化配置
GPIO_EXTILineConfig(GPIO_PortSourceGPIOA,GPIO_PinSource15);
EXTI_InitStructure.EXTI_Line=EXTI_Line15; // PA15中断线为EXTI15
EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;
EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling;
EXTI_InitStructure.EXTI_LineCmd = ENABLE;
EXTI_Init(&EXTI_InitStructure); //根据EXTI_InitStruct中指定的参数初始化外设EXTI寄存器
//GPIOA.0 中断线以及中断初始化配置
GPIO_EXTILineConfig(GPIO_PortSourceGPIOA,GPIO_PinSource0);
EXTI_InitStructure.EXTI_Line=EXTI_Line0;
EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;
EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising;
EXTI_InitStructure.EXTI_LineCmd = ENABLE;
EXTI_Init(&EXTI_InitStructure); //根据EXTI_InitStruct中指定的参数初始化外设EXTI寄存器
NVIC_InitStructure.NVIC_IRQChannel = EXTI0_IRQn; //使能按键所在的外部中断通道;EXTI0~4单独有自己的中断号(中断服务函数),所以这里是EXTI0。
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x02; //抢占优先级2,
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x02; //子优先级1
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //使能外部中断通道
NVIC_Init(&NVIC_InitStructure); //根据NVIC_InitStruct中指定的参数初始化外设NVIC寄存器
NVIC_InitStructure.NVIC_IRQChannel = EXTI9_5_IRQn; //使能按键所在的外部中断通道;EXTI5~9共享一个中断号,所以这里是EXTI9_5_IRQn。
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x02; //抢占优先级2,
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x01; //子优先级1
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //使能外部中断通道
NVIC_Init(&NVIC_InitStructure);
NVIC_InitStructure.NVIC_IRQChannel = EXTI15_10_IRQn; //使能按键所在的外部中断通道;EXTI10~15共享一个中断号,这里EXTI15的中断号当然是EXTI15_10_IRQn。
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x02; //抢占优先级2,
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x00; //子优先级1
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //使能外部中断通道
NVIC_Init(&NVIC_InitStructure);
}