STM32 HAL库中,串口不定长接收使用技巧

HAL UART不定长接收使用技巧

本文只讨论了中断形式不定长接收,不同于网上常见例程,主要是我在项目上遇到的坑。我遇到的情况是,我希望接收一个定长的命令,但实际情况是,串口过来的数据可能短,可能长,那么,就出现了一系列问题。

HAL_UART_Receive_IT()

常见的接收定长的方式是HAL_UART_Receive_IT(&UartHandle,(uint8_t*)RxBuff,BUFFSIZE); 这种方式对于接收的数据每次一定是定长的就没有问题,但是对于偶尔数据不定长,就会出现故障,比如,当接收数据小于BUFFSIZE,那么就不会进入中断回调函数HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart),并且会堆积影响下一次接收,比如,我本来是要定长接收0x11,0x22,0x33,0x44这4个字节,当某一次只收到了0x11,0x22,然后下一次再收到0x11,0x22,0x33,0x44时,进入中断回调函数后,得到的数据就变为0x11,0x220x11,0x22了,并且多余的两个数据还会导致串口卡死,有例程解决这个方法是在中断响应函数里加空闲中断判断,当收到数据小于固定长度时,则做个标记进行判断处理和清空,这个方法我没复现,也许能行,但还有新的问题,那就是当接收的数据大于缓冲BUFFSIZE时,网上都说多余的数据会丢弃,实际我调试的时候根本没有被丢弃,而是会堆积到下一次接收里(而且还不知道缓存满了之后,他到底存到哪里去了,反正当开启下一次中断时,多余的数据会直接装到新的缓存里),并且,再接收几次就串口卡死了。

网上也有办法就是将BUFFSIZE设置为1,每来一个数据就判断一次,这种方法兴许能行,但对于追求程序优化来说,这种方式实在太蛮干,不是解决问题的根本。

HAL_UARTEx_ReceiveToIdle_IT()

后来,看到一个方法说用空闲中断,不得不说,这个方法很棒,既然来的数据可能长短不一,那么我就接收到空闲为止,然后在判断接收到数据。这个方法HAL_UARTEx_ReceiveToIdle (UART_HandleTypeDef * huart, uint8_t * pData,
uint16_t Size, uint16_t * RxLen, uint32_t Timeout)接收的好处就是,某次接收到数据短于接收到的数据,是不会影响下一次接收的,也不会导致串口卡死,但也存在一个问题,那就是当某一次接收的数据大于设定的缓存,也会导致后续接收时串口卡死,这种情况可采用将缓存设置得很大的方式来解决。不过这终究不是合适的办法,因为很浪费内存空间。

UART_HandleTypeDef

typedef struct __UART_HandleTypeDef
{
  USART_TypeDef            *Instance;                /*!< UART registers base address        */

  UART_InitTypeDef         Init;                     /*!< UART communication parameters      */

  UART_AdvFeatureInitTypeDef AdvancedInit;           /*!< UART Advanced Features initialization parameters */

  const uint8_t            *pTxBuffPtr;              /*!< Pointer to UART Tx transfer Buffer */

  uint16_t                 TxXferSize;               /*!< UART Tx Transfer size              */

  __IO uint16_t            TxXferCount;              /*!< UART Tx Transfer Counter           */

  uint8_t                  *pRxBuffPtr;              /*!< Pointer to UART Rx transfer Buffer */

  uint16_t                 RxXferSize;               /*!< UART Rx Transfer size              */

  __IO uint16_t            RxXferCount;              /*!< UART Rx Transfer Counter           */

  uint16_t                 Mask;                     /*!< UART Rx RDR register mask          */

  __IO HAL_UART_RxTypeTypeDef ReceptionType;         /*!< Type of ongoing reception          */

  __IO HAL_UART_RxEventTypeTypeDef RxEventType;      /*!< Type of Rx Event                   */

  void (*RxISR)(struct __UART_HandleTypeDef *huart); /*!< Function pointer on Rx IRQ handler */

  void (*TxISR)(struct __UART_HandleTypeDef *huart); /*!< Function pointer on Tx IRQ handler */

  DMA_HandleTypeDef        *hdmatx;                  /*!< UART Tx DMA Handle parameters      */

  DMA_HandleTypeDef        *hdmarx;                  /*!< UART Rx DMA Handle parameters      */

  HAL_LockTypeDef           Lock;                    /*!< Locking object                     */

  __IO HAL_UART_StateTypeDef    gState;              /*!< UART state information related to global Handle management
                                                          and also related to Tx operations. This parameter
                                                          can be a value of @ref HAL_UART_StateTypeDef */

  __IO HAL_UART_StateTypeDef    RxState;             /*!< UART state information related to Rx operations. This
                                                          parameter can be a value of @ref HAL_UART_StateTypeDef */

  __IO uint32_t                 ErrorCode;           /*!< UART Error code                    */

仔细观察了调试过程中的UART_HandleTypeDef参数的变化,采用HAL_UARTEx_ReceiveToIdle_IT(&UART_HANDLE,(uint8_t*)RxBuff,BUFFSIZE_RX)时,假如设置的缓存大小BUFFSIZE_RX是4,此时,若来了一个长度为5的数据, 那么,响应中断回调函数void HAL_UARTEx_RxEventCallback(UART_HandleTypeDef *huart, uint16_t Size)时,RxBuff装了接收到的前4个数据,当再开启空闲中断时,UART_HANDLE的RxXferSize=4,RxXferCount=3(每接收到一个数据RxXferCount会减1),*pRxBuffPtr存储了第5个数据。也就是说多余的数据其实是按地址增加一直存在地址空间,并不是像网上说的那样大于缓存的数据就丢失了。这里我不需要多余的数据,如果不进行处理,后续串口会出现卡死现象,因此这里刚打开中断时需要进行判断一下,防止上一次多余的数据导致堆积导致串口堵死。

	  HAL_UARTEx_ReceiveToIdle_IT(&UART_HANDLE,(uint8_t*)RxBuff,BUFFSIZE_RX);//开启空闲中断接收
	  if(UART_HANDLE.RxXferCount < UART_HANDLE.RxXferSize)
	  {
		  UART_HANDLE.RxXferCount = UART_HANDLE.RxXferSize;
		  UART_HANDLE.pRxBuffPtr = (uint8_t*)RxBuff;
	  }

当然,如果多余的数据也需要,也可以提取出去进行处理。
如此,就解决了HAL UART接收不定长数据的问题。

  • 11
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值