历史上的今天
今天是:2024年09月07日(星期六)
2021年09月07日 | 重构外部中断回调函数来区分外部中断具体引脚做具体任务
2021-09-07 来源:eefocus
1.STM32CubeMX配置如下:

这里GPIO mode一共有六种分别是:

(1)上升沿触发外部中断
(2)下降沿触发外部中断
(3)边沿触发外部中断
(4)上升沿触发外部事件
(5)下降沿触发外部事件
(6)边沿触发外部事件
2.CubeMX生成的代码:
/** Configure pins as
* EXTI
*/
void MX_GPIO_Init(void)
{
__HAL_RCC_GPIOD_CLK_ENABLE(); //使能GPIO时钟
GPIO_InitTypeDef GPIO_InitStruct = {0};
GPIO_InitStruct.Pin = DATA_433M_Pin;
GPIO_InitStruct.Mode = GPIO_MODE_IT_RISING; //上升沿触发
GPIO_InitStruct.Pull = GPIO_PULLDOWN; //下拉
HAL_GPIO_Init(DATA_433M_GPIO_Port, &GPIO_InitStruct);
HAL_NVIC_SetPriority(EXTI2_3_IRQn, 0, 0);//设置中断优先级
HAL_NVIC_EnableIRQ(EXTI2_3_IRQn);//使能外部中断
}
/******************************************************************************/
/* STM32G0xx Peripheral Interrupt Handlers */
/* Add here the Interrupt Handlers for the used peripherals. */
/* For the available peripheral interrupt handler names, */
/* please refer to the startup file (startup_stm32g0xx.s). */
/******************************************************************************/
/**
* @brief This function handles EXTI line 2 and line 3 interrupts.
*/
void EXTI2_3_IRQHandler(void)
{
/* USER CODE BEGIN EXTI2_3_IRQn 0 */
/* USER CODE END EXTI2_3_IRQn 0 */
HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_2);
/* USER CODE BEGIN EXTI2_3_IRQn 1 */
/* USER CODE END EXTI2_3_IRQn 1 */
}
3.分析外部中断过程
我们可以看见这个外部中断包含了GPIO_Pin_2和GPIO_Pin_3两个外部中断源,这两个脚都可以触发这个外部中断,如果我们想区分具体是2还是3脚的时候,或者需要区分上升沿做不同事情,那么就需要自己重构回调函数来区分,然后执行不同的任务。我们发现里面只有一个函数,打开看看如下:
/**
* @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_RISING_IT(GPIO_Pin) != 0x00u)
{
__HAL_GPIO_EXTI_CLEAR_RISING_IT(GPIO_Pin);
HAL_GPIO_EXTI_Rising_Callback(GPIO_Pin);
}
if (__HAL_GPIO_EXTI_GET_FALLING_IT(GPIO_Pin) != 0x00u)
{
__HAL_GPIO_EXTI_CLEAR_FALLING_IT(GPIO_Pin);
HAL_GPIO_EXTI_Falling_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_Rising_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_Rising_Callback could be implemented in the user file
*/
}
凡是前面带__weak的我们都是可以再重构而不会报错的。
4.重构回调函数
//下降沿回调函数
void HAL_GPIO_EXTI_Rising_Callback(uint16_t GPIO_Pin)
{
if(GPIO_Pin == GPIO_PIN_2)
{
SEGGER_RTT_printf(0,"GPIO_Pin_2 Rising exti!rn");
}
else if(GPIO_Pin == GPIO_PIN_3)
{
SEGGER_RTT_printf(0,"GPIO_Pin_3 Rising exti!rn");
}
}
//上升沿回调函数
void HAL_GPIO_EXTI_Falling_Callback(uint16_t GPIO_Pin)
{
if(GPIO_Pin == GPIO_PIN_2)
{
SEGGER_RTT_printf(0,"GPIO_Pin_2 Falling exti!rn");
}
else if(GPIO_Pin == GPIO_PIN_3)
{
SEGGER_RTT_printf(0,"GPIO_Pin_3 Falling exti!rn");
}
}
5.调试结果

6.增加GPIO端口判断
1)解决办法:
进中断回调函数的时候通过if(HAL_GPIO_ReadPin(GPIOD,DATA_433M_Pin)==1)读取对应引脚电平状态来区分
void HAL_GPIO_EXTI_Rising_Callback(uint16_t GPIO_Pin)
{
if(GPIO_Pin == GPIO_PIN_2)
{
if(HAL_GPIO_ReadPin(GPIOD,DATA_433M_Pin)==1)
SEGGER_RTT_printf(0,"GPIO_Pin_2 Rising exti!rn");
}
else if(GPIO_Pin == GPIO_PIN_3)
{
SEGGER_RTT_printf(0,"GPIO_Pin_3 Rising exti!rn");
}
}
2)实测如下:

第一个是if(HAL_GPIO_ReadPin(GPIOD,DATA_433M_Pin) == 1)的结果,因为我们是上升沿,所以触发中断的时候肯定是个高电平,所以这个时候是可以正常打印RTT的。
第二个是if(HAL_GPIO_ReadPin(GPIOD,DATA_433M_Pin) == 0)的结果,因为我们是上升沿,所以触发中断的时候肯定是个高电平,而我们条件是低电平才会正常打印,所以退出低功耗的时候没有看见RTT打印的log。
上一篇:解决低功耗之后无法下载程序
下一篇:示波器分析485波形图
史海拾趣
|
我现在正在调试的系统中用到了RTL8212,是一块千兆双口物理层收发器。现在他能够正常接收数据,但是却不能发送数据,发出的数据在接收方说是错误的数据包。我是用一块FPGA来控制的,现在不知道问题出在哪里,不知道是我的FPGA时序不对还是RTL8212的 ...… 查看全部问答> |
|
目 录 第1章 UNIX操作系统概述 6 1.1 UNIX操作系统简介 6 1.2 UNIX系统组成 6 1.3 与UNIX有关的几个名词 7 第2章 UNIX常用操作 9 2.1 启动终端 9 2.2 登录 9 2.3 UNIX命令 9 2.4 注销(退出UNIX系统) 13 第3章 UNIX文件系统 ...… 查看全部问答> |
|
arm+linux平台 通过 串口发送 数据 write完以后 必须sleep()发送才能成功 否则,发送的就在中间某位产生错误码,数据长的时候,总是在中间顿一下,然后发后半部分,前半部分的最后一个字节就错掉了 这是怎么回事? 太怪了 高手帮忙分析吧 … 查看全部问答> |
|
我用stc12c5608AD自带的AD做一个AD转换的程序 具体的代码如下 void ad_cov() { P1M0=P1M0||0x20; P1M1=P1M1||0x20; //选择P1.5为开漏。(做A/D使用时选择的模式) ADC_CONTR=0xc5; //540个时钟周期转换一次;ADC_FLAG=0;ADC_START=0(设置为1 ...… 查看全部问答> |
|
自己仿着S3C2410a的开发板,根据需要自己做了一个底板(插在上面的核心板没做),画了PCB,只用了电源,串口和液晶屏(其它的没画),做好板之后又焊上器件,当把原来的核心板(系统在flash里)插在我做的板子上时,液晶可以正常开启,但是触摸时只 ...… 查看全部问答> |




