PY32F003F18的GPIO外部中断源:EXTI0_1_IRQn,EXTI2_3_IRQn和EXTI4_15_IRQn,与之对应的中断函数为EXTI0_1_IRQHandler(),EXTI2_3_IRQHandler()和EXTI4_15_IRQHandler()。
PY32F003F18的外部中断服务函数通过调用HAL_GPIO_EXTI_IRQHandler(uint16_t GPIO_Pin),才能实现调用其Callback函数HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)。
因此,HAL_GPIO_EXTI_IRQHandler(uint16_t GPIO_Pin)和HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)是外部中断调用的公共函数。函数原型如下:
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);
//GPIOx外部中断回调函数
}
}
__weak void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{
/* Prevent unused argument(s) compilation warning */
UNUSED(GPIO_Pin);
/* NOTE: This function should not be modified, when the callback is needed,
the HAL_GPIO_EXTI_Callback could be implemented in the user file
*/
}
HAL_GPIO_EXTI_Callback()需要用户自己去构建
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{
if(GPIO_Pin==GPIO_PIN_0)//处理外部中断0
{
EXTI0_LED_Toggle();
}
if(GPIO_Pin==GPIO_PIN_1)//处理外部中断1
{
EXTI1_LED_Toggle();
}
if(GPIO_Pin==GPIO_PIN_2)//处理外部中断2
{
EXTI0_LED_Toggle();
}
if(GPIO_Pin==GPIO_PIN_3)//处理外部中断3
{
EXTI1_LED_Toggle();
}
}
//函数功能:GPIO0~GPIO1外部中断服务程序
void EXTI0_1_IRQHandler(void)
{
HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_0);
HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_1);
}
这种做法,实现了外部中断统一管理,缺点是中断程序之间出现了交叉,其次执行效率降低了,再次也不是很直观。对于不清楚HAL库程序管理的人来说,确实是一个坑。如果我们不用HAL_GPIO_EXTI_IRQHandler(),也可以实现。
//函数功能:GPIO0~GPIO1外部中断服务程序
void EXTI0_1_IRQHandler(void)
{
///HAL_GPIO_EXTI_Callback开始
if(__HAL_GPIO_EXTI_GET_IT(GPIO_PIN_0) != 0x00u)
{//读"GPIO_PIN_0事件挂起标志位",当软件或者硬件产生上升沿/下降沿触发事件时,该位置位。
EXTI0_LED_Toggle();//输出电平翻转
__HAL_GPIO_EXTI_CLEAR_IT(GPIO_PIN_0);//清除外部事件标志位
//清除"GPIO_PIN_0外部事件标志位"
//当软件或者硬件产生上升沿/下降沿触发事件时,该位置位;
}
if(__HAL_GPIO_EXTI_GET_IT(GPIO_PIN_1) != 0x00u)
{//读"GPIO_PIN_1事件挂起标志位",当软件或者硬件产生上升沿/下降沿触发事件时,该位置位。
EXTI1_LED_Toggle();//输出电平翻转
__HAL_GPIO_EXTI_CLEAR_IT(GPIO_PIN_1);//清除外部事件标志位
//清除"GPIO_PIN_1外部事件标志位"
//当软件或者硬件产生上升沿/下降沿触发事件时,该位置位;
}
NVIC_ClearPendingIRQ(EXTI0_1_IRQn);//清除EXTI0_1_IRQn中断源的中断标志位
///HAL_GPIO_EXTI_Callback结束
}
通过两个程序对比,后者更具有可读性。
#include "EXTI.h"
#include "LED.h"
void EXTI0_Init(void);
void EXTI12_Init(void);
//函数功能:将PA0引脚配置为外部中断引脚
void EXTI0_Init(void)
{
GPIO_InitTypeDef GPIO_InitStructureure;
__HAL_RCC_GPIOA_CLK_ENABLE(); //GPIOA时钟使能
GPIO_InitStructureure.Pin = GPIO_PIN_0;//选择第0脚
GPIO_InitStructureure.Pull = GPIO_PULLUP;//引脚上拉被激活
GPIO_InitStructureure.Speed = GPIO_SPEED_FREQ_MEDIUM;//配置GPIO速度为中速
GPIO_InitStructureure.Mode = GPIO_MODE_IT_FALLING;//配置为下降沿检测模式
HAL_GPIO_Init(GPIOA, &GPIO_InitStructureure);
//根据GPIO_InitStructureure结构变量指定的参数初始化GPIOA的外设寄存器
//因为使用了GPIO_MODE_IT_FALLING,所以使能了外部中断线
HAL_NVIC_SetPriority(EXTI0_1_IRQn,0x03,0);
//EXTI0_1_IRQn表示外部中断线0~中断线1,EXTI0_1_IRQn
//设置中断优先级为0x03,0无意义,注意:0<=PreemptPriority<=3,值越大,表示中断优先级越低
//Enable and set Button EXTI Interrupt to the lowest priority
HAL_NVIC_EnableIRQ(EXTI0_1_IRQn);
//EXTI0_1_IRQn表示外部中断线0~中断线1,EXTI0_1_IRQn
//使能EXTI0_1_IRQn中断
}
//函数功能:将PA1引脚配置为外部中断引脚
void EXTI1_Init(void)
{
GPIO_InitTypeDef GPIO_InitStructureure;
__HAL_RCC_GPIOA_CLK_ENABLE(); //GPIOA时钟使能
GPIO_InitStructureure.Pin = GPIO_PIN_1;//选择第1脚
GPIO_InitStructureure.Pull = GPIO_PULLUP;//引脚上拉被激活
GPIO_InitStructureure.Speed = GPIO_SPEED_FREQ_MEDIUM;//配置GPIO速度为中速
GPIO_InitStructureure.Mode = GPIO_MODE_IT_FALLING;//配置为下降沿检测模式
HAL_GPIO_Init(GPIOA, &GPIO_InitStructureure);
//根据GPIO_InitStructureure结构变量指定的参数初始化GPIOA的外设寄存器
//因为使用了GPIO_MODE_IT_FALLING,所以使能了外部中断线
HAL_NVIC_SetPriority(EXTI0_1_IRQn,0x03,0);
//EXTI0_1_IRQn表示外部中断线0~中断线1,EXTI0_1_IRQn
//设置中断优先级为0x03,0无意义,注意:0<=PreemptPriority<=3,值越大,表示中断优先级越低
//Enable and set Button EXTI Interrupt to the lowest priority
HAL_NVIC_EnableIRQ(EXTI0_1_IRQn);
//EXTI0_1_IRQn表示外部中断线0~中断线1,EXTI0_1_IRQn
//使能EXTI0_1_IRQn中断
}
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{
if(GPIO_Pin==GPIO_PIN_0)//处理外部中断0
{
EXTI0_LED_Toggle();
}
if(GPIO_Pin==GPIO_PIN_1)//处理外部中断1
{
EXTI1_LED_Toggle();
}
if(GPIO_Pin==GPIO_PIN_2)//处理外部中断2
{
EXTI0_LED_Toggle();
}
if(GPIO_Pin==GPIO_PIN_3)//处理外部中断3
{
EXTI1_LED_Toggle();
}
}
//函数功能:GPIO0~GPIO1外部中断服务程序
//void EXTI0_1_IRQHandler(void)
//{
// HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_0);
// HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_1);
//}
//函数功能:GPIO0~GPIO1外部中断服务程序
void EXTI0_1_IRQHandler(void)
{
///HAL_GPIO_EXTI_Callback开始
if(__HAL_GPIO_EXTI_GET_IT(GPIO_PIN_0) != 0x00u)
{//读"GPIO_PIN_0事件挂起标志位",当软件或者硬件产生上升沿/下降沿触发事件时,该位置位。
EXTI0_LED_Toggle();//输出电平翻转
__HAL_GPIO_EXTI_CLEAR_IT(GPIO_PIN_0);//清除外部事件标志位
//清除"GPIO_PIN_0外部事件标志位"
//当软件或者硬件产生上升沿/下降沿触发事件时,该位置位;
}
if(__HAL_GPIO_EXTI_GET_IT(GPIO_PIN_1) != 0x00u)
{//读"GPIO_PIN_1事件挂起标志位",当软件或者硬件产生上升沿/下降沿触发事件时,该位置位。
EXTI1_LED_Toggle();//输出电平翻转
__HAL_GPIO_EXTI_CLEAR_IT(GPIO_PIN_1);//清除外部事件标志位
//清除"GPIO_PIN_1外部事件标志位"
//当软件或者硬件产生上升沿/下降沿触发事件时,该位置位;
}
NVIC_ClearPendingIRQ(EXTI0_1_IRQn);//清除EXTI0_1_IRQn中断源的中断标志位
///HAL_GPIO_EXTI_Callback结束
}