外部中断
认识外部中断
STM32的外部中断是一种用于检测和响应外部事件的机制。它允许微控制器在发生特定的外部信号变化时,立即暂停当前执行的任务,转而执行一个中断服务例程(ISR)。这对于处理时间敏感的任务,如按钮按下、传感器信号变化等,非常重要。
STM32芯片有19个EXTI外部中断源,其中GPIO外部中断源16个,分别对应7个中断向量,即对应着7个中断服务函数。
外部中断的触发条件
- 下降沿触发(Falling Edge Trigger)
条件:当外部信号从高电平变为低电平时触发中断。
应用:适用于需要对信号的负跳变进行响应的场合,例如检测按钮的按下。 - 上升沿触发(Rising Edge Trigger)
条件:当外部信号从低电平变为高电平时触发中断。
应用:适用于需要对信号的正跳变进行响应的场合,例如检测按钮的释放。 - 双沿触发(Both Edge Trigger)
条件:当外部信号在上升沿或下降沿时都会触发中断。
应用:适用于需要对信号的任何边沿变化都进行响应的场合,例如高频信号的边沿检测。 - 电平触发(Level Trigger)
条件:当外部信号保持在特定电平(高或低)时触发中断。STM32F103中不直接支持电平触发,但可以通过外部电路来实现电平触发的效果。
应用:适用于需要对信号电平状态变化的监控,但通常需要额外的电路来转换为边沿触发的信号。
注意:所有的GPIO口都可以触发中断,但相同的Pin号不能同时触发中断。
代码示例
配置过程中我们需要使用到一些库函数,如GPIO库函数、RCC库函数、EXTI库函数、NVIC库函数。
除了GPIO的基本配置函数,这里还需使用GPIO库函数的最后一个,即选择GPIO管脚用作外部中断线路。
我们需要使能GPIO的时钟、AFIO的时钟、外部中断的时钟。
根据功能要求使用相应的EXTI库函数。
NVIC库函数提供了对中断控制和管理的全面支持,包括中断使能、禁用、优先级设置和优先级分组等功能。
static void ConfigEXTIGPIO(void)
{
GPIO_InitTypeDef GPIO_InitStructure; //GPIO_InitStructure用于存放GPIO的参数
//使能RCC相关时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); //使能GPIOA的时钟
//配置PA0
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0; //设置引脚
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU; //设置输入类型
GPIO_Init(GPIOA, &GPIO_InitStructure); //根据参数初始化GPIO
}
初始化PA0引脚,对应STM32板子上的KEY3。
static void ConfigEXTI(void)
{
EXTI_InitTypeDef EXTI_InitStructure; //EXTI_InitStructure用于存放EXTI的参数
NVIC_InitTypeDef NVIC_InitStructure; //NVIC_InitStructure用于存放NVIC的参数
//使能RCC相关时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE); //使能AFIO的时钟
//配置PA0的EXTI和NVIC
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
NVIC_InitStructure.NVIC_IRQChannel = EXTI0_IRQn; //中断通道号
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2; //设置抢占优先级
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 2; //设置响优先级
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //使能中断
NVIC_Init(&NVIC_InitStructure); //根据参数初始化NVIC
}
- EXTI_InitTypeDef EXTI_InitStructure; 和 NVIC_InitTypeDef NVIC_InitStructure;定义了两个结构体,用于存储 EXTI 和 NVIC 的初始化配置参数。
- RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);使能 AFIO外设的时钟,这是配置外部中断所必须的。AFIO 允许将 GPIO引脚配置为外部中断源。
- GPIO_EXTILineConfig(GPIO_PortSourceGPIOA, GPIO_PinSource0);配置GPIOA 的第 0 引脚(PA0)为外部中断源 EXTI0。这是将具体的 GPIO 引脚映射到 EXTI 线的步骤。
- EXTI_InitStructure.EXTI_Line = EXTI_Line0;选择 EXTI0 作为外部中断线。STM32 的EXTI 线用于处理外部信号中断。
- EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;配置为中断模式。中断模式会在触发条件满足时产生中断请求。
- EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising;设置中断触发条件为上升沿触发。即当 PA0 引脚检测到上升沿时,会产生中断。
- EXTI_InitStructure.EXTI_LineCmd = ENABLE;使能 EXTI0 中断线,表示启用配置好的中断线。
- EXTI_Init(&EXTI_InitStructure);根据配置参数初始化 EXTI 外部中断线。
- NVIC_InitStructure.NVIC_IRQChannel = EXTI0_IRQn;设置 NVIC 中断通道为EXTI0 中断通道,NVIC 用于中断管理。
- NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2;:设置 EXTI0中断的抢占优先级为 2。抢占优先级用于确定中断是否可以打断当前正在执行的中断。
- NVIC_InitStructure.NVIC_IRQChannelSubPriority = 2;设置 EXTI0中断的响应优先级为 2。响应优先级用于在同一抢占优先级下决定中断的优先处理顺序。
- NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;使能 EXTI0 中断通道。
- NVIC_Init(&NVIC_InitStructure);根据配置参数初始化 NVIC 中断控制器。
这段代码的目的是配置外部中断线 EXTI0,并设置中断触发条件、优先级等,使得当 PA0 引脚检测到上升沿时,会产生中断请求并由处理器处理。
void EXTI0_IRQHandler(void)
{
if(EXTI_GetITStatus(EXTI_Line0) != RESET) //判断中断是否发生
{
//LED1状态取反
GPIO_WriteBit(GPIOC, GPIO_Pin_4, (BitAction)(1 - GPIO_ReadOutputDataBit(GPIOC, GPIO_Pin_4)));
//LED2状态取反
GPIO_WriteBit(GPIOC, GPIO_Pin_5, (BitAction)(1 - GPIO_ReadOutputDataBit(GPIOC, GPIO_Pin_5)));
EXTI_ClearITPendingBit(EXTI_Line0); //清除Line0上的中断标志位
}
}
上述代码实现的是,按键KEY3每按下一次,LED1和LED2状态进行一次翻转。