中断概括
STM32 中断非常强大,每个外设都可以产生中断,
内核水平上搭载了一个异常响应系统, 分为:系统异常和外部中断。
NVIC
NVIC相当于一个中断总开关,总开关打开,相应的中断才能使用。
在讲如何配置中断优先级之前,我们需要先了解下 NVIC。 NVIC 是嵌套向量中断控制
器,控制着整个芯片中断相关的功能,是内核里面的一个外设。
代码 17-1 NVIC 结构体定义,来自固件库头文件: core_cm3.h
1 typedef struct {
2 __IO uint32_t ISER[8]; // 中断使能寄存器
3 uint32_t RESERVED0[24];
4 __IO uint32_t ICER[8]; // 中断清除寄存器
5 uint32_t RSERVED1[24];
6 __IO uint32_t ISPR[8]; // 中断使能悬起寄存器
7 uint32_t RESERVED2[24];
8 __IO uint32_t ICPR[8]; // 中断清除悬起寄存器
9 uint32_t RESERVED3[24];
10 __IO uint32_t IABR[8]; // 中断有效位寄存器
11 uint32_t RESERVED4[56];
12 __IO uint8_t IP[240]; // 中断优先级寄存器(8Bit wide)
13 uint32_t RESERVED5[644];
14 __O uint32_t STIR; // 软件触发中断寄存器
15 } NVIC_Type;
在配置中断的时候我们一般只用 ISER、 ICER 和 IP 这三个寄存器, ISER 用来使能中
断, ICER 用来失能(清除)中断, IP 用来设置中断优先级。
在 NVIC 有一个专门的寄存器:中断优先级寄存器 NVIC_IPRx, 用来配置外部中断的
优先级, IPR 宽度为 8bit。在F103 中,只使用了高 4bit。
用于表达优先级的这 4bit,又被分组成抢占优先级和子优先级。如果有多个中断同时
响应,抢占优先级高的就会 抢占 抢占优先级低的优先得到执行,如果抢占优先级相同,就
比较子优先级。如果抢占优先级和子优先级都相同的话,就比较他们的硬件中断编号,编
号越小,优先级越高。
编程要点
- 初始化用来产生中断的 GPIO;
- 初始化 EXTI;
- 配置 NVIC;
- 编写中断服务函数;
/*********************EXIT.C文件************************/
#include "EXIT.h"
void NVIC_COFIG(){
NVIC_InitTypeDef NVIC_Initstruct;
//NVIC初始化
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);//选择优先级分组
NVIC_Initstruct.NVIC_IRQChannel = EXTI0_IRQn;//配置NVIC中断源
NVIC_Initstruct.NVIC_IRQChannelPreemptionPriority = 1;//主优先级为1;
NVIC_Initstruct.NVIC_IRQChannelSubPriority = 1;//子优先级为1;
NVIC_Initstruct.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_Initstruct);
}
void EXIT_CONFIG(){
GPIO_InitTypeDef EXIT_GPIO;
EXTI_InitTypeDef EXIT_Initstruct;
NVIC_COFIG();
//开时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
//GPIO口初始化
EXIT_GPIO.GPIO_Pin = GPIO_Pin_0;
EXIT_GPIO.GPIO_Mode = GPIO_Mode_IN_FLOATING;
GPIO_Init(EXIT_GPIO_PORT,&EXIT_GPIO);
//EXIT初始化
RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);
GPIO_EXTILineConfig(GPIO_PortSourceGPIOA, GPIO_PinSource0);//选择EXIT的中断源
EXIT_Initstruct.EXTI_Line = EXTI_Line0;
EXIT_Initstruct.EXTI_LineCmd = ENABLE;//使能该中断线
EXIT_Initstruct.EXTI_Trigger = EXTI_Trigger_Rising_Falling;//上升沿触发
EXIT_Initstruct.EXTI_Mode = EXTI_Mode_Interrupt;//选择中断
EXTI_Init(&EXIT_Initstruct);
}