STM32的每个I/O都可以作为外部中断的中断输入口,每个中断设有状态位,每个中断/事件都有独立的触发和屏蔽设置。这里使用的外部中断来检测按键,下面是相关配置代码~
void EXTIX_Init()
{
GPIO_InitTypeDef GPIO_InitStructure;
EXTI_InitTypeDef EXTI_InitStructure;
NVIC_InitTypeDef NVIC_InitStructure;
/* Enable Button(GPIOA) clock 使能I/O口时钟*/
RCC_AHBPeriphClockCmd(User_Button_GPIO_CLK, ENABLE);
/* Enable SYSCFG clock 使能系统时钟*/
RCC_APB2PeriphClockCmd(RCC_APB2Periph_SYSCFG, ENABLE);
//I/O口配置为输入
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;
GPIO_Init(GPIOA, &GPIO_InitStructure);
/* 外部中断配置 */
SYSCFG_EXTILineConfig(EXTI_PortSourceGPIOA, EXTI_PinSource3);
EXTI_InitStructure.EXTI_Line = EXTI_Line3;
EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;
EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising;
EXTI_InitStructure.EXTI_LineCmd = ENABLE;
EXTI_Init(&EXTI_InitStructure);
/* 中断优先级配置 */
NVIC_InitStructure.NVIC_IRQChannel = EXTI2_3_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPriority = 0x00;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
}
初始化对I/O口,外部中断线,中断优先级做配置,接着还要编写中断服务函数,A8,M3,M4等都可以自己在中断初始化配置时自定义中断服务函数名,而在M0中只能直接调用库函数给我们准备好的中断函数名。
//上面我们用的是A3脚,所以是触发EXTI2_3_IRQHandler函数
void EXTI2_3_IRQHandler(void)
{
//检测中断位状态
if(EXTI_GetITStatus(EXTI_Line3) != RESET)
{
//产生中断时的对应操作
Key_Flag = true;
Key_Value1 = 1;
//产生中断,清除中断位
EXTI_ClearITPendingBit(EXTI_Line3);
}
}
EXTI2_3_IRQHandler()
函数为 EXTI_Line2
、 EXTI_Line3
中断线共用,即是PA2、PA3是共用同一个中断服务函数,类似的 EXTI4_15_IRQHandler
是中断线4-15的中断服务函数,这里就有个疑问了,这么多中断线都是跑同一个函数,那要怎么区分不同中断线的操作呢?!细心的朋友可能已经找到答案了~ if(EXTI_GetITStatus(EXTI_Line3) != RESET)
进入中断服务函数后都会先进行一个 if 判断,即检测该中断线是否发生中断,例如我设置了PA2、PA3为两外部中断,那么我的中断服务函数应该是这么写,I/O初始化那些的另行配置
void EXTI2_3_IRQHandler(void)
{
if(EXTI_GetITStatus(EXTI_Line2) != RESET)
{
//code
//产生中断,清除中断位
EXTI_ClearITPendingBit(EXTI_Line2);
}
if(EXTI_GetITStatus(EXTI_Line3) != RESET)
{
//code
//产生中断,清除中断位
EXTI_ClearITPendingBit(EXTI_Line3);
}
}
4-15的中断也是一样的道理,还有注意一点就是中断函数中不要调用延时函数,中断是一个很快的操作,在其中加入延时会引发不必要的错误,可以是修改变量的状态来达到某个目的,但需要考虑项目耦合性。
总结一下使用I/O口外部中断的一般步骤:
- 定义结构体,使能I/O、系统时钟
- 初始化I/O口为输入
- 初始化线上中断,设置触发条件等
- 配置中断分组(NVIC),并使能中断
- 编写中断服务函数