【问题标题】:stm32 USB receive more than 1 bytestm32 USB接收超过1个字节
【发布时间】:2020-01-30 08:12:45
【问题描述】:

我正在尝试在 PC 和 STM32 MCU 之间建立 USB 通信。我想从 PC 接收整数。 (整数范围在 0 到 20.000 之间)。我添加了这些行:

到 usb_cdc_if.h :

_weak void CDC_ReceiveCallBack(uint8_t *buf, uint32_t len);

到 usb_cdc_if.c

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);
  CDC_ReceiveCallBack(Buf, Len);
  return (USBD_OK);
  /* USER CODE END 6 */
}
.
.
.
__weak void CDC_ReceiveCallBack(uint8_t *buf, uint32_t len)
{}

在主类中:

void CDC_ReceiveCallBack(uint8_t *buf, uint32_t len)
{

fan_speed=atoi(buf);
    memset(statusString,0x00,255);
statusStringLength = sprintf(statusString,"Fan Speed: %d ", fan_speed);
    CDC_Transmit_FS(statusString,statusStringLength);
}

所以我只能收到 1 位数字。我应该在函数的开头添加一个 if 语句,当按下 enter 时,我应该从缓冲区接收它吗?

【问题讨论】:

    标签: c stm32


    【解决方案1】:

    我假设您想通过 USB 实现串行连接(也称为虚拟 COM 端口),并且您在 PC 上连接了一个终端应用程序...

    如果是这样,您需要了解:

    • 从 PC 发送到 MCU 的字符可以被分割成任意数据包。不可能确保一段文本在同一个数据包中。如果您在终端程序中输入,甚至可能每个字符都在单独的数据包中发送。如果您将长文本粘贴到终端程序中,您可能会收到最多 64 个字符的长数据包。

    • 接收到的数据是一个字符数组。它不是一个字符串(以 '\0' 结尾)。因此,除非数据已转换为字符串,否则不得使用atoistrlen 等字符串函数。

    为了进步:

    • 添加检测何时收到足够数据来处理它的代码。一种典型的方法是为其使用换行符,即保存所有接收到的数据,直到接收到整行。然后处理整行。

    • 在保存的数据中,添加'\0' 字符。这样,缓冲区就变成了一个字符串,可以用字符串函数来处理。

    它可能看起来像这样:

    char line_buffer[80];
    int line_len = 0;
    
    void CDC_ReceiveCallBack(uint8_t *buf, uint32_t len)
    {
        // append received data to line buffer
        memcpy(line_buffer + line_len, buf, len);
        line_len += len;
    
        while (1) {
            // check for linefeed character
            char* line_feed = memchr(buf, '\n', line_len);
            if (line_feed == NULL)
                break;
    
            // add string termination
            *line_feed = '\0';
            process_line(line_buffer);
    
            // copy remaining data to start of line buffer
            line_len -= line_feed + 1 - line_buffer;
            memcpy(line_buffer, line_feed + 1, line_len);
        }
    }
    
    void process_line(char* line) {
        // do something with the line; string functions are ok
    }
    

    注意代码不完整:

    • 它不检查接收到的数据是否适合line_buffer
    • 您可能会同时收到'\r''\n' 字符作为行分隔符。因此,您可能需要删除 '\r' 字符。
    • 我还没有测试过代码。它可能会丢失一些从void*char* 或从uint32_tint 的转换。

    【讨论】:

    • 在实践中,通常使用环形缓冲区(循环缓冲区),以及某种消息终止符和校验和。
    • @Groo 你有代码吗?我过去一直在为可变长度的消息使用环形缓冲区而苦苦挣扎?如果不再需要拆分消息,那就很难看。
    • 我们实际上有一个相当复杂的环形缓冲区实现,它抽象了几乎所有的操作,以允许它类似于线性缓冲区一样使用。也许对于一个小项目来说是过度设计的,但它消除了在缓冲区周围复制数据的需要,并允许我们同时从不同的中断读取数据(一个写入器 + 一个读取器)。例如,rb_peek_u16_le(&rb, x) 将在距尾部偏移 x 处解析一个 little-endian uint16 值。但你是对的,如果必须从头开始编写,那是相当多的工作。
    • 在努力找到一个好的通用实现来读取任意数量的字节之后 - 我决定在这里写一个:github.com/philrawlings/bluepill-usb-cdc-test 这实质上修改了usb_cdc_if.c 以创建一个循环缓冲区并公开其他功能(CDC_GetRxBufferBytesAvailable_FS()CDC_ReadRxBuffer_FS()CDC_FlushRxBuffer_FS())可以从main.c 消费。您可以一次读取一个字节,直到收到行终止符。
    猜你喜欢
    • 2021-03-29
    • 2020-12-25
    • 1970-01-01
    • 2018-12-16
    • 1970-01-01
    • 1970-01-01
    • 2014-08-14
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多