路有阻夷,旅行者知 2024-04-09 18:52 采纳率: 0%
浏览 18

USB复合设备CDC两个COM同时使用出现问题

使用STM32G431创建USB转TTL和USB转CAN功能的模块,使用了USBCDC类的复合,生成两个COM口,当CAN和串口同时使用时,不打开串口的COM口仅打开CAN的COM口有时主机接收不到上位机的消息,这是什么原因?

这是串口向主机的发送函数
uint8_t CDC_Transmit_FS(uint8_t* Buf, uint16_t Len)
{
  uint8_t result = USBD_OK;
  /* USER CODE BEGIN 7 */
    HAL_UART_Transmit_DMA(&huart2,Buf,Len);
    system_irq_disable();

    // Process transmit buffer
    USBD_CDC_HandleTypeDef *hcdc = (USBD_CDC_HandleTypeDef*)hUsbDeviceFS.pClassData;

    if (hcdc->TxState != 0){
        return USBD_BUSY;
    }
    USBD_CDC_SetTxBuffer(&hUsbDeviceFS, Buf, Len);
    USBD_CDC_TransmitPacket(&hUsbDeviceFS, CDC2_IN_EP);

    system_irq_enable();
  /* USER CODE END 7 */
  return USBD_OK;
}
这是CAN的发送函数
    // Process transmit buffer
    USBD_CDC_HandleTypeDef *hcdc = (USBD_CDC_HandleTypeDef*)hUsbDeviceFS.pClassData;
    if(hcdc->TxState == 0)
    {
        uint16_t linbuf_ctr = 0;
        while(txbuf.tail != txbuf.head)
        {
            tx_linbuf[linbuf_ctr++] = txbuf.data[txbuf.tail];
            txbuf.tail = (txbuf.tail + 1UL) % USBTXQUEUE_LEN;

            // Take up to the number of bytes to fill the linbuf
            if(linbuf_ctr >= TX_LINBUF_SIZE)
                break;
        }

        if(linbuf_ctr > 0)
        {
            // Set transmit buffer and start TX
            USBD_CDC_SetTxBuffer(&hUsbDeviceFS, tx_linbuf, linbuf_ctr);
            USBD_CDC_TransmitPacket(&hUsbDeviceFS, CDC_IN_EP);
        }
    }

``````

  • 写回答

4条回答 默认 最新

  • 码农阿豪@新空间代码工作室 Java领域优质创作者 2024-04-09 18:52
    关注
    让阿豪来帮你解答,本回答参考chatgpt3.5编写提供,如果还有疑问可以评论或留言
    问题描述: 在使用STM32G431创建USB转TTL和USB转CAN功能的模块时,使用了USBCDC类的复合,生成两个COM口。当CAN和串口同时使用时,只打开CAN的COM口时,主机有时会接收不到上位机的消息,造成这种情况的原因是什么? 回答: 可能是因为串口和CAN同时使用导致数据冲突,串口数据和CAN数据发生了竞争,从而导致主机无法正确接收到上位机的消息。此时建议在串口数据和CAN数据发送时进行数据缓存,分别处理,避免数据竞争引起的问题。 优化建议: 1.在串口数据发送函数中加入数据缓存。可以使用队列进行缓存,并在DMA传输完成后将数据取出。例如:
    typedef struct {
      uint8_t data[SERIAL_TX_BUFFER_SIZE]; //缓存数组
      uint32_t head; //队列头
      uint32_t tail; //队列尾
    } serial_tx_buffer_t;
    static serial_tx_buffer_t txbuf; //全局变量,用于存放队列
    /*将数据写入到缓存中*/
    void serial_write_buf(const uint8_t *data, uint32_t len) {
      uint32_t i = 0;
      for (i = 0; i < len; i++) {
        uint32_t next_tail = (txbuf.tail + 1UL) % SERIAL_TX_BUFFER_SIZE;
        if (next_tail == txbuf.head) { //队列已满
          return;
        }
        txbuf.data[txbuf.tail] = data[i];
        txbuf.tail = next_tail;
      }
    }
    /*将缓存中的数据发送出去*/
    void serial_send_buf(void) {
      if (!huart2.gState) { // UART空闲
        uint32_t size = 0;
        if (txbuf.tail >= txbuf.head) {
          size = txbuf.tail - txbuf.head;
        } else {
          size = SERIAL_TX_BUFFER_SIZE - txbuf.head + txbuf.tail;
        }
        if (size) {
          HAL_UART_Transmit_DMA(&huart2, &txbuf.data[txbuf.head], size);
          txbuf.head = txbuf.tail;
        }
      }
    }
    

    2.在CAN数据发送函数中加入数据缓存。同样可以使用队列进行缓存,并在USB中断中将数据取出发送。例如:

    #define USBTXQUEUE_LEN 1024
    #define TX_LINBUF_SIZE 256
    typedef struct _usbtxqueue_t {
      uint8_t data[USBTXQUEUE_LEN];
      volatile uint16_t head;
      volatile uint16_t tail;
    } usbtxqueue_t;
    static usbtxqueue_t txbuf; //全局变量,用于存放队列
    uint8_t tx_linbuf[TX_LINBUF_SIZE];
    /*将数据写入到缓存队列中*/
    void usb_write_buf(const uint8_t *data, uint16_t len) {
      uint16_t next_tail;
      for (int i = 0; i < len; i++) {
        next_tail = (txbuf.tail + 1UL) % USBTXQUEUE_LEN;
        if (next_tail == txbuf.head) { //队列已满
          return;
        }
        txbuf.data[txbuf.tail] = data[i];
        txbuf.tail = next_tail;
      }
    }
    /*在USB中断中将缓存中的数据发送出去*/
    void usb_cdc_if_tx(uint8_t epnum) {
      if ((epnum == CDC_IN_EP) && (txbuf.tail != txbuf.head)) {
        uint16_t linbuf_ctr = 0;
        while (txbuf.tail != txbuf.head) {
          tx_linbuf[linbuf_ctr++] = txbuf.data[txbuf.head];
          txbuf.head = (txbuf.head + 1UL) % USBTXQUEUE_LEN;
          if (linbuf_ctr >= TX_LINBUF_SIZE) { //缓存区满,跳出循环
            break;
          }
        }
        USBD_CDC_SetTxBuffer(&hUsbDeviceFS, tx_linbuf, linbuf_ctr);
        USBD_CDC_TransmitPacket(&hUsbDeviceFS, CDC_IN_EP);
      }
    }
    

    以上仅为例子,具体实现可以根据实际情况来决定。

    评论

报告相同问题?

问题事件

  • 创建了问题 4月9日

悬赏问题

  • ¥15 is not in the mmseg::model registry。报错,模型注册表找不到自定义模块。
  • ¥15 安装quartus II18.1时弹出此error,怎么解决?
  • ¥15 keil官网下载psn序列号在哪
  • ¥15 想用adb命令做一个通话软件,播放录音
  • ¥30 Pytorch深度学习服务器跑不通问题解决?
  • ¥15 部分客户订单定位有误的问题
  • ¥15 如何在maya程序中利用python编写领子和褶裥的模型的方法
  • ¥15 Bug traq 数据包 大概什么价
  • ¥15 在anaconda上pytorch和paddle paddle下载报错
  • ¥25 自动填写QQ腾讯文档收集表