stm32: 串口空闲中断的实现(HAL库)

STM32利用串口空闲中断来分包(HAL库)

文章目录

  • STM32利用串口空闲中断来分包(HAL库)
  • 1. 开发环境
  • 2. 串口中断接收的问题和解决办法
  • 3. 串口空闲中断分包的原理
  • 4. STM32的空闲中断的使用(修改HAL库)
  • 4.1 修改1(为了保持HAL库的完整性而添加的)
  • 4.2 修改2(为了保持HAL库的完整性而添加的)
  • 4.3 看是否有清空闲标志位的函数(不用修改)
  • 4.4 修改3(重要的修改)
  • 4.5 使用空闲中断
  • 5.其他:上面第四节使能串口接收错误回调的原因
  • 5.1 使能接收错误回调函数的原因
  • 1. 开发环境

  • 系统:win10
  • 开发软件:keil5
  • mcu型号:STM32L4
  • sdk版本:HAL库1.17.0
  • 时间:2022.2
  • 2. 串口中断接收的问题和解决办法

    当我们用串口接收的时候经常会遇到分包的问题。即难以确定是否接收完一个完整的包

    通常遇到这类问题有几种解决方案:

    1. 通过规定字符的长度来确定报文包:比如串口modbus协议。
    2. 添加包头包尾标识来确定报文包,比如GPS报文。
    3. 通过定时器来确定是否接收完成,当接收完数据开启定时器,等待一段时间若未收到数据,则表示一个包完成。
    4. 有些单片机支持空闲中断,利用空闲中断完成一个包的判别。
    5. 其他方法。

    以上方法各有利弊,第一二种要求报文有特定格式,但是有些设备报文的格式是难以琢磨的。第三种需要占用额外的资源。第四种需要单片机硬件的支持。下面讲的是第四种方法。

    3. 串口空闲中断分包的原理

    对于串口发送函数我们往往这样写:

    //本函数用于发送c语言string类型('\0'结尾)字符串
    void put_string(char *str){
    	while (*str){
            put_char(*str);//发送字符
            while(!IT);//等待这个字符发送完成
            str++;
    	}		
    }
    

    一个完整字符串内的字符是连续发送的,这样发送的字符之间的时间间隔通常是很小的。空闲中断就是通过检查两个字节之间空闲多少时间来产生中断的。
    有些mcu是有串口空闲中断的,即当串口收到字节后,若在一段时间内未收到后续的字节,那么它就出发空闲中断,而这个一段时间
    在每中mcu中略有不同,通常我们认为在接收完字节后,若在传输3个字节所需的时间内未收到新的字节,我们就认为一个包传完了。有的mcu是可以配置这个等待时间的(2个字节时间、3个字节时间)。我仿佛记得华大的MCU就可以配置(好像是HC32F460记不清了).

    STM32也有空闲中断,在手册中写道,当接收完一个字符后,在下一个字节时间内收到的都是1,那么产生空闲中断。解释一下,因为串口在发送字节前要拉低一下电平,产生一个起始位,而所谓收到的都是1的意思就是说,在一个字节时间内没有收到下一个字节的起始位,那么就会触发空闲中断。

    4. STM32的空闲中断的使用(修改HAL库)

    为什么要大篇幅讲STM32的空闲中断,那是因为STM32虽然有空闲中断,但是HAL并没有实现,所以本文就是讲如何修改HAL库,来支持STM32空闲中断。

    4.1 修改1(为了保持HAL库的完整性而添加的)

    stm32l4xx_hal_uart.c中添加下面代码:

    /**
      * @brief  Rx Transfer idle callback.
      * @param  huart UART handle.
      * @retval None
      */
    __weak void HAL_UART_IdleCpltCallback(UART_HandleTypeDef *huart)
    {
      /* Prevent unused argument(s) compilation warning */
      UNUSED(huart);
    
      /* NOTE : This function should not be modified, when the callback is needed,
                the HAL_UART_IdleCpltCallback can be implemented in the user file.
       */
    }
    

    为了看着整洁我将上面函数添加到 HAL_UART_RxCpltCallback函数后。如下图:

    4.2 修改2(为了保持HAL库的完整性而添加的)

    stm32l4xx_hal_uart.h中添加下面代码:

    void HAL_UART_IdleCpltCallback(UART_HandleTypeDef *huart);
    

    为了看着整洁我将上面的函数声明添加到 HAL_UART_RxCpltCallback函数声明后。如下图:

    4.3 看是否有清空闲标志位的函数(不用修改)

    同时我们会发现在stm32l4xx_hal_uart.h中清除空闲中断的函数已经实现了,我的在931行,所以清除中断函数就不用我们写了。

    /** @brief  Clear the UART IDLE pending flag.
      * @param  __HANDLE__ specifies the UART Handle.
      * @retval None
      */
    #define __HAL_UART_CLEAR_IDLEFLAG(__HANDLE__)   __HAL_UART_CLEAR_FLAG((__HANDLE__), UART_CLEAR_IDLEF)
    

    4.4 修改3(重要的修改)

    stm32l4xx_hal_uart.c中找到HAL_UART_IRQHandler函数,这个函数会在串口中断的时候调用,函数内部通过寄存器判断串口中断的类型,然后调用相应的中断回调函数,为了支持空闲中断,需要在这个函数里面编写空闲中断的 if 判断,当空闲中断发生时候调用空闲中断回调函数。

    HAL_UART_IRQHandler函数里添加下面代码:

    if(((isrflags & USART_ISR_IDLE) != 0U) && ((cr1its & USART_CR1_IDLEIE) != 0U))
    {	
        //当中断类型为空闲中断
        __HAL_UART_DISABLE_IT(huart,UART_IT_IDLE);    	//关了空闲中断
        HAL_UART_IdleCpltCallback(huart);				//调用空闲中断回调函数
        __HAL_UART_CLEAR_IDLEFLAG(huart);				//清除IDLE标志
        __HAL_UART_ENABLE_IT(huart,UART_IT_IDLE);    	//使能空闲中断
    
        return;
    }
    

    注意:为了更好表示函数添加的位置,我将HAL_UART_IRQHandler函数全部贴出,只要对照下面的函数,将上面的代码贴到自己函数的指定位置。

    /**
      * @brief Handle UART interrupt request.
      * @param huart UART handle.
      * @retval None
      */
    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     = READ_REG(huart->Instance->CR3);
    
      uint32_t errorflags;
      uint32_t errorcode;
    
      /* If no error occurs */
      errorflags = (isrflags & (uint32_t)(USART_ISR_PE | USART_ISR_FE | USART_ISR_ORE | USART_ISR_NE | USART_ISR_RTOF));
      if (errorflags == 0U)
      {
        /* UART in mode Receiver ---------------------------------------------------*/
    #if defined(USART_CR1_FIFOEN)
        if (((isrflags & USART_ISR_RXNE_RXFNE) != 0U)
            && (((cr1its & USART_CR1_RXNEIE_RXFNEIE) != 0U)
                || ((cr3its & USART_CR3_RXFTIE) != 0U)))
    #else
        if (((isrflags & USART_ISR_RXNE) != 0U)
            && ((cr1its & USART_CR1_RXNEIE) != 0U))
    #endif /* USART_CR1_FIFOEN */
        {
          if (huart->RxISR != NULL)
          {
            huart->RxISR(huart);
          }
          return;
        }
      }
    
      /* If some errors occur */
    #if defined(USART_CR1_FIFOEN)
      if ((errorflags != 0U)
          && ((((cr3its & (USART_CR3_RXFTIE | USART_CR3_EIE)) != 0U)
               || ((cr1its & (USART_CR1_RXNEIE_RXFNEIE | USART_CR1_PEIE | USART_CR1_RTOIE)) != 0U))))
    #else
      if ((errorflags != 0U)
          && (((cr3its & USART_CR3_EIE) != 0U)
              || ((cr1its & (USART_CR1_RXNEIE | USART_CR1_PEIE | USART_CR1_RTOIE)) != 0U)))
    #endif /* USART_CR1_FIFOEN */
      {
        /* UART parity error interrupt occurred -------------------------------------*/
        if (((isrflags & USART_ISR_PE) != 0U) && ((cr1its & USART_CR1_PEIE) != 0U))
        {
          __HAL_UART_CLEAR_FLAG(huart, UART_CLEAR_PEF);
    
          huart->ErrorCode |= HAL_UART_ERROR_PE;
        }
    
        /* UART frame error interrupt occurred --------------------------------------*/
        if (((isrflags & USART_ISR_FE) != 0U) && ((cr3its & USART_CR3_EIE) != 0U))
        {
          __HAL_UART_CLEAR_FLAG(huart, UART_CLEAR_FEF);
    
          huart->ErrorCode |= HAL_UART_ERROR_FE;
        }
    
        /* UART noise error interrupt occurred --------------------------------------*/
        if (((isrflags & USART_ISR_NE) != 0U) && ((cr3its & USART_CR3_EIE) != 0U))
        {
          __HAL_UART_CLEAR_FLAG(huart, UART_CLEAR_NEF);
    
          huart->ErrorCode |= HAL_UART_ERROR_NE;
        }
    
        /* UART Over-Run interrupt occurred -----------------------------------------*/
    #if defined(USART_CR1_FIFOEN)
        if (((isrflags & USART_ISR_ORE) != 0U)
            && (((cr1its & USART_CR1_RXNEIE_RXFNEIE) != 0U) ||
                ((cr3its & (USART_CR3_RXFTIE | USART_CR3_EIE)) != 0U)))
    #else
        if (((isrflags & USART_ISR_ORE) != 0U)
            && (((cr1its & USART_CR1_RXNEIE) != 0U) ||
                ((cr3its & USART_CR3_EIE) != 0U)))
    #endif /* USART_CR1_FIFOEN */
        {
          __HAL_UART_CLEAR_FLAG(huart, UART_CLEAR_OREF);
    
          huart->ErrorCode |= HAL_UART_ERROR_ORE;
        }
    
        /* UART Receiver Timeout interrupt occurred ---------------------------------*/
        if (((isrflags & USART_ISR_RTOF) != 0U) && ((cr1its & USART_CR1_RTOIE) != 0U))
        {
          __HAL_UART_CLEAR_FLAG(huart, UART_CLEAR_RTOF);
    
          huart->ErrorCode |= HAL_UART_ERROR_RTO;
        }
    
        /* Call UART Error Call back function if need be ----------------------------*/
        if (huart->ErrorCode != HAL_UART_ERROR_NONE)
        {
          /* UART in mode Receiver --------------------------------------------------*/
    #if defined(USART_CR1_FIFOEN)
          if (((isrflags & USART_ISR_RXNE_RXFNE) != 0U)
              && (((cr1its & USART_CR1_RXNEIE_RXFNEIE) != 0U)
                  || ((cr3its & USART_CR3_RXFTIE) != 0U)))
    #else
          if (((isrflags & USART_ISR_RXNE) != 0U)
              && ((cr1its & USART_CR1_RXNEIE) != 0U))
    #endif /* USART_CR1_FIFOEN */
          {
            if (huart->RxISR != NULL)
            {
              huart->RxISR(huart);
            }
          }
    
          /* If Error is to be considered as blocking :
              - Receiver Timeout error in Reception
              - Overrun error in Reception
              - any error occurs in DMA mode reception
          */
          errorcode = huart->ErrorCode;
          if ((HAL_IS_BIT_SET(huart->Instance->CR3, USART_CR3_DMAR)) ||
              ((errorcode & (HAL_UART_ERROR_RTO | HAL_UART_ERROR_ORE)) != 0U))
          {
            /* 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 */
    #if (USE_HAL_UART_REGISTER_CALLBACKS == 1)
                /*Call registered error callback*/
                huart->ErrorCallback(huart);
    #else
                /*Call legacy weak error callback*/
                HAL_UART_ErrorCallback(huart);
    #endif /* USE_HAL_UART_REGISTER_CALLBACKS */
    
              }
            }
            else
            {
              /* Call user error callback */
    #if (USE_HAL_UART_REGISTER_CALLBACKS == 1)
              /*Call registered error callback*/
              huart->ErrorCallback(huart);
    #else
              /*Call legacy weak error callback*/
              HAL_UART_ErrorCallback(huart);
    #endif /* USE_HAL_UART_REGISTER_CALLBACKS */
            }
          }
          else
          {
            /* Non Blocking error : transfer could go on.
               Error is notified to user through user error callback */
    #if (USE_HAL_UART_REGISTER_CALLBACKS == 1)
            /*Call registered error callback*/
            huart->ErrorCallback(huart);
    #else
            /*Call legacy weak error callback*/
            HAL_UART_ErrorCallback(huart);
    #endif /* USE_HAL_UART_REGISTER_CALLBACKS */
            huart->ErrorCode = HAL_UART_ERROR_NONE;
          }
        }
        return;
    
      } /* End if some error occurs */
    
      /* Check current reception Mode :
         If Reception till IDLE event has been selected : */
      if (  (huart->ReceptionType == HAL_UART_RECEPTION_TOIDLE)
          &&((isrflags & USART_ISR_IDLE) != 0U)
          &&((cr1its & USART_ISR_IDLE) != 0U))
      {
        __HAL_UART_CLEAR_FLAG(huart, UART_CLEAR_IDLEF);
    
        /* Check if DMA mode is enabled in UART */
        if (HAL_IS_BIT_SET(huart->Instance->CR3, USART_CR3_DMAR))
        {
          /* DMA mode enabled */
          /* Check received length : If all expected data are received, do nothing,
             (DMA cplt callback will be called).
             Otherwise, if at least one data has already been received, IDLE event is to be notified to user */
          uint16_t nb_remaining_rx_data = (uint16_t) __HAL_DMA_GET_COUNTER(huart->hdmarx);
          if (  (nb_remaining_rx_data > 0U)
              &&(nb_remaining_rx_data < huart->RxXferSize))
          {
            /* Reception is not complete */
            huart->RxXferCount = nb_remaining_rx_data;
    
            /* In Normal mode, end DMA xfer and HAL UART Rx process*/
            if (HAL_IS_BIT_CLR(huart->hdmarx->Instance->CCR, DMA_CCR_CIRC))
            {
              /* Disable PE and ERR (Frame error, noise error, overrun error) interrupts */
              CLEAR_BIT(huart->Instance->CR1, USART_CR1_PEIE);
              CLEAR_BIT(huart->Instance->CR3, USART_CR3_EIE);
    
              /* Disable the DMA transfer for the receiver request by resetting the DMAR bit
                 in the UART CR3 register */
              CLEAR_BIT(huart->Instance->CR3, USART_CR3_DMAR);
    
              /* At end of Rx process, restore huart->RxState to Ready */
              huart->RxState = HAL_UART_STATE_READY;
              huart->ReceptionType = HAL_UART_RECEPTION_STANDARD;
    
              CLEAR_BIT(huart->Instance->CR1, USART_CR1_IDLEIE);
    
              /* Last bytes received, so no need as the abort is immediate */
              (void)HAL_DMA_Abort(huart->hdmarx);
            }
    #if (USE_HAL_UART_REGISTER_CALLBACKS == 1)
            /*Call registered Rx Event callback*/
            huart->RxEventCallback(huart, (huart->RxXferSize - huart->RxXferCount));
    #else
            /*Call legacy weak Rx Event callback*/
            HAL_UARTEx_RxEventCallback(huart, (huart->RxXferSize - huart->RxXferCount));
    #endif
          }
          return;
        }
        else
        {
          /* DMA mode not enabled */
          /* Check received length : If all expected data are received, do nothing.
             Otherwise, if at least one data has already been received, IDLE event is to be notified to user */
          uint16_t nb_rx_data = huart->RxXferSize - huart->RxXferCount;
          if (  (huart->RxXferCount > 0U)
              &&(nb_rx_data > 0U) )
          {
    #if defined(USART_CR1_FIFOEN)
            /* Disable the UART Parity Error Interrupt and RXNE interrupts */
            CLEAR_BIT(huart->Instance->CR1, (USART_CR1_RXNEIE_RXFNEIE | USART_CR1_PEIE));
    
            /* Disable the UART Error Interrupt: (Frame error, noise error, overrun error) and RX FIFO Threshold interrupt */
            CLEAR_BIT(huart->Instance->CR3, (USART_CR3_EIE | USART_CR3_RXFTIE));
    #else
            /* Disable the UART Parity Error Interrupt and RXNE interrupts */
            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);
    #endif
    
            /* Rx process is completed, restore huart->RxState to Ready */
            huart->RxState = HAL_UART_STATE_READY;
            huart->ReceptionType = HAL_UART_RECEPTION_STANDARD;
    
            /* Clear RxISR function pointer */
            huart->RxISR = NULL;
    
            CLEAR_BIT(huart->Instance->CR1, USART_CR1_IDLEIE);
    #if (USE_HAL_UART_REGISTER_CALLBACKS == 1)
            /*Call registered Rx complete callback*/
            huart->RxEventCallback(huart, nb_rx_data);
    #else
            /*Call legacy weak Rx Event callback*/
            HAL_UARTEx_RxEventCallback(huart, nb_rx_data);
    #endif
          }
          return;
        }
      }
    
      /* UART wakeup from Stop mode interrupt occurred ---------------------------*/
      if (((isrflags & USART_ISR_WUF) != 0U) && ((cr3its & USART_CR3_WUFIE) != 0U))
      {
        __HAL_UART_CLEAR_FLAG(huart, UART_CLEAR_WUF);
    
        /* UART Rx state is not reset as a reception process might be ongoing.
           If UART handle state fields need to be reset to READY, this could be done in Wakeup callback */
    
    #if (USE_HAL_UART_REGISTER_CALLBACKS == 1)
        /* Call registered Wakeup Callback */
        huart->WakeupCallback(huart);
    #else
        /* Call legacy weak Wakeup Callback */
        HAL_UARTEx_WakeupCallback(huart);
    #endif /* USE_HAL_UART_REGISTER_CALLBACKS */
        return;
      }
    /
    //空闲中断检测和回调就放在这里就可以//
      if(((isrflags & USART_ISR_IDLE) != 0U) && ((cr1its & USART_CR1_IDLEIE) != 0U))
      {	
          //当中断类型为空闲中断
          __HAL_UART_DISABLE_IT(huart,UART_IT_IDLE);    	//关了空闲中断
          HAL_UART_IdleCpltCallback(huart);				//调用空闲中断回调函数
          __HAL_UART_CLEAR_IDLEFLAG(huart);				//清除IDLE标志
          __HAL_UART_ENABLE_IT(huart,UART_IT_IDLE);    	//使能IDLE中断
          return;
      }
    ///上面的代码段为新添加的空闲中断检测和回调
    
      /* UART in mode Transmitter ------------------------------------------------*/
    #if defined(USART_CR1_FIFOEN)
      if (((isrflags & USART_ISR_TXE_TXFNF) != 0U)
          && (((cr1its & USART_CR1_TXEIE_TXFNFIE) != 0U)
              || ((cr3its & USART_CR3_TXFTIE) != 0U)))
    #else
      if (((isrflags & USART_ISR_TXE) != 0U)
          && ((cr1its & USART_CR1_TXEIE) != 0U))
    #endif /* USART_CR1_FIFOEN */
      {
        if (huart->TxISR != NULL)
        {
          huart->TxISR(huart);
        }
        return;
      }
    
      /* UART in mode Transmitter (transmission end) -----------------------------*/
      if (((isrflags & USART_ISR_TC) != 0U) && ((cr1its & USART_CR1_TCIE) != 0U))
      {
        UART_EndTransmit_IT(huart);
        return;
      }
    
    #if defined(USART_CR1_FIFOEN)
      /* UART TX Fifo Empty occurred ----------------------------------------------*/
      if (((isrflags & USART_ISR_TXFE) != 0U) && ((cr1its & USART_CR1_TXFEIE) != 0U))
      {
    #if (USE_HAL_UART_REGISTER_CALLBACKS == 1)
        /* Call registered Tx Fifo Empty Callback */
        huart->TxFifoEmptyCallback(huart);
    #else
        /* Call legacy weak Tx Fifo Empty Callback */
        HAL_UARTEx_TxFifoEmptyCallback(huart);
    #endif /* USE_HAL_UART_REGISTER_CALLBACKS */
        return;
      }
    
      /* UART RX Fifo Full occurred ----------------------------------------------*/
      if (((isrflags & USART_ISR_RXFF) != 0U) && ((cr1its & USART_CR1_RXFFIE) != 0U))
      {
    #if (USE_HAL_UART_REGISTER_CALLBACKS == 1)
        /* Call registered Rx Fifo Full Callback */
        huart->RxFifoFullCallback(huart);
    #else
        /* Call legacy weak Rx Fifo Full Callback */
        HAL_UARTEx_RxFifoFullCallback(huart);
    #endif /* USE_HAL_UART_REGISTER_CALLBACKS */
        return;
      }
    #endif /* USART_CR1_FIFOEN */
    }
    

    到此为止,HAL库就配置完了。。。。。。。。。。。。。。。。。。

    4.5 使用空闲中断

    因为空闲中断只有在开启串口接收中断才有意义,所以在初始化串口的时候,要在HAL_UART_Receive_IT函数后面在添加两个函数,用于开启空闲中断,如下:

    HAL_UART_Receive_IT(&huart1, &rx_temp, 1);			//hal库用于开启串口接收的函数
    __HAL_UART_CLEAR_IDLEFLAG(&huart1);  				//清除IDLE标志
    __HAL_UART_ENABLE_IT(&huart1, UART_IT_IDLE);       	// 使能 IDLE中断
    

    在编写串口接收回调函数HAL_UART_RxCpltCallback的时候,同时也要编写串口空闲中断回调函数HAL_UART_IdleCpltCallback

    和接收错误回调函数。如下:

    //串口接收中断回调函数
    void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
    {
        if(huart->Instance == USART1){
            
    		rx_data[rx_len] = rx_temp;
        	rx_len++;   // 接收到上个数据,长度+1
            HAL_UART_Receive_IT(&huart1, &rx_temp, 1);    // 继续使能RX中断
            
        }
    }
    //串口接收空闲中断回调函数,这个是从hal里面新加的
    void HAL_UART_IdleCpltCallback(UART_HandleTypeDef *huart)
    {
        if(huart->Instance == USART1){  
            
            //一般要在这里判断一下,是否已经接收到数据,防止误触发
            //经测试发现在开机刚开始使能idle中断的时候,会触发一次idle中断。
            if(rx_len >= 1){
                __NOP();//已经触发空闲中断回调,剩下内容由用户操作
            }
            
        }
    }
    //串口接收错误中断,下一节会说明为啥要有这个
    void HAL_UART_ErrorCallback(UART_HandleTypeDef *huart)
    {
    	if(HAL_UART_GetError(huart) & HAL_UART_ERROR_PE){		/*!< Parity error            */
    		//奇偶校验错误
    		__HAL_UART_CLEAR_PEFLAG(huart);
    	}else if(HAL_UART_GetError(huart) & HAL_UART_ERROR_NE){ /*!< Noise error             */
    		//噪声错误
    		__HAL_UART_CLEAR_NEFLAG(huart);
    	}else if(HAL_UART_GetError(huart) & HAL_UART_ERROR_FE){ /*!< Frame error             */
    		//帧格式错误
    		__HAL_UART_CLEAR_FEFLAG(huart);
    	}else if(HAL_UART_GetError(huart) & HAL_UART_ERROR_ORE){ /*!< Overrun error           */
    		//数据太多串口来不及接收错误
    		__HAL_UART_CLEAR_OREFLAG(huart);
    	}
        //当这个串口发生了错误,一定要在重新使能接收中断
        if(huart ->Instance == USART1){
    		HAL_UART_Receive_IT(&huart1, &rx_temp, 1);
    	}
        //其他串口......
    }
    

    5.其他:上面第四节使能串口接收错误回调的原因

    5.1 使能接收错误回调函数的原因

    当串口在接收数据产生了接收错误的时候,会导致串口接收中断失效,从而导致串口接收停止。

    以下几种情况可能会产生串口接收错误:

  • 串口在接收数据的时候受到干扰,比如做静电实验。
  • 数据量过大,串口一时间处理不过来,这个时候不止会丢包,还会产生接收错误,对于性能不高的mcu尤其严重。
  • 所以不处理接收错误中断,设备将存在不可预知的bug,这终究是个隐患

    解决方法就是使能接收错误中断,在接收错误中断回调函数里面先清除错误中断标志位,然后从新使能串口接收中断,这样串口接收就不会停止。代码上只需要添加错误回调函数就可以了,例子已经在上节给出。

    物联沃分享整理
    物联沃-IOTWORD物联网 » stm32: 串口空闲中断的实现(HAL库)

    发表评论