打印
[应用相关]

USB虚拟串口实现多字节数据接收,基于stm32h743

[复制链接]
3093|4
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
coshi|  楼主 | 2021-7-7 13:18 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
一.USB虚拟串口原理简介
  USB 虚拟串口,简称 VCP,是 Virtual COM Port 的简写,它是利用 USB 的 CDC 类来实现的一种通信接口。
  我们可以利用 STM32 自带的 USB 功能,来实现一个 USB 虚拟串口,从而通过 USB,实现电脑与 STM32 的数据互传。上位机无需编写专门的 USB 程序,只需要一个串口调试助手即可调试,非常实用。
  这里我们移植HAL库的标准底层驱动文件,实现USB的底层配置。移植USB工程需要包含三个文件夹:
USB_DEVICE:USB设备选择,这里我们选择CDC类,用来实现虚拟串口
USB_CORE:内核文件,基本不需改动
USB_APP:用户层代码编写,由用户自己编写,实现功能
  由于USB协议规定,一次最多只能接收64字节数据,如果要传输的字节数是64整数倍,都要多传输一个0字节的数据包。而这里经过改写接收函数,可以实现任意长度数据的接收!!!非常方便。由于实现驱动的代码部分十分繁杂,就不一一列举,可参考正点原子的例程。正点原子的串口接收采用的是0x0a,0x0d判断的方式。这里我们仅对其接收函数进行改写,实现任意长度字节接收,且不需要结束字符判断。


使用特权

评论回复
沙发
coshi|  楼主 | 2021-7-7 13:20 | 只看该作者
二.接收函数实现源码

  这里要先对USB虚拟串口接收数据的流程做一个说明:在进行内核代码初始化后,USB会自动调用函数进行串口接收监测,一旦串口接收到数据就进入串口接收函数处理。调用的函数如下:

//CDC数据接收函数,供USB内核调用,用来接受数据
//Buf:接收数据缓冲区
//Len:接收到的数据长度
static int8_t CDC_Itf_Receive(uint8_t *Buf,uint32_t *Len)
{
    SCB_CleanDCache_by_Addr((uint32_t *)Buf,*Len);
    USBD_CDC_ReceivePacket(&USBD_Device);
    VCP_DataRx(Buf,*Len);
    return (USBD_OK);
}




CDC_Itf_Receive()函数是供USB内核调用的,用来接收数据,其中又调用了VCP_DataRx(Buf,*Len)函数供用户层对接收到的数据进行处理。我们要改写的就是VCP_DataRx(Buf,*Len)函数。这里要注意的是之前提到由于USB协议规定,一次最多只能接收64字节数据,因此若接收到的字节数小于64,则该函数只被调用一次,若是大于64字节则需被多次调用,这里我们按照这个原则来对其进行改写:

u8 receive_times=0;                //定义调用该函数的次数
u32 VCP_DataRx_Len=0;              //定义USB_Usart接收数据长度
uint16_t VCP_DataRx (uint8_t* Buf, uint32_t Len)
{
        u32 i;
    for(i=0;i<Len;i++)
    {
        USB_USART_RX_BUF[64*receive_times+i]=Buf;  //将接受到的数据放置在接收缓存区,缓存区大小可由自己定义
    }
    receive_times++;                        //进入一次接收函数标记接收次数加一
    VCP_DataRx_Len=64*(receive_times-1)+Len;//计算出最终接受到的字节数
        return USBD_OK;
}



上述代码很简单,主要工作是对调用接收函数的次数进行计数,最终获得完整的接收数据以及实际接收到的字节数。

  在主函数中我们对接收数据做判断并显示出来:

extern u32 VCP_DataRx_Len;                       //外部声明USB_Usart接收数据长度
extern u8 receive_times;                         //外部声明进入接收中断次数
while(1)
{
    if(VCP_DataRx_Len)        //判断接收的字节数是否为0,也就是判断接收标志
        {                                          
                usb_printf("您发送的消息长度为:%d\r\n\r\n",VCP_DataRx_Len);
        VCP_DataTx(USB_USART_RX_BUF,VCP_DataRx_Len);//调用USB串口发送函数将接收到的数据发送出去
                usb_printf("\r\n\r\n");//插入换行
                VCP_DataRx_Len=0;      //接收数据个数清零
        receive_times=0;       //进入接收中断次数清零
        }
}          


使用特权

评论回复
板凳
木木guainv| | 2021-8-6 12:35 | 只看该作者
虚拟串口感觉不好调试啊

使用特权

评论回复
地板
xiaoqizi| | 2021-8-6 12:39 | 只看该作者
如何自动生成虚拟串口呢

使用特权

评论回复
5
wowu| | 2021-8-6 12:43 | 只看该作者
接收数据可以不是定长的吗

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

95

主题

3301

帖子

4

粉丝