STM32-HAL库调试外部中断EXTI的问题剖析

最近在使用STM32的HAL库尝试作1个极其简单的小实验:以外部中断激励引脚PC1,令引脚PC0-LED响应翻转…………但就是这么一个简单的实验,让我卡住了好久。下面我们就来分析这个实验和出现的问题:
板子的硬件原理图:
在这里插入图片描述
HAL库代码配置:

一、初始化LED_IO口,即void MX_GPIO_Init(void),记得要在头文件声明

void MX_GPIO_Init(void)
{

  GPIO_InitTypeDef GPIO_InitStruct = {0};

  /* GPIO Ports Clock Enable */
  __HAL_RCC_GPIOC_CLK_ENABLE();
  __HAL_RCC_GPIOA_CLK_ENABLE();

  /*Configure GPIO pin Output Level */
  HAL_GPIO_WritePin(GPIOC, GPIO_PIN_0, GPIO_PIN_RESET);

  /*Configure GPIO pin : PC0 */
  GPIO_InitStruct.Pin = GPIO_PIN_0;
  GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
  GPIO_InitStruct.Pull = GPIO_NOPULL;
  GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_MEDIUM;
  HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);

}

二、初始化按键_IO口,即void key_Init(void),下降沿触发EXTI中断,记得要在头文件声明

void key_Init(void)
{
    GPIO_InitTypeDef GPIO_InitStruct = {0};

    /* GPIO Ports Clock Enable */
    __HAL_RCC_GPIOC_CLK_ENABLE();
    
    /*Configure GPIO pin : PC1 */
    GPIO_InitStruct.Pin = GPIO_PIN_1;
    GPIO_InitStruct.Mode = GPIO_MODE_IT_FALLING;
    GPIO_InitStruct.Pull = GPIO_PULLUP;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_MEDIUM;
    HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);
    HAL_NVIC_SetPriority(EXTI1_IRQn, 0, 0);
    HAL_NVIC_EnableIRQ(EXTI1_IRQn);
}

三、在main.c中调用上述2个初始化函数MX_GPIO_Init();和key_Init();,记得包含有这2个函数的头文件

int main(void)
{
  /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
  HAL_Init();

  /* Configure the system clock */
  SystemClock_Config();

  MX_GPIO_Init();
  key_Init();
  USART1_Init();

  while (1)
  {

  }
}

while(1)里面不用写东西,后面我们直接在中断回调callback函数编写中断服务

四、查看stm32f1xx_hal_gpio.c文件中的库函数

void HAL_GPIO_EXTI_IRQHandler(uint16_t GPIO_Pin)的作用:获取中断标志位并清除中断标志位—>调用中断服务回调函数并响应;
__weak void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)是弱回调函数,如果我们在其他的.c文件重新定义实现这个函数,则该位置函数无效。这2个函数我们不要修改,也无需理会,这里只是作个说明。

/**
  * @brief  This function handles EXTI interrupt request.
  * @param  GPIO_Pin: Specifies the pins connected 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 callbacks.
  * @param  GPIO_Pin: Specifies the pins connected 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
   */
}

五、在stm32f1xx_it.c源文件代码的后面实现下述中断响应函数

/**
 * @brief This function handles EXTI line0 interrupt.
 */
void EXTI1_IRQHandler(void)
{
  /* USER CODE BEGIN EXTI1_IRQn 0 */

  /* USER CODE END EXTI1_IRQn 0 */
  HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_1);
  /* USER CODE BEGIN EXTI1_IRQn 1 */

  /* USER CODE END EXTI1_IRQn 1 */
}

六、编写中断服务函数

我们在按键key.c文件中重新实现void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)中断回调函数,该回调函数在上面的void HAL_GPIO_EXTI_IRQHandler(uint16_t GPIO_Pin)被调用。

/**
 * @brief          exit callback function
 * @param[in]      GPIO_Pin:gpio pin
 * @retval         none
 */
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{
    //if (GPIO_Pin == GPIO_PIN_1)
    //{
    //    HAL_GPIO_TogglePin(GPIOC, GPIO_PIN_0);
    //}


    while (GPIO_Pin == GPIO_PIN_1)
    {
        HAL_GPIO_TogglePin(GPIOC, GPIO_PIN_0);
    }


    // do
    // {
    //     HAL_GPIO_TogglePin(GPIOC, GPIO_PIN_0);
    // } while (GPIO_Pin == GPIO_PIN_1);
}

