单片机
返回首页

STM32开发笔记28: 中断请求的移植与处理

2019-07-16 来源:eefocus

单片机型号:STM32L053R8T6


    本文介绍如何移植STM32的IRQ(中断请求)到自己的系统中,我们以USART1接收中断为例。


    先看启动文件(汇编语言),如下列程序所示,列出了其向量区,USART1的中断向量已用红色标识,当和USART1相关的中断发生时,程序指针(PC)在保护现场后,直接指向到该向量。


__Vectors       DCD     __initial_sp              ; Top of Stack

                DCD     Reset_Handler             ; Reset Handler

                DCD     NMI_Handler               ; NMI Handler

                DCD     HardFault_Handler         ; Hard Fault Handler

                DCD     0                         ; Reserved

                DCD     0                         ; Reserved

                DCD     0                         ; Reserved

                DCD     0                         ; Reserved

                DCD     0                         ; Reserved

                DCD     0                         ; Reserved

                DCD     0                         ; Reserved

                DCD     SVC_Handler               ; SVCall Handler

                DCD     0                         ; Reserved

                DCD     0                         ; Reserved

                DCD     PendSV_Handler            ; PendSV Handler

                DCD     SysTick_Handler           ; SysTick Handler


                ; External Interrupts

                DCD     WWDG_IRQHandler                ; Window Watchdog

                DCD     PVD_IRQHandler                 ; PVD through EXTI Line detect

                DCD     RTC_IRQHandler                 ; RTC through EXTI Line

                DCD     FLASH_IRQHandler               ; FLASH

                DCD     RCC_CRS_IRQHandler             ; RCC and CRS

                DCD     EXTI0_1_IRQHandler             ; EXTI Line 0 and 1

                DCD     EXTI2_3_IRQHandler             ; EXTI Line 2 and 3

                DCD     EXTI4_15_IRQHandler            ; EXTI Line 4 to 15

                DCD     TSC_IRQHandler                 ; TSC

                DCD     DMA1_Channel1_IRQHandler       ; DMA1 Channel 1

                DCD     DMA1_Channel2_3_IRQHandler     ; DMA1 Channel 2 and Channel 3

                DCD     DMA1_Channel4_5_6_7_IRQHandler ; DMA1 Channel 4, Channel 5, Channel 6 and Channel 7

                DCD     ADC1_COMP_IRQHandler           ; ADC1, COMP1 and COMP2 

                DCD     LPTIM1_IRQHandler              ; LPTIM1

                DCD     0                              ; Reserved

                DCD     TIM2_IRQHandler                ; TIM2

                DCD     0                              ; Reserved

                DCD     TIM6_DAC_IRQHandler            ; TIM6 and DAC

                DCD     0                              ; Reserved

                DCD     0                              ; Reserved

                DCD     TIM21_IRQHandler               ; TIM21

                DCD     0                              ; Reserved

                DCD     TIM22_IRQHandler               ; TIM22

                DCD     I2C1_IRQHandler                ; I2C1

                DCD     I2C2_IRQHandler                ; I2C2

                DCD     SPI1_IRQHandler                ; SPI1

                DCD     SPI2_IRQHandler                ; SPI2

                DCD     USART1_IRQHandler              ; USART1

                DCD     USART2_IRQHandler              ; USART2

                DCD     RNG_LPUART1_IRQHandler         ; RNG and LPUART1

                DCD     LCD_IRQHandler                 ; LCD

                DCD     USB_IRQHandler                 ; USB

                

__Vectors_End

DCD     USART1_IRQHandler              ; USART1

                DCD     USART2_IRQHandler              ; USART2

                DCD     RNG_LPUART1_IRQHandler         ; RNG and LPUART1

                DCD     LCD_IRQHandler                 ; LCD

                DCD     USB_IRQHandler                 ; USB

                

__Vectors_End

    此时,我们需做2件事情,在驱动的头文件中定义该向量的函数原型,在驱动的C文件中完成该向量的函数实现。STM32CubeMX会有相应的中断处理,我们直接调用就好,这个可以参照STM32提供的样例文件,如下列程序所示。


void USART1_IRQHandler(void)

{  

  HAL_UART_IRQHandler(pUART1);

}

    后面的事情交由STM32CubeMX提供的驱动函数进行处理,我们慢慢看。HAL_UART_IRQHandler函数对中断进行处理,然后根据相应的中断类型,再调用相关的驱动函数,我们这里就需调用UART_Receive_IT函数,已用红色标识。


