最近移植一个项目使用STM32F030,使用CubeMX中生成的代码,审查代码时候,看起来总有些疑惑。
关于外部中断使能的函数不见了,查找到中断使能,只有这两句话。
这样在哪设置边沿触发呢???使能了EXIT0和EXIT1的中断,但是我只需要EXIT0,这又是怎么对应的呢???
static void MX_NVIC_Init(void)
{
/* EXTI0_1_IRQn interrupt configuration */
HAL_NVIC_SetPriority(EXTI0_1_IRQn, 3, 0);
HAL_NVIC_EnableIRQ(EXTI0_1_IRQn);
}
首先看一下手册,相关寄存器
标准库中,初始化一个外部中断,需要先配置中断,在使能中断。如下EXTI_Init,和NVIC_Init。
//外部中断初始化函数
void EXTIX_Init(void)
{
EXTI_InitTypeDef EXTI_InitStructure;
NVIC_InitTypeDef NVIC_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE);//外部中断,需要使能AFIO时钟
//GPIOA.0 中断线以及中断初始化配置
GPIO_EXTILineConfig(GPIO_PortSourceGPIOA,GPIO_PinSource0);
EXTI_InitStructure.EXTI_Line=EXTI_Line0;
EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;
EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling;
EXTI_InitStructure.EXTI_LineCmd = ENABLE;
EXTI_Init(&EXTI_InitStructure); //根据EXTI_InitStruct中指定的参数初始化外设EXTI寄存器
NVIC_InitStructure.NVIC_IRQChannel = EXTI0_IRQn; //使能按键所在的外部中断通道
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x02; //抢占优先级
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x00; //子优先级
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //使能外部中断通道
NVIC_Init(&NVIC_InitStructure); //根据NVIC_InitStruct中指定的参数初始化外设NVIC寄存器
}
下意识地就去找EXTI_Init对应的HAL函数,还真有HAL_EXTI_SetConfigLine,里面有RTSR,FTSR,IMR,EMR相关寄存器的操作,然后以为是这样写,但始终觉得不妥。
//外部中断初始化函数
void EXTIX_Init(void)
{
GPIO_InitTypeDef GPIO_InitStruct;
EXTI_ConfigTypeDef EXTI_InitStruct;
EXTI_InitStruct.Line = EXTI_LINE_0;
EXTI_InitStruct.Mode = EXTI_MODE_INTERRUPT;
EXTI_InitStruct.Trigger = EXTI_TRIGGER_RISING_FALLING; //下降沿中断
EXTI_InitStruct.GPIOSel = EXTI_GPIOA;
HAL_EXTI_SetConfigLine(&hexti0,&EXTI_InitStruct);
/* EXTI0_1_IRQn interrupt configuration */
HAL_NVIC_SetPriority(EXTI0_1_IRQn, 3, 0);
HAL_NVIC_EnableIRQ(EXTI0_1_IRQn);
}
然后仔细看了GPIO初始化函数,才发现MX是怎么处理的。
GPIO_InitStruct.Pin = GPIO_PIN_0|GPIO_PIN_1|GPIO_PIN_2|GPIO_PIN_3
|GPIO_PIN_4|GPIO_PIN_5|GPIO_PIN_6|GPIO_PIN_7
|GPIO_PIN_8|GPIO_PIN_11;
GPIO_InitStruct.Mode = GPIO_MODE_IT_RISING;//中断配置
GPIO_InitStruct.Pull = GPIO_NOPULL;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
Mode = GPIO_MODE_IT_RISING,在这里做出了区别,有点隐蔽啊。
然后跳到HAL_GPIO_Init去看,的确在这里对外部中断寄存器做出配置。
使用哪种方法看个人,甚至直接寄存器,完工。
附上中断函数,
这里之前出错了,不能用if(__HAL_GPIO_EXTI_GET_IT(EXTI_LINE_0) != 0x00u),而是if(__HAL_GPIO_EXTI_GET_IT(GPIO_PIN_0) != 0x00u)。
区别如下,__HAL_GPIO_EXTI_GET_IT是读取PR寄存器,GPIO_PIN_0产生中断PR=0x0001,使用EXTI_LINE_0是错误的。
#define EXTI_LINE_0 (EXTI_GPIO | 0x00u) /*!< External interrupt line 0 /
#define GPIO_PIN_0 ((uint16_t)0x0001U) / Pin 0 selected */
void EXTI0_1_IRQHandler(void)
{
if(__HAL_GPIO_EXTI_GET_IT(GPIO_PIN_0) != 0x00u)
{
__HAL_GPIO_EXTI_CLEAR_IT(GPIO_PIN_0);
}
else if(__HAL_GPIO_EXTI_GET_IT(GPIO_PIN_1) != 0x00u)
{
__HAL_GPIO_EXTI_CLEAR_IT(GPIO_PIN_1);
}
}
或者使用回调函数,在HAL_GPIO_EXTI_Callback写需要的功能
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 EXTI0_1_IRQHandler(void)
{
/* USER CODE BEGIN EXTI0_1_IRQn 0 */
/* USER CODE END EXTI0_1_IRQn 0 */
HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_0);
HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_1);
/* USER CODE BEGIN EXTI0_1_IRQn 1 */
/* USER CODE END EXTI0_1_IRQn 1 */
}
/**
* @brief Handle EXTI interrupt request.
* @param GPIO_Pin Specifies the port pin connected to corresponding EXTI line.
* @retval None
*/
void HAL_GPIO_EXTI_IRQHandler(uint16_t GPIO_Pin)
{
/* EXTI line interrupt detected */
if(__HAL_GPIO_EXTI_GET_IT(GPIO_Pin) != 0x00u)
{
__HAL_GPIO_EXTI_CLEAR_IT(GPIO_Pin);
HAL_GPIO_EXTI_Callback(GPIO_Pin);
}
}
/**
* @brief EXTI line detection callback.
* @param GPIO_Pin Specifies the port pin connected to corresponding EXTI line.
* @retval None
*/
__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
*/
}