在这里问题就出现了!!!如下图红色框所示,我一开始用的while (GPIO_Pin == GPIO_PIN_1)来判断中断响应引脚,把程序下到MCU中,发现按键怎么按下都没有翻转LED,代码检查了一遍又一遍,还是未检查出问题,后面改成if (GPIO_Pin == GPIO_PIN_1)之后,按键就能翻转LED了……啊这……按照我的理解,if和while不都是能判断条件的吗?于是我再改成do{ }while形式去判断,果然也不行,为啥只有if起作用呢,为啥?
在这里插入图片描述
知其然,不知其所以然。那能怎么办呢,去请教网上的大佬看看ifwhile的具体用法呗,搜索中…………出现答案。
在这里插入图片描述
哦,意思就是if不会等你,它只会过一遍,而while会一直在原地等你,直到你来…………原来while的使用会进入无限循环判断,如果不加break,就会一直卡在判断条件成立与否,那EXTI中断就不能跳出循环进行下一次的响应了,害……C语言基础不牢,果真地动山摇。既然如此,那就修改下void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)中断回调函数的实现,添加break跳出语句,如下:

/**
 * @brief          exit callback function
 * @param[in]      GPIO_Pin:gpio pin
 * @retval         none
 */
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{
    // if (GPIO_Pin == GPIO_PIN_1)
    // {
    //     HAL_GPIO_TogglePin(GPIOC, GPIO_PIN_0);
    // }

    while (GPIO_Pin == GPIO_PIN_1)
    {
        HAL_GPIO_TogglePin(GPIOC, GPIO_PIN_0);
        break;
    }

    //do
    //{
    //    HAL_GPIO_TogglePin(GPIOC, GPIO_PIN_0);
    //    break;
    //} while (GPIO_Pin == GPIO_PIN_1);
}

这样,就能够正常使用外部中断去判断下降沿/上升沿触发啦。

<think>嗯,用户想了解STM32 HAL如何配置外部中断。首先,我需要回忆一下HAL的基本结构。记得HAL提供了一套标准化的接口,简化了外设的配置。外部中断的话,可能需要用到EXTI模块和GPIO的中断功能。 首先,用户需要配置GPIO口为中断模式。根据参考资料的引用[1],HALEXTI初始化需要配置IO口的模式、中断源、优先级和使能中断。这里应该涉及到GPIO_InitTypeDef结构体的配置,将GPIO的模式设置为外部中断模式,比如GPIO_MODE_IT_RISING上升沿触发。 然后,配置NVIC中断优先级。HAL中需要用HAL_NVIC_SetPriority来设置优先级,并且使能对应的中断通道。比如EXTI0_IRQn对应GPIO引脚0的中断。 接下来,用户需要编写中断服务函数。在STM32中,中断服务函数的名字是固定的,比如EXTI0_IRQHandler。不过HAL提供了HAL_GPIO_EXTI_Callback这个弱定义的函数,用户可以在自己的代码中重写这个回调函数来处理中断事件。 另外,参考引用[2]提到,在项目配置时需要注意工程名称不要包含中文,选择正确的IDE,比如MDK-ARM。这可能在用户实际创建工程时会有帮助,避免一些配置错误。 可能用户的问题还包括如何选择触发方式,比如上升沿、下降沿或双边沿触发。这需要在GPIO初始化时设置对应的模式,例如GPIO_MODE_IT_FALLING用于下降沿触发。 还需要提醒用户,在CubeMX中配置外部中断会更方便,通过图形化界面选择引脚和触发方式,自动生成初始化代码。这可能对新手更友好,减少手动配置的错误。 最后,用户可能需要示例代码来验证他们的配置是否正确。应该提供基本的初始化代码和回调函数示例,并指出常见的错误点,比如忘记使能中断或优先级配置不当。</think>### STM32 HAL外部中断配置详解 #### 一、环境准备 1. 使用STM32CubeMX创建工程时,需在Project Manager中设置英文工程名称,并选择MDK-ARM工具链[^2] 2. 在Pinout & Configuration界面选择需要配置的GPIO引脚 #### 二、硬件配置步骤 1. 配置GPIO模式: ```c GPIO_InitTypeDef GPIO_InitStruct = {0}; GPIO_InitStruct.Pin = GPIO_PIN_0; GPIO_InitStruct.Mode = GPIO_MODE_IT_RISING; // 上升沿触发 GPIO_InitStruct.Pull = GPIO_NOPULL; HAL_GPIO_Init(GPIOA, &GPIO_InitStruct); ``` 2. 配置中断优先级: ```c HAL_NVIC_SetPriority(EXTI0_IRQn, 0, 0); HAL_NVIC_EnableIRQ(EXTI0_IRQn); ``` #### 三、中断服务函数实现 1. 在stm32fxx_it.c中添加: ```c void EXTI0_IRQHandler(void){ HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_0); } ``` 2. 重写回调函数: ```c void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin){ if(GPIO_Pin == GPIO_PIN_0){ // 中断处理逻辑 } } ``` #### 四、调试要点 1. 使用逻辑分析仪验证中断触发时序 2. 通过__HAL_GPIO_EXTI_CLEAR_FLAG()清除中断标志 3. 注意中断服务函数与回调函数的调用关系
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值