STM32 LL库串口丢包问题与解决

在CubeMx生成代码时,默认为 HAL 库,但也可以指定为 LL库,LL库基本是直接操作寄存器,功能较为单一,但是效率更高。串口使用HAL如果每次接收一个字次,由于HAL库的效率,容易丢包,若一次性接收多个字节,又需要固定的字节数。

于是这次使用了 LL 库,在LL库中: LL_USART_TransmitData8(); 为发送一个字节函数,通过查看定义可知,它直接操作了DR寄存器,所以效率很高。

这次想设计一个简单的程序:当收到字符A的时,发送字符E,但是发现居然有丢包的现象,这是由于程序逻辑问题导致的,这也是库函数使用者对寄存器操作不熟悉的原因,最后调整程序如下:

while (1)
  {
          
   
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
      static uint8_t recv;

      if(USART1->SR&(1<<5))                          //如果接受到数据
      {
          
   
          recv = LL_USART_ReceiveData8(USART1);      //读取数据
          if(recv == A)                            //如果是字符A
          {
          
   
             LL_USART_TransmitData8(USART1,E);     //发送字符E
             while((USART1->SR&0X40)==0);            //等待数据发送完成
             
          }
      }

    /* USER CODE BEGIN 3 */
  }

上文程序不断的轮询,判断是否接受到数据,再进行值的读取,将数据发送出去以后,等待数据发送完成,经测试效果稳定: 可以看到,100B/s 的速度发送了近4万个字节,也接到同样的数据,说明程序未丢包。

如果把 recv = LL_USART_ReceiveData8(USART1),移出if语句,如下:

// !!错误代码示例
  while (1)
  {
          
   
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
      static uint8_t recv;
      recv = LL_USART_ReceiveData8(USART1);          //读取数据
      if(USART1->SR&(1<<5))                          //如果接受到数据
      {
          
   
          if(recv == A)                           //如果是字符A
          {
          
   
             LL_USART_TransmitData8(USART1,E);    //发送字符E
             while((USART1->SR&0X40)==0);           //等待数据发送完成
             
          }
      }
    /* USER CODE BEGIN 3 */
  }

即未接收到新的数据,也不断的读取DR的值,程序测试会出现比较频繁的丢包。

可以看到,同样的数据发送,241个字节,才收到92个字节,丢包严重。原因可能是频繁的调用LL_USART_ReceiveData8()(读取DR的值),导致串口外设一直忙碌,最后导致了丢包。

经验分享 程序员 微信小程序 职场和发展