void HAL_UART_IRQHandler(UART_HandleTypeDef *huart)

{

  uint32_t isrflags   = READ_REG(huart->Instance->ISR);

  uint32_t cr1its     = READ_REG(huart->Instance->CR1);

  uint32_t cr3its;

  uint32_t errorflags;

 

  /* If no error occurs */

  errorflags = (isrflags & (uint32_t)(USART_ISR_PE | USART_ISR_FE | USART_ISR_ORE | USART_ISR_NE));

  if (errorflags == RESET)

  {

    /* UART in mode Receiver ---------------------------------------------------*/

    if(((isrflags & USART_ISR_RXNE) != RESET) && ((cr1its & USART_CR1_RXNEIE) != RESET))

    {

      UART_Receive_IT(huart);

      return;

    }

  }  

 

  /* If some errors occur */

  cr3its = READ_REG(huart->Instance->CR3);

  if(   (errorflags != RESET)

     && (   ((cr3its & USART_CR3_EIE) != RESET)

         || ((cr1its & (USART_CR1_RXNEIE | USART_CR1_PEIE)) != RESET)) )

  {

    /* UART parity error interrupt occurred -------------------------------------*/

    if(((isrflags & USART_ISR_PE) != RESET) && ((cr1its & USART_CR1_PEIE) != RESET))

    {

      __HAL_UART_CLEAR_IT(huart, UART_CLEAR_PEF);

 

      huart->ErrorCode |= HAL_UART_ERROR_PE;

    }

 

    /* UART frame error interrupt occurred --------------------------------------*/

    if(((isrflags & USART_ISR_FE) != RESET) && ((cr3its & USART_CR3_EIE) != RESET))

    {

      __HAL_UART_CLEAR_IT(huart, UART_CLEAR_FEF);

 

      huart->ErrorCode |= HAL_UART_ERROR_FE;

    }

 

    /* UART noise error interrupt occurred --------------------------------------*/

    if(((isrflags & USART_ISR_NE) != RESET) && ((cr3its & USART_CR3_EIE) != RESET))

    {

      __HAL_UART_CLEAR_IT(huart, UART_CLEAR_NEF);

 

      huart->ErrorCode |= HAL_UART_ERROR_NE;

    }

    

    /* UART Over-Run interrupt occurred -----------------------------------------*/

    if(((isrflags & USART_ISR_ORE) != RESET) &&

       (((cr1its & USART_CR1_RXNEIE) != RESET) || ((cr3its & USART_CR3_EIE) != RESET)))

    {

      __HAL_UART_CLEAR_IT(huart, UART_CLEAR_OREF);

 

      huart->ErrorCode |= HAL_UART_ERROR_ORE;

    }

 

    /* Call UART Error Call back function if need be --------------------------*/

    if(huart->ErrorCode != HAL_UART_ERROR_NONE)

    {

      /* UART in mode Receiver ---------------------------------------------------*/

      if(((isrflags & USART_ISR_RXNE) != RESET) && ((cr1its & USART_CR1_RXNEIE) != RESET))

      {

        void UART_Receive_IT(huart);

      }

 

      /* If Overrun error occurs, or if any error occurs in DMA mode reception,

         consider error as blocking */

      if (((huart->ErrorCode & HAL_UART_ERROR_ORE) != RESET) ||

          (HAL_IS_BIT_SET(huart->Instance->CR3, USART_CR3_DMAR)))

      {  

        /* Blocking error : transfer is aborted

           Set the UART state ready to be able to start again the process,

           Disable Rx Interrupts, and disable Rx DMA request, if ongoing */

        UART_EndRxTransfer(huart);

 

        /* Disable the UART DMA Rx request if enabled */

        if (HAL_IS_BIT_SET(huart->Instance->CR3, USART_CR3_DMAR))

        {

          CLEAR_BIT(huart->Instance->CR3, USART_CR3_DMAR);

 

          /* Abort the UART DMA Rx channel */

          if(huart->hdmarx != NULL)

          {

            /* Set the UART DMA Abort callback : 

               will lead to call HAL_UART_ErrorCallback() at end of DMA abort procedure */

            huart->hdmarx->XferAbortCallback = UART_DMAAbortOnError;

 

            /* Abort DMA RX */

            if(HAL_DMA_Abort_IT(huart->hdmarx) != HAL_OK)

            {

              /* Call Directly huart->hdmarx->XferAbortCallback function in case of error */

              huart->hdmarx->XferAbortCallback(huart->hdmarx);

            }

          }

          else

          {

            /* Call user error callback */

            HAL_UART_ErrorCallback(huart);

          }

        }

        else

        {

          /* Call user error callback */

          HAL_UART_ErrorCallback(huart);

        }

      }

      else

      {

        /* Non Blocking error : transfer could go on. 

           Error is notified to user through user error callback */

        HAL_UART_ErrorCallback(huart);

        huart->ErrorCode = HAL_UART_ERROR_NONE;

      }

    }

    return;

 

  } /* End if some error occurs */

 

  /* UART wakeup from Stop mode interrupt occurred ---------------------------*/

  if(((isrflags & USART_ISR_WUF) != RESET) && ((cr3its & USART_CR3_WUFIE) != RESET))

  {

    __HAL_UART_CLEAR_IT(huart, UART_CLEAR_WUF);

    /* Set the UART state ready to be able to start again the process */

    huart->gState  = HAL_UART_STATE_READY;

    huart->RxState = HAL_UART_STATE_READY;

    HAL_UARTEx_WakeupCallback(huart);

    return;

  }

 

  /* UART in mode Transmitter ------------------------------------------------*/

  if(((isrflags & USART_ISR_TXE) != RESET) && ((cr1its & USART_CR1_TXEIE) != RESET))

  {

    UART_Transmit_IT(huart);

    return;

  }

 

  /* UART in mode Transmitter (transmission end) -----------------------------*/

  if(((isrflags & USART_ISR_TC) != RESET) && ((cr1its & USART_CR1_TCIE) != RESET))

  {

    UART_EndTransmit_IT(huart);

    return;

  }

 

}

void UART_Receive_IT(huart);

      }


      /* If Overrun error occurs, or if any error occurs in DMA mode reception,

         consider error as blocking */

      if (((huart->ErrorCode & HAL_UART_ERROR_ORE) != RESET) ||

          (HAL_IS_BIT_SET(huart->Instance->CR3, USART_CR3_DMAR)))

      {  

        /* Blocking error : transfer is aborted

           Set the UART state ready to be able to start again the process,

           Disable Rx Interrupts, and disable Rx DMA request, if ongoing */

        UART_EndRxTransfer(huart);


        /* Disable the UART DMA Rx request if enabled */

        if (HAL_IS_BIT_SET(huart->Instance->CR3, USART_CR3_DMAR))

        {

          CLEAR_BIT(huart->Instance->CR3, USART_CR3_DMAR);


          /* Abort the UART DMA Rx channel */

          if(huart->hdmarx != NULL)

          {

            /* Set the UART DMA Abort callback : 

               will lead to call HAL_UART_ErrorCallback() at end of DMA abort procedure */

            huart->hdmarx->XferAbortCallback = UART_DMAAbortOnError;


            /* Abort DMA RX */

            if(HAL_DMA_Abort_IT(huart->hdmarx) != HAL_OK)

            {

              /* Call Directly huart->hdmarx->XferAbortCallback function in case of error */

              huart->hdmarx->XferAbortCallback(huart->hdmarx);

            }

          }

          else

          {

            /* Call user error callback */

            HAL_UART_ErrorCallback(huart);

          }

        }

        else

        {

          /* Call user error callback */

          HAL_UART_ErrorCallback(huart);

        }

      }

      else

      {

        /* Non Blocking error : transfer could go on. 

           Error is notified to user through user error callback */

        HAL_UART_ErrorCallback(huart);

        huart->ErrorCode = HAL_UART_ERROR_NONE;

      }

    }

    return;


  } /* End if some error occurs */


  /* UART wakeup from Stop mode interrupt occurred ---------------------------*/

  if(((isrflags & USART_ISR_WUF) != RESET) && ((cr3its & USART_CR3_WUFIE) != RESET))

  {

    __HAL_UART_CLEAR_IT(huart, UART_CLEAR_WUF);

    /* Set the UART state ready to be able to start again the process */

    huart->gState  = HAL_UART_STATE_READY;

    huart->RxState = HAL_UART_STATE_READY;

    HAL_UARTEx_WakeupCallback(huart);

    return;

  }


  /* UART in mode Transmitter ------------------------------------------------*/

  if(((isrflags & USART_ISR_TXE) != RESET) && ((cr1its & USART_CR1_TXEIE) != RESET))

  {

    UART_Transmit_IT(huart);

    return;

  }


  /* UART in mode Transmitter (transmission end) -----------------------------*/

  if(((isrflags & USART_ISR_TC) != RESET) && ((cr1its & USART_CR1_TCIE) != RESET))

  {

    UART_EndTransmit_IT(huart);

    return;

  }


}

    下面是UART_Receive_IT函数,里面有一个以Callback结尾的函数,已用红色标识,这就是STM32CubeMX留给我们的回调函数,我们只需将自己的逻辑写入该函数即可。而且该函数是用__weak进行修饰的,也就是说,我们只需在自己的文件中直接处理该函数即可。


static HAL_StatusTypeDef UART_Receive_IT(UART_HandleTypeDef *huart)

{

  uint16_t* tmp;

  uint16_t  uhMask = huart->Mask;

  uint16_t  uhdata;

 

  /* Check that a Rx process is ongoing */

  if(huart->RxState == HAL_UART_STATE_BUSY_RX)

  {

    uhdata = (uint16_t) READ_REG(huart->Instance->RDR);

    if ((huart->Init.WordLength == UART_WORDLENGTH_9B) && (huart->Init.Parity == UART_PARITY_NONE))

    {

      tmp = (uint16_t*) huart->pRxBuffPtr ;

      *tmp = (uint16_t)(uhdata & uhMask);

      huart->pRxBuffPtr +=2;

    }

    else

    {

      *huart->pRxBuffPtr++ = (uint8_t)(uhdata & (uint8_t)uhMask);

    }

 

    if(--huart->RxXferCount == 0U)

    {

      /* Disable the UART Parity Error Interrupt and RXNE interrupt*/

      CLEAR_BIT(huart->Instance->CR1, (USART_CR1_RXNEIE | USART_CR1_PEIE));

 

      /* Disable the UART Error Interrupt: (Frame error, noise error, overrun error) */

      CLEAR_BIT(huart->Instance->CR3, USART_CR3_EIE);

 

      /* Rx process is completed, restore huart->RxState to Ready */

      huart->RxState = HAL_UART_STATE_READY;

 

      HAL_UART_RxCpltCallback(huart);

 

      return HAL_OK;

    }

 

    return HAL_OK;

  }

  else

  {

    /* Clear RXNE interrupt flag */

    __HAL_UART_SEND_REQ(huart, UART_RXDATA_FLUSH_REQUEST);

 

    return HAL_BUSY;

  }

}

HAL_UART_RxCpltCallback(huart);


      return HAL_OK;

    }


    return HAL_OK;

  }

  else

  {

    /* Clear RXNE interrupt flag */

    __HAL_UART_SEND_REQ(huart, UART_RXDATA_FLUSH_REQUEST);


    return HAL_BUSY;

  }

}

    总结一下,如何移植和处理中断函数。


    (1)在自己的驱动文件的头文件中,加入需要处理的中断矢量函数的函数原型声明。


    (2)在自己的驱动文件的C文件中,对该函数进行处理,要调用STM32CubeMX提供的驱动文件进行处理。


    (3)在自己的驱动文件的C文件中,直接对相应的回调函数进行处理,加入逻辑即可。



进入单片机查看更多内容>>
相关视频
  • 【TI MSPM0 应用实战】智能小车+工业角度编码器+血氧仪+烟雾探测器!硬核参考设计详解!

  • 2022 Digi-Key KOL 系列: 你见过1GHz主频的单片机吗?Teensy 4.1开发板介绍

  • TI 新一代 C2000™ 微控制器:全方位助力伺服及马达驱动应用

  • MSP430电容触摸技术 - 防水Demo演示

  • 直播回放: Microchip Timberwolf™ 音频处理器在线研讨会

  • 基于灵动MM32W0系列MCU的指夹血氧仪控制及OTA升级应用方案分享

精选电路图
  • 100瓦 LM3886 功率放大器

  • 精密低压电源

  • 20MHz函数发生器

  • 基于PIC16F676的30V电压表

  • 50MHz频率计

  • ESR表/低电阻测量仪

    相关电子头条文章