问小白 wenxiaobai
资讯
历史
科技
环境与自然
成长
游戏
财经
文学与艺术
美食
健康
家居
文化
情感
汽车
三农
军事
旅行
运动
教育
生活
星座命理

STM32中断回调技巧大揭秘!

创作时间:
作者:
@小白创作中心

STM32中断回调技巧大揭秘!

引用
CSDN
8
来源
1.
https://blog.csdn.net/Aaags/article/details/133046701
2.
https://blog.csdn.net/L_Z_J_I/article/details/141504718
3.
https://blog.csdn.net/qq_38942623/article/details/113481160
4.
https://wenku.csdn.net/column/4zd9zqmtp4
5.
https://blog.csdn.net/wjyjoy/article/details/139650433
6.
https://blog.csdn.net/qq_42425882/article/details/89190150
7.
https://www.fenice.website/archives/929
8.
https://shequ.stmicroelectronics.cn/thread-641320-1-1.html

在STM32开发过程中,中断回调函数是处理外部事件和异常情况的重要机制。通过使用HAL库提供的中断处理机制,开发者可以更高效地响应中断事件。本文将详细介绍如何利用弱声明和强声明的回调函数来实现自定义操作,以及如何模块化代码进行解耦,提高项目移植效率。

01

中断回调基础回顾

在STM32的开发中,中断是一种非常重要的机制,用于响应外部事件或内部异常情况。STM32在启动文件(stmxxxxx.s)中为我们预先定义了所有中断的中断服务函数。这意味着当特定的中断发生时,处理器会自动跳转到相应的中断服务函数处执行代码。

在标准库中,处理中断需要开发者自己去判断中断标志位,确定中断是否发生,然后执行相应的操作,最后还需要手动清除中断标志位。例如在EXTI15_10_IRQHandler中断服务函数中,开发者需要通过检查特定的线(比如线12)的中断标志位来判断该中断是否发生,如果中断标志位为真,则执行特定的操作,最后还需要清除线12产生的中断标志位,以确保下次中断能够正确响应。

HAL库为各个外设的中断提供了更加便捷的处理方式。在HAL库提供的中断处理函数中,会自动判断中断标志位并清除标志位。例如在void HAL_GPIO_EXTI_IRQHandler(uint16_t GPIO_Pin)函数中,首先使用__HAL_GPIO_EXTI_GET_IT(GPIO_Pin)!= 0x00u来判断标志位,确定中断是否发生。如果中断发生,接着使用__HAL_GPIO_EXTI_CLEAR_IT(GPIO_Pin)来清除标志位,确保下次中断能够正常响应。

在自动判断和清除标志位的函数中,还提供了一个回调函数HAL_GPIO_EXTI_Callback(GPIO_Pin)。这个回调函数的作用是在中断发生并且标志位被正确处理后,执行用户自定义的操作。

在自动判断和清除标志位的函数下,会有回调函数有一个弱声明:__weak void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)。这个弱声明的回调函数只是为了防止编译报错而存在的,它内部实际上什么操作都不执行,只是通过UNUSED(GPIO_Pin)来告诉编译器这个参数虽然没有被使用,防止产生编译错误。

开发者可以在自己的代码中定义一个“强声明”的中断回调函数,即void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)。当程序编译时,会自动使用这个强声明的回调函数替代弱声明的回调函数。这样,当中断发生时,就会执行开发者自定义的回调函数,而不是弱声明的空函数。

为了让HAL库的中断处理函数能够正确地响应中断并执行自定义的回调函数,我们只需要在it.c文件中,在中断发生时跳转到HAL库的中断处理函数。这样,当中断发生时,HAL库的中断处理函数就会自动帮我们判断中断标志位、清除标志位,并进入对应的回调函数,执行我们自定义的操作。

02

高级应用技巧

弱声明与强声明的灵活运用

弱声明的回调函数是一个空函数,用于防止编译错误。开发者可以通过强声明覆盖弱声明,实现自定义操作。这种机制提供了极大的灵活性,允许开发者根据具体需求定制中断处理逻辑。

模块化设计提高代码复用性

在处理多个项目时,自动生成的中断函数往往调用同一个回调函数,这给代码移植带来了不便。通过模块化设计,可以将不同外设的中断处理逻辑封装成独立的模块,提高代码的复用性和可维护性。

多中断源的优先级管理

在实际项目中,往往需要处理多个中断源。合理设置中断优先级和调度策略,可以确保关键任务得到及时处理,提高系统的实时性。

03

实际案例:串口中断的模块化设计

在实际项目中,我们经常需要处理多个串口的中断。传统的做法是在一个统一的回调函数中通过句柄区分不同的串口,但这会导致代码耦合度高,移植困难。通过自定义中断回调函数,我们可以实现模块化的代码设计。

  1. 首先在stm32f7xx_it.c中配置中断处理函数:
void USART2_IRQHandler(void)
{
  /* USER CODE BEGIN USART2_IRQn 0 */

  /* USER CODE END USART2_IRQn 0 */
  HAL_UART_IRQHandler(&huart2);
  /* USER CODE BEGIN USART2_IRQn 1 */

  /* USER CODE END USART2_IRQn 1 */
}
  1. 在HAL_UART_IRQHandler函数中,通过USE_HAL_UART_REGISTER_CALLBACKS宏定义来实现自定义中断回调:
void HAL_UART_IRQHandler(UART_HandleTypeDef *huart)
{
  uint32_t isrflags   = READ_REG(huart->Instance->SR);
  uint32_t cr1its     = READ_REG(huart->Instance->CR1);
  uint32_t cr3its     = READ_REG(huart->Instance->CR3);
  uint32_t errorflags = 0x00U;
  uint32_t dmarequest = 0x00U;

  /* 如果没有错误发生 */
  errorflags = (isrflags & (uint32_t)(USART_SR_PE | USART_SR_FE | USART_SR_ORE | USART_SR_NE));
  if (errorflags == RESET)
  {
    /* UART处于接收模式 -------------------------------------------------*/
    if (((isrflags & USART_SR_RXNE) != RESET) && ((cr1its & USART_CR1_RXNEIE) != RESET))
    {
      UART_Receive_IT(huart);
      return;
    }
  }

  /* 如果发生一些错误 */
  if ((errorflags != RESET) && (((cr3its & USART_CR3_EIE) != RESET) || ((cr1its & (USART_CR1_RXNEIE | USART_CR1_PEIE)) != RESET)))
  {
    /* UART parity error interrupt occurred ----------------------------------*/
    if (((isrflags & USART_SR_PE) != RESET) && ((cr1its & USART_CR1_PEIE) != RESET))
    {
      huart->ErrorCode |= HAL_UART

通过这种方式,我们可以为每个串口定义独立的回调函数,实现模块化设计。这样在不同项目间移植代码时,只需包含相应的模块即可,大大提高了开发效率。

04

总结

掌握中断回调的高级应用技巧对于提高STM32开发效率至关重要。通过灵活运用弱声明和强声明机制,结合模块化设计思想,可以实现更高效、更灵活的中断处理逻辑。希望本文介绍的这些技巧能帮助读者在实际项目中更好地应对各种中断处理需求。

© 2023 北京元石科技有限公司 ◎ 京公网安备 11010802042949号