一.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判断的方式。这里我们仅对其接收函数进行改写,实现任意长度字节接收,且不需要结束字符判断。
二.接收函数实现源码
这里要先对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
{
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,也就是判断接收标志
{
u***_printf("您发送的消息长度为:%drnrn",VCP_DataRx_Len);
VCP_DataTx(USB_USART_RX_BUF,VCP_DataRx_Len);//调用USB串口发送函数将接收到的数据发送出去
u***_printf("rnrn");//插入换行
VCP_DataRx_Len=0; //接收数据个数清零
receive_times=0; //进入接收中断次数清零
}
}
三.小结
USB虚拟串口功能很具有实用功能,在不需要进行电平转换的情况下直接通过USB与电脑实现串口通信。本文主要对USB串口接收数据做了处理,巧妙的解决了USB串口一次只能接受64字节的局限,算是自己开发过程中用到的小技巧,与大家分享,谢谢!
一.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判断的方式。这里我们仅对其接收函数进行改写,实现任意长度字节接收,且不需要结束字符判断。
二.接收函数实现源码
这里要先对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
{
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,也就是判断接收标志
{
u***_printf("您发送的消息长度为:%drnrn",VCP_DataRx_Len);
VCP_DataTx(USB_USART_RX_BUF,VCP_DataRx_Len);//调用USB串口发送函数将接收到的数据发送出去
u***_printf("rnrn");//插入换行
VCP_DataRx_Len=0; //接收数据个数清零
receive_times=0; //进入接收中断次数清零
}
}
三.小结
USB虚拟串口功能很具有实用功能,在不需要进行电平转换的情况下直接通过USB与电脑实现串口通信。本文主要对USB串口接收数据做了处理,巧妙的解决了USB串口一次只能接受64字节的局限,算是自己开发过程中用到的小技巧,与大家分享,谢谢!
举报