STM32有许多的中断,为了方便配置,因此内部设有一个强大而方便的中断控制器NVIC,它属于Cortex内核器件,不可屏蔽中断(NMI)和外部中断都有它来处理。
在固件库中对NVIC初始化,有个NIVC-InitTypeDef类型的结构体,定义如下:
typedef struct
{
uint8_t NVIC_IRQChannel; //需要配置的中断向量
uint8_t NVIC_IRQChannelPreemptionPriority; //配置相应中断向量抢占优先级
uint8_t NVIC_IRQChannelSubPriority; //配置相应中断向量响应优先级
FunctionalState NVIC_IRQChannelCmd; //使能或关闭相应的中断向量的中断优先级
} NVIC_InitTypeDef;
STM32的中断向量具有两个属性,一个为抢占,另一个为响应属性,其编号越小说明它的优先级越高。
-
-
- 抢占:是指打断其他中断的属性,即因为具有这个属性会出现嵌套中断;
- 响应:应用在抢占属性相同的情况下,当两个中断向量的抢占优先级相同时,如果两个中断同时到达,则先处理响应优先级高 的中断。
-
NVIC优先级组:
NVIC只可以配置16种中断向量的优先级,即抢占优先级和响应优先级的数量由一个4位数字决定,将4位数字位数分配成抢占优先级和响应优先级,有5种分组方式:
-
-
- 第0组:所用4位用来配置响应优先级,即16种中断向量具有不同的响应优先级;
- 第1组:最高1位配置抢占优先级,低3位配置响应优先级,表示有2种级别的抢占优先级(0~1),8种响应优先级(0~7), 即在16种中断向量中,有8种中断抢占优先级都为0级,而它们的响应优先级分别为0~7,其余8种中断向量的抢占优 先级则都为1,响应优先级为0~7;
- 第2组:2位配置抢占优先级,2位配置响应优先级,即4种抢占优先级,4种响应优先级;
- 第3组:高3位配置抢占优先级,最低1位配置响应优先级;
- 第4组:所有4位用来配置抢占优先级,即16种中断向量都是只有抢占属性,没有响应属性。
-
配置嵌套向量中断控制器,代码如下:
static void NVIC_Initstructucture(void) { NVIC_InitTypeDef NVIC_Initstructure; NVIC_PriorityGropConfig(NVIC_PriorityGrop_1);
NVIC_Initstructure.NVIC_IRQChannel=EXTI9_5_IRQn;
NVIC_Initstructure.NVIC_IRQChannelPreemptionPriority=0
NVIC_Initstructure.NVIC_IRQChannelSubPriority=0
NVIC_Initstructure.NVIC_IRQChannelCmd=ENABLE;
NVIC_Init(&NVIC_InitStructure);
}
本代码调用了NVIC—PriorityGroupConfig()库函数,将NVIC中断优先级分组设置为第1组,EXTI9_5_IRQn表示要配置的EXTI第5~9线的中断向量(PE5)。在文件stm32f10x.h文件中,可以找到IRQn类型的定义,
#ifdef STM32F10X_LD_VL
ADC1_IRQn = 18, /*!< ADC1 global Interrupt */
EXTI9_5_IRQn = 23, /*!< External Line[9:5] Interrupts */
TIM1_BRK_TIM15_IRQn = 24, /*!< TIM1 Break and TIM15 Interrupts */
TIM1_UP_TIM16_IRQn = 25, /*!< TIM1 Update and TIM16 Interrupts */
TIM1_TRG_COM_TIM17_IRQn = 26, /*!< TIM1 Trigger and Commutation and TIM17 Interrupt */
TIM1_CC_IRQn = 27, /*!< TIM1 Capture Compare Interrupt */
TIM2_IRQn = 28, /*!< TIM2 global Interrupt */
TIM3_IRQn = 29, /*!< TIM3 global Interrupt */
I2C1_EV_IRQn = 31, /*!< I2C1 Event Interrupt */
I2C1_ER_IRQn = 32, /*!< I2C1 Error Interrupt */
SPI1_IRQn = 35, /*!< SPI1 global Interrupt */
USART1_IRQn = 37, /*!< USART1 global Interrupt */
USART2_IRQn = 38, /*!< USART2 global Interrupt */
EXTI15_10_IRQn = 40, /*!< External Line[15:10] Interrupts */
RTCAlarm_IRQn = 41, /*!< RTC Alarm through EXTI Line Interrupt */
CEC_IRQn = 42, /*!< HDMI-CEC Interrupt */
TIM6_DAC_IRQn = 54, /*!< TIM6 and DAC underrun Interrupt */
TIM7_IRQn = 55 /*!< TIM7 Interrupt */
#endif /* STM32F10X_LD_VL */
外部中断配置:
void EXTI—PE5—Config() { GPIO_InitTypeDef GPIO_Initstructure; EXTI_InitTypeDef EXTI_Initstructure;
NVIC—Configuration(); RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOE|RCC_APB2Periph_AFIO, ENABLE); //打开端口时钟及复用时钟 GPIO_EXTILineConfig(GPIO_PortSourceGPIOE,GPIO_PinSource5); EXTI_ClearFlag(EXTI_Line5); //清楚中断标志位 EXTI_Initstructure.EXTI_Line=EXTI_Line5; EXTI_Initstructure.EXTI_Mode=EXTI_Mode_Interrupt; EXTI_Initstructure.EXTI_Trigger=EXTI_Trigger_Falling; //下降沿触发 EXTI_Initstructure.EXTI_LineCmd=ENABLE; EXTI_Init(&EXTI_Initstructure); }
编写中断服务程序:
在EXTI设置中将PE5连接到内部的EXTI5,GPIO配置为上拉输入,工作在下降沿中断。在stm32f10x—it.c文件中是专门用来存放中断服务程序的,而且都是空函数,在需要的时候自行编写。但是中断服务函数的名字必须要与启动文件startup_stm32f10x_hd.s中的中断向量表定义一致,其定义的部分向量表代码如下:
DCD EXTI0_IRQHandler ; EXTI Line 0 DCD EXTI1_IRQHandler ; EXTI Line 1 DCD EXTI2_IRQHandler ; EXTI Line 2 DCD EXTI3_IRQHandler ; EXTI Line 3 DCD EXTI4_IRQHandler ; EXTI Line 4 DCD DMA1_Channel1_IRQHandler ; DMA1 Channel 1 DCD DMA1_Channel2_IRQHandler ; DMA1 Channel 2 DCD DMA1_Channel3_IRQHandler ; DMA1 Channel 3 DCD DMA1_Channel4_IRQHandler ; DMA1 Channel 4 DCD DMA1_Channel5_IRQHandler ; DMA1 Channel 5 DCD DMA1_Channel6_IRQHandler ; DMA1 Channel 6 DCD DMA1_Channel7_IRQHandler ; DMA1 Channel 7 DCD EXTI9_5_IRQHandler ; EXTI Line 9..5 DCD TIM1_BRK_IRQHandler ; TIM1 Break DCD TIM1_UP_IRQHandler ; TIM1 Update DCD TIM1_TRG_COM_IRQHandler ; TIM1 Trigger and Commutation DCD EXTI15_10_IRQHandler ; EXTI Line 15..10
根据外部中断为PE5,因此中断服务程序如下:
void EXTI9_5_IRQHandler(void)
{
if(EXTI_GetITStatus(EXTI_Lint5)!=REST) //确认是否产生了中断
{
中断服务程序;
EXTI_ClearFlag(EXTI_Line13); //清楚中断标志位
}
}