前言
本文教大家使用外部中断,通过连接按键到IO口,利用中断控制单片机内部程序。 使用器材:STM32F407
一、STM32F4 外部中断简介
STM32F4 的每个 IO 都可以作为外部中断的中断输入口,STM32设计GPIO 的管脚GPIOx.0~GPIOx.15(x=A,B,C,D,E,F,G,H,I)分别对应中断线 0~15。这样每个中断线对应了最多 9 个 IO 口,以线 0 为例:它对应了 GPIOA.0、GPIOB.0、GPIOC.0、GPIOD.0、GPIOE.0、GPIOF.0、GPIOG.0,GPIOH.0,GPIOI.0。而中断线每次只能连接到 1 个 IO口上,这样就需要通过配置来决定对应的中断线配置到哪个 GPIO 上了。 GPIO跟中断线的映射关系图:
二、编程要点
- 使能 IO 口时钟,初始化 IO 口为输入;
- 配置 NVIC;
- 配置按键 GPIO 为输入模式;
- 将按键 GPIO 连接到 EXTI 源输入;
- 配置按键 EXTI 中断/事件线;
- 编写 EXTI 中断服务函数。
相关宏定义如下
#define KEY1_INT_GPIO_PORT GPIOC
#define KEY1_INT_GPIO_CLK RCC_AHB1Periph_GPIOC
#define KEY1_INT_GPIO_PIN GPIO_Pin_9
#define KEY1_INT_EXTI_PORTSOURCE EXTI_PortSourceGPIOC
#define KEY1_INT_EXTI_PINSOURCE EXTI_PinSource9
#define KEY1_INT_EXTI_LINE EXTI_Line9
#define KEY_INT_EXTI_IRQ EXTI9_5_IRQn
#define KEY_IRQHandler EXTI9_5_IRQHandler
1、使能 IO 口时钟,初始化 IO 口为输入
首先,我们要使用 IO 口作为中断输入,所以我们要使能相应的 IO 口时钟,以及初始化相 应的 IO 口为输入模式
GPIO_InitTypeDef GPIO_InitStructure;
RCC_AHB1PeriphClockCmd(KEY1_INT_GPIO_CLK,ENABLE);
GPIO_InitStructure.GPIO_Pin = KEY1_INT_GPIO_PIN;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;
GPIO_Init(KEY1_INT_GPIO_PORT,&GPIO_InitStructure);
2.开启 SYSCFG 时钟,设置 IO 口与中断线的映射关系。
1、我们要配置 GPIO 与中断线的映射关系,那么我们首先需要打开 SYSCFG 时钟。这里大家一定要注意,只要我们使用到外部中断,就必须打开 SYSCFG 时钟。 2、我们配置 GPIO 与中断线的映射关系。在库函数中,配置 GPIO 与中断线的映射关系的函数 SYSCFG_EXTILineConfig ()来实现的:
RCC_APB2PeriphClockCmd(RCC_APB2Periph_SYSCFG, ENABLE);
SYSCFG_EXTILineConfig(KEY1_INT_EXTI_PORTSOURCE,KEY1_INT_EXTI_PINSOURCE);
3、 初始化线上中断,设置触发条件等。
SYSCFG_EXTILineConfig(KEY1_INT_EXTI_PORTSOURCE,KEY1_INT_EXTI_PINSOURCE);
EXTI_InitStructure.EXTI_Line = KEY1_INT_EXTI_LINE;
EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;
EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling;
EXTI_InitStructure.EXTI_LineCmd = ENABLE;
EXTI_Init(&EXTI_InitStructure);
4、配置中断分组(NVIC),并使能中断。
static void NVIC_Configuration(void)
{
NVIC_InitTypeDef NVIC_InitStructure;
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);
NVIC_InitStructure.NVIC_IRQChannel = KEY_INT_EXTI_IRQ;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
}
5、编写中断服务函数。
我们配置完中断优先级之后,接着要做的就是编写中断服务函数。中断服务函数的名字是 在 MDK 中事先有定义的。这里需要说明一下,STM32F4 的 IO 口外部中断函数只有 7 个,分 别为:
EXPORT EXTI0_IRQHandler
EXPORT EXTI1_IRQHandler
EXPORT EXTI2_IRQHandler
EXPORT EXTI3_IRQHandler
EXPORT EXTI4_IRQHandler
EXPORT EXTI9_5_IRQHandler
EXPORT EXTI15_10_IRQHandler
中断线 0-4 每个中断线对应一个中断函数,中断线 5-9 共用中断函数 EXTI9_5_IRQHandler,中 断线 10-15 共用中断函数 EXTI15_10_IRQHandler。在编写中断服务函数的时候会经常使用到两 个函数。 第一个函数是判断某个中断线上的中断是否发生(标志位是否置位):
ITStatus EXTI_GetITStatus(uint32_t EXTI_Line);
这个函数一般使用在中断服务函数的开头判断中断是否发生。另一个函数是清除某个中断线上 的中断标志位:
void EXTI_ClearITPendingBit(uint32_t EXTI_Line);
这个函数一般应用在中断服务函数结束之前,清除中断标志位。 常用的中断服务函数格式为
void EXTI3_IRQHandler(void)
{
if(EXTI_GetITStatus(EXTI_Line3)!=RESET)
{ …中断逻辑…
EXTI_ClearITPendingBit(EXTI_Line3);
}
}
在这里需要说明一下,固件库还提供了两个函数用来判断外部中断状态以及清除外部状态: 标志位的函数 EXTI_GetFlagStatus 和 EXTI_ClearFlag,他们的作用和前面两个函数的作用类似。 只是在 EXTI_GetITStatus 函数中会先判断这种中断是否使能,使能了才去判断中断标志位,而 EXTI_GetFlagStatus 直接用来判断状态标志位。
6、在main函数中初始化按键的配置
一定要记得在main函数中调用这些初始化函数,很多新手小白就是一老忘记这件事(我),烧录程序之后按键没反应,对着代码看了半天也想不明白哪里配置错了。
总结
1)使能 IO 口时钟,初始化 IO 口为输入。 2)使能 SYSCFG 时钟,设置 IO 口与中断线的映射关系。 3)初始化线上中断,设置触发条件等。 4)配置中断分组(NVIC),并使能中断。 5)编写中断服务函数。 6)在main函数中初始化按键的配置 通过以上几个步骤的设置,我们就可以正常使用外部中断了。
|