STM32 外部中断
摘要
本文介绍STM32配置的步骤以及相关的步骤,通过触发按键外部中断实现摁键点灯操作,即摁下摁键,触发中断,LED灯亮,松开LED灯灭。
STM32外部中断简介
STM32 的每个 IO 都可以作为外部中断的中断输入口, STM32F103 的中断控制器支持 19 个外部中断/事件请求。每个中断设有状态位,每个中断/事件都有独立的触发和屏蔽设置。 STM32F103 的19 个外部中断为:
线 0~15:对应外部 IO 口的输入中断。
线 16:连接到 PVD 输出。
线 17:连接到 RTC 闹钟事件。
线 18:连接到 USB 唤醒事件。
所以STM32可以作为GPIO外部中断的线路共有16个,其具体的映射关系如下:
STM32F1外部中断配置的一般步骤如下:
1)将对应的GPIO口初始化维输入模式
2)开启AFIO时钟,开启端口的复用
3)根据GPIO和中断的映射关系配置IO口与中断的映射关系
4)初始化GPIO外部中断线,并设置触发条件等内容
5)配置中断,包括使能中断和为中断分组等
6)根据项目需求配置中断服务程序
预实现的功能
摁下UP_LED对应的按键,点亮UP引脚连接的LED灯,松开UP_LED按键,熄灭LED引脚连接的LED灯。
程序代码
端口宏定义:、
/*配置GPIO输入模式*/
#define UP_LED_PORT GPIOB
#define UP_LED_PIN GPIO_Pin_3
#define UP_LED_RCC RCC_APB2Periph_GPIOB
#define UP_LED_Mode GPIO_Mode_IPU //上拉输入
#define UP_LED_Speed GPIO_Speed_50MHz
/*配置GPIO外部中断相关的信息 按键接在PB3,对应的3号中断线和USART3_IRQ中断*/
#define UP_LED_EXTI_PORT GPIO_PortSourceGPIOB
#define UP_LED_EXTI_Source GPIO_PinSource3
#define UP_LED_EXTI_LINE EXTI_Line3
#define UP_LED_EXTI_MODE EXTI_Mode_Interrupt
#define UP_LED_EXTI_TRIGGER EXTI_Trigger_Rising_Falling //上升下降沿触发
#define UP_LED_NVIC_IRQChannel EXTI3_IRQn
/*配置UP对应的LED状态,推挽输出*/
#define UP_PORT GPIOD
#define UP_PIN GPIO_Pin_2
#define UP_RCC RCC_APB2Periph_GPIOD
#define UP_Mode GPIO_Mode_Out_PP //push pull
#define UP_Speed GPIO_Speed_50MHz
/*宏定义LED灯电平状态*/
#define UP(x) x?GPIO_SetBits(UP_PORT,UP_PIN):GPIO_ResetBits(UP_PORT,UP_PIN)
#define UP_Elevator_LED_ON UP(0) //电梯按钮亮
#define UP_Elevator_LED_OFF UP(1) //电梯按钮灭
/*宏定义UP_LED 读取电平状态*/
#define READ_UP_LED GPIO_ReadInputDataBit(UP_LED_PORT,UP_LED_PIN)
LED对应的引脚功能初始化: 推挽输出模式
void Elevator_LED_Configuration(void)
{
GPIO_InitTypeDef Elevator_GPIO_InitStruct;
RCC_APB2PeriphClockCmd(UP_RCC,ENABLE); //ENABLE the CLOCK
/*初始化UP的引脚功能,推挽输出模式*/
Elevator_GPIO_InitStruct.GPIO_Pin = UP_PIN;
Elevator_GPIO_InitStruct.GPIO_Mode = UP_Mode;
Elevator_GPIO_InitStruct.GPIO_Speed = UP_Speed;
GPIO_Init(UP_PORT,&Elevator_GPIO_InitStruct);
/*设置默认输出状态*/
UP_Elevator_LED_OFF;
}
按钮对应的引脚功能初始化,上拉输入
void Elevator_Key_Configuration(void)
{
GPIO_InitTypeDef Elevator_GPIO_InitStruct;
RCC_APB2PeriphClockCmd(UP_LED_RCC,ENABLE); //ENABLE the CLOCK
/*初始化UP_LED的引脚功能,输入模式*/
Elevator_GPIO_InitStruct.GPIO_Pin = UP_LED_PIN;
Elevator_GPIO_InitStruct.GPIO_Mode = UP_LED_Mode;
Elevator_GPIO_InitStruct.GPIO_Speed = UP_LED_Speed;
GPIO_Init(UP_LED_PORT,&Elevator_GPIO_InitStruct);
}
按键对应的引脚外部中断初始化配置。
void Elevator_Key_EXTI_Configuration(void)
{
EXTI_InitTypeDef Elevator_Key_EXTI_InitStructure;
NVIC_InitTypeDef Elevator_Key_NVIC_InitStructure;
Elevator_Key_Configuration(); //初始化电梯按钮为输入模式
RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE); //开始AFIO时钟
/*配置UP_LED对应的电梯按钮中断线*/
GPIO_EXTILineConfig(UP_LED_EXTI_PORT,UP_LED_EXTI_Source);
Elevator_Key_EXTI_InitStructure.EXTI_Line = UP_LED_EXTI_LINE;
Elevator_Key_EXTI_InitStructure.EXTI_Mode = UP_LED_EXTI_MODE;
Elevator_Key_EXTI_InitStructure.EXTI_Trigger = UP_LED_EXTI_TRIGGER; //配置触发方式,下降沿触发
Elevator_Key_EXTI_InitStructure.EXTI_LineCmd = ENABLE;
EXTI_Init(&Elevator_Key_EXTI_InitStructure);
Elevator_Key_NVIC_InitStructure.NVIC_IRQChannel = UP_LED_NVIC_IRQChannel; //使能外部中断通道
Elevator_Key_NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x02;
Elevator_Key_NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x02;
Elevator_Key_NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&Elevator_Key_NVIC_InitStructure);
}
中断服务程序,本次项目中需要同时检测摁下和松手,所以配置成上升下降沿触发,所以无论是摁下还是松开均会触发中断服务函数,通过以下中断服务程序的处理便实现当按键摁下时,对应的LED灯亮,松开即关闭的效果。
void EXTI3_IRQHandler(void)
{
if(READ_UP_LED==RESET) //检测到下降沿,即摁键摁下
{
UP_Elevator_LED_ON; //点亮内部LED灯
UP_KeyMode = 1; //摁下标志位置1
}
else //检测到上升沿,即摁键弹起
{
UP_Elevator_LED_OFF; //熄灭内部LED灯
UP_KeyMode = 0; //复位摁下标志位
}
EXTI_ClearITPendingBit(UP_LED_EXTI_LINE);//清除中断线路
}
虽然本文所提的控制目标也可以使用扫描的方式实现,但是在实际项目中,为了提高系统响应的灵敏度,通常建议使用触发中断的方式检测按键。