STM32 USB CDC长数据包接收

问题描述

我需要将数据从PC发送到STM32F3,所以我决定在uC中使用内置USB。 但是现在我有一个问题-我想一次向stm32发送大量数据-我的意思是大约200-500字节。

当我从PC发送带有少于64个图表的minicom数据包时-一切都很好-回调CDC_Receive_FS(uint8_t * Buf,uint32_t * Len)发生一次-它启用了UsbRxFlag,只是通知正在运行的程序有数据可用。

static int8_t CDC_Receive_FS(uint8_t* Buf,uint32_t *Len)
{
  /* USER CODE BEGIN 6 */
  USBD_CDC_SetRxBuffer(&hUsbDeviceFS,&Buf[0]);
  USBD_CDC_ReceivePacket(&hUsbDeviceFS);
  if( (Buf[0] == 'A') & (Buf[1] == 'T') ){
      GPIOB->BSRR = (uint32_t)RX_Led_Pin;
      UsbRxFlag = 1;
  }

  return (USBD_OK);
  /* USER CODE END 6 */
}

但是,当我尝试向uC发送更多数据(只是从minicom发送的长文本)时,会发生一些奇怪的事情-有时uC根本不响应-有时没有考虑到某些数据。

如何处理通过USB-CDC向STM32F3发送超过64Bytes的数据?

解决方法

全速USB通信的最大数据包长度为64字节。因此,数据将以64字节的块形式传输,并且需要在另一端重新组装。

USB CDC基于批量传输端点,并实现了数据流(也称为 pipe ),而不是消息流。基本上是字节流。因此,如果您发送200个字节,请不要期望任何指示200个字节结束的位置。这样的信息不会被发送。

您的代码看起来有点可疑:

  • 您可能是说'&&'而不是恢复莫妮卡指出的'&'。
  • 除非更改缓冲区,否则USBD_CDC_SetRxBuffer仅需要在初始化时被调用一次。
  • 调用CDC_Receive_FS时,已经接收到一个数据包。 Buf将指向您用USBD_CDC_SetRxBuffer指定的缓冲区。 Len提供数据包的长度。因此,您要做的第一件事是处理接收到的数据。处理完数据并再次使用缓冲区后,您将调用USBD_CDC_ReceivePacket表示已准备好接收下一个数据包。因此,将USBD_CDC_SetRxBuffer移至另一个函数(除非您要使用多个缓冲区),然后将USBD_CDC_ReceivePacket移至CDC_Receive_FS的末尾。

错误的函数调用顺序可能会导致在您仍在处理接收的数据时将其覆盖。

但是最大的问题可能是,如果发送的是单个数据,则您希望接收到的所有数据都是单个数据,或者至少包含该数据结束的指示。事实并非如此。您必须自己实现。

如果使用文本协议,则可以缓冲所有传入数据,直到检测到换行符为止。然后,您知道您拥有完整的命令并可以执行它。

,

以下是读取任意数量字节的通用实现:https://github.com/philrawlings/bluepill-usb-cdc-test

完整代码有点太长,无法在此处发布,但这实质上修改了 usb_cdc_if.c 以创建循环缓冲区并公开其他函数(CDC_GetRxBufferBytesAvailable_FS()CDC_ReadRxBuffer_FS() 和 {{1} }) 可以从 CDC_FlushRxBuffer_FS() 消费。主页上显示的 readme.md 文本描述了所需的所有代码更改。

正如@Codo 所提到的,您需要在源数据中添加终止字符,或者在开头包含一个“长度”值(它本身是一个固定的字节数),然后指示有多少字节在数据负载中。

相关问答

错误1:Request method ‘DELETE‘ not supported 错误还原:...
错误1:启动docker镜像时报错:Error response from daemon:...
错误1:private field ‘xxx‘ is never assigned 按Alt...
报错如下,通过源不能下载,最后警告pip需升级版本 Requirem...