外部中断
HAL库基本使用系列的 全部博客是我重新学习HAL库的学习记录,仅作为学习记录。其中使用了正点原子Mini开发板和正点原子HAL库Demo,详细的资料请观看正点原子官网
本来计划写一下串口的使用,但是前面的博客里面已经介绍到了串口的文件夹以及串口的初始化以及基本使用,最多就是在加一个中断处理函数,对接收到的数据进行处理,关于串口不同中断的区别,后期单独介绍。
STM32F1 的每个 IO 都可以作为外部中断的中断输入口,中断控制器支持 19个外部中断/事件请求。每个中断设有状态位,每个中断/事件都有独立的触发和屏蔽设置。
STM32F103 的 19 个外部中断为:
EXTI 线 0~15:对应外部 IO 口的输入中断。
EXTI 线 16:连接到 PVD 输出。
EXTI 线 17:连接到 RTC 闹钟事件。
EXTI 线 18:连接到 USB 唤醒事件。
EXTI 线 19:连接到以太网唤醒事件。
STM32通过映射关系,把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。而中断线每次只能连接到 1 个 IO 口上,这样就需要通过配置来决定对应的中断线配置到哪个 GPIO 上了。
IO 口外部中断的一般步骤:
1)使能 IO 口时钟。
2)调用函数 HAL_GPIO_Init 设置 IO 口模式,触发条件,使能 SYSCFG 时钟以及设置 IO
口与中断线的映射关系。
3)配置中断优先级(NVIC),并使能中断。
4)在中断服务函数中调用外部中断共用入口函数 HAL_GPIO_EXTI_IRQHandler。
5)编写外部中断回调函数 HAL_GPIO_EXTI_Callback。
1、外部中断配置
1.1、初始化中断I/O,设置触发条件
I/O作为中断,那么端口输入模式为输入模式。
GPIO_InitTypeDef GPIO_Initure;
__HAL_RCC_GPIOA_CLK_ENABLE(); //开启GPIOA时钟
__HAL_RCC_GPIOC_CLK_ENABLE(); //开启GPIOC时钟
GPIO_Initure.Pin=GPIO_PIN_0; //PA0
GPIO_Initure.Mode=GPIO_MODE_IT_RISING; //上升沿触发
GPIO_Initure.Pull=GPIO_PULLDOWN;
HAL_GPIO_Init(GPIOA,&GPIO_Initure);
GPIO_Initure.Pin=GPIO_PIN_15; //PA15
GPIO_Initure.Mode=GPIO_MODE_IT_FALLING; //下降沿触发
GPIO_Initure.Pull=GPIO_PULLUP;
HAL_GPIO_Init(GPIOA,&GPIO_Initure);
GPIO_Initure.Pin=GPIO_PIN_5; //PC5
HAL_GPIO_Init(GPIOC,&GPIO_Initure);
通过定位查找,可以看到中断模式的设置有如下几种:
GPIO_MODE_IT_RISING(外部中断上升沿触发),
GPIO_MODE_IT_FALLING (外部中断下降沿触发)
GPIO_MODE_IT_RISING_FALLING(外部中断双边沿触发)
该函数内部会通过判断Mode 的值来开启 SYSCFG 时钟,并且设置 IO 口和中断线的映射关系。
初始化了PA0,如果PB0在初始化中断,那么PA0的中断映射将会被清除。
1.2、配置中断优先级(NVIC),并使能中断。
设置好了中断的触发模式等初始化参数。既然是外部中断,涉及到中断我们当然还要设置 NVIC 中断优先级。
//中断线0-PA0
HAL_NVIC_SetPriority(EXTI0_IRQn,2,2); //抢占优先级为2,子优先级为2
HAL_NVIC_EnableIRQ(EXTI0_IRQn); //使能中断线0
//中断线5-PC5
HAL_NVIC_SetPriority(EXTI9_5_IRQn,2,1); //抢占优先级为2,子优先级为1
HAL_NVIC_EnableIRQ(EXTI9_5_IRQn);
//中断线15-PA15
HAL_NVIC_SetPriority(EXTI15_10_IRQn,2,0); //抢占优先级为2,子优先级为0
HAL_NVIC_EnableIRQ(EXTI15_10_IRQn); //使能中断线15
外部中断的5-9,10-15各自共用了一个通道EXTI15_10_IRQn以及EXTI9_5_IRQn,如图所示:
1.3、编写中断服务函数。
中断服务函数的名字是在 HAL 库中事先有定义的。STM32F1 的 IO 口外部中断函数只有 7 个,分别为:
void EXTI0_IRQHandler();
void EXTI1_IRQHandler();
void EXTI2_IRQHandler();
void EXTI3_IRQHandler();
void EXTI4_IRQHandler();
void EXTI9_5_IRQHandler();
void EXTI15_10_IRQHandler();
 通过上面的图中我们也可以知道中断线 0-4 每个中断线对应一个中断函数,中断线 5-9 共用中断函数 EXTI9_5_IRQHandler,中断线 10-15 共用中断函数EXTI15_10_IRQHandler。
//中断服务函数
void EXTI0_IRQHandler(void)
{
HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_0); //调用中断处理公用函数
}
void EXTI9_5_IRQHandler(void)
{
HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_5); //调用中断处理公用函数
}
void EXTI15_10_IRQHandler(void)
{
HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_15); //调用中断处理公用函数
}
1.4、编写中断处理回调函数 HAL_GPIO_EXTI_Callback
通过查找可以看到HAL_GPIO_EXTI_Callback函数是HAL库定义的弱函数,我们可以重新定义新的回调函数,并且编写中断函数控制逻辑。
提 供 了一个中断通用入口 函 数HAL_GPIO_EXTI_IRQHandler,在该函数内部直接调用回调函数 HAL_GPIO_EXTI_Callback。
void HAL_GPIO_EXTI_IRQHandler(uint16_t GPIO_Pin)
{
if(__HAL_GPIO_EXTI_GET_IT(GPIO_Pin) != 0x00u)
{
__HAL_GPIO_EXTI_CLEAR_IT(GPIO_Pin);
HAL_GPIO_EXTI_Callback(GPIO_Pin);
}
}
该函数实现的作用非常简单,就是清除中断标志位,然后调用回调函数
HAL_GPIO_EXTI_Callback()实现控制逻辑。
//中断服务程序中需要做的事情
//在HAL库中所有的外部中断服务函数都会调用此函数
//GPIO_Pin:中断引脚号
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{
delay_ms(100); //消抖
switch(GPIO_Pin)
{
case GPIO_PIN_0:
if(WK_UP==1)
{
LED1=!LED1; //控制LED0,LED1互斥点亮
LED0=!LED1;
}
break;
case GPIO_PIN_5:
if(KEY0==0) //控制LED0翻转
{
LED0=!LED0;
}
break;
case GPIO_PIN_15:
if(KEY1==0)
{
LED1=!LED1; //控制LED0翻转
}
break;
}
}