历史上的今天
返回首页

历史上的今天

今天是:2024年09月12日(星期四)

正在发生

2018年09月12日 | STM32L0开发笔记11: 中断请求的移植与处理

2018-09-12 来源:eefocus

    本文介绍如何移植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

    此时,我们需做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;

  }

 

}

    下面是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;

  }

}

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


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


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


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


推荐阅读

史海拾趣

Avic公司的发展小趣事

Avic公司注重提升自主创新能力,不断加大在航空电子技术领域的研发投入。公司建立了一支高素质的研发团队,并积极引进国内外先进的研发设备和技术。这些措施有效提升了公司的创新能力,为公司在航空电子领域的持续发展提供了有力保障。

Capar Components Corp公司的发展小趣事

作为一家有社会责任感的企业,Capar Components Corp积极参与公益事业,回馈社会。公司定期组织员工参与社区服务活动,帮助困难群体解决实际问题。此外,公司还设立了奖学金和助学金,支持教育事业的发展。这些举措不仅彰显了公司的社会责任感,也为公司树立了良好的企业形象。


这些故事是基于一个虚构的电子行业公司背景编写的,您可以根据Capar Components Corp的实际情况进行调整和修改,以使其更符合该公司的历史和发展轨迹。请注意,由于我无法获取Capar Components Corp的具体信息,这些故事仅为示例性质,并非真实事件。

CTS [CTS Corporation]公司的发展小趣事

随着电子技术的不断进步和广泛应用,CTS敏锐地捕捉到了电子元器件和传感器市场的巨大潜力。于是,公司开始逐步转型,将业务重心转向这些领域。通过不断的研发和创新,CTS成功设计并生产出一系列高性能的电子元器件和传感器产品,赢得了市场的广泛认可。

珠海艾派克(APEXMIC)公司的发展小趣事

为了进一步提升研发实力,艾派克先后在珠海、上海、杭州和美国北卡罗来纳州建立了四大研发中心,并与浙江大学、中科院上海微系统所等国内外知名机构建立联合实验室。这些举措不仅加强了公司在技术研发方面的国际合作,也推动了艾派克在行业技术前沿的领先地位。

扬州国芯(Gcore)公司的发展小趣事

近年来,艾派克通过一系列战略性并购,实现了公司的国际化发展。其中最为引人注目的是艾派克科技股份有限公司与太盟投资集团共同牵头收购利盟公司的案例。这次收购不仅使艾派克获得了先进的技术、国际化的品牌和团队,还进一步拓宽了公司的业务范围和市场渠道。通过并购,艾派克成功跻身真正意义上的国际化打印公司,为全球打印行业的未来发展打开了新的想象空间。

Fenghua (HK) Electronics Ltd公司的发展小趣事

为了降低成本、提高生产效率,Fenghua (HK) Electronics Ltd不断优化供应链管理。公司与供应商建立了长期稳定的合作关系,实现了原材料的及时供应和成本控制。同时,公司引入了先进的生产管理系统,对生产过程中的各个环节进行精细化管理,确保了产品质量的稳定性和一致性。

问答坊 | AI 解惑

正弦波信号发生器VHDL源代码

本帖最后由 paulhyde 于 2014-9-15 09:44 编辑 拿出来恭喜  …

查看全部问答>

50Mhz分频的问题

怎么将50M的时钟分频成153600hz? 用普通的方法好像不能解决,因为除不尽。 我设想用一个pll,倍频后,再分 高手指教…

查看全部问答>

有操作系统的嵌入式设备和没有操作系统的嵌入式设备之间的区别

有操作系统的嵌入式设备和没有操作系统的嵌入式设备之间的区别,以及有操作系统的嵌入式设备的优点是什么??…

查看全部问答>

初学者问几个问题,关于wince与arm,望高人指教

首先,我用的是微芯力科的ws-430评估板,cpu为at91rm9200,要求用wince开发。 评估板附带的资料只有linux以及ucos系统的,没有wince的资料,打电话到微芯力科公司,被告知该板不支持wince,因为wince要求某尺寸的真彩屏幕,而我的板子上是一个128 ...…

查看全部问答>

如何验证下位机的串行发送程序

我现在没有芯片,只是在keilc中写的串行通信程序,我想验证一下它能不能实现发送字节,只有一台的情况下该如何做?其中发送字节程序是? void sendbyte(unsigned char word) { SBUF=word; while(TI==0);   TI=0; } …

查看全部问答>

原以为写个usb驱动很简单

DOS下的usb storage驱动一个比一个不好用,我一急就决定自己写一个,结果搞了20天了,还一头浆糊,怎么办。想来想去还是原始社会好啊…

查看全部问答>

AD快捷键大全

挺全的,ad6的快捷键大全,很实用的…

查看全部问答>

如何使用MSP430外部计数信号TACLK

急求高手指点,我的做法是引脚TACLK连接外部频率信号,对外部信号直接计数,不知道为什么总是得不到计数值。 MSP430F2274 P1SEL |= BIT0; P1DIR &= ~BIT0; TACTL = TASSEL_0 + ID_0 + MC_2;…

查看全部问答>

空中鼠标-MSP-EXP430FR5739实验板实现

玩跑跑卡丁车突发奇想,可不可以用团购来的MSP-EXP430FR5739实验板来控制赛车!基本思路是这样的,利用EXP430FR5739实验板上的三轴加速度传感器来检测前后左右上下位置信息,利用串口发送到上位机程序,上位机软件是在VS2010下写的MFC程序,利用该 ...…

查看全部问答>

Kinetis KE06 GPIO测试

Kinetis KE06 GPIO测试 IDE-Version: μVision V5.11.1.0 例程包:KEXX_DRIVERS_V1.2.1_DEVD.RAR 该包用鼠标右键的“解压文件” ,解压后的文件名还是这个,不然DOWN时会出错! 1、打开例程 相关文件:gpio.c,gpio.h主要GPIO操作都在 ...…

查看全部问答>