【STM32+cubemx】0016 HAL库开发:USB虚拟串口(virtual COM)
stm32很多系列的芯片都带usb接口,而且cubemx也能生成多种功能的usb初始化代码,使得一般用户可以不用关注usb底层复杂的实现方式,直接使用HAL函数就能方便地实现usb通信。本节我们就来学习cubemx生成虚拟串口(USB virtual COM)的使用方法。
1)生成USB虚拟串口工程
仍然使用串口工程,如下图添加USB的配置:
可以看到,勾选usb device的功能后,右侧的芯片引脚已经设置好了,DP和DM两根线就是usb通信的差分线。
再配置USB的软件中间件,选择usb device,virtual port COM,也就是虚拟串口:
修改时钟设置,把usb时钟设置为48M:
其他的配置都不用改,就可以生成工程代码了。
2)收、发函数的改写
打开生成的keil工程,可以看到已经生成了几个usb相关的源文件:
简单说明一下这几个文件的作用:
usb_device.c是USB设备函数初始化函数MX_USB_DEVICE_Init(),在main函数开始时会调用;
usb_desc.c包含USB的描述符,以及USB枚举处理等函数,也属于初始配置的一些函数;
usb_conf.c是管脚配置文件,包含引USB引脚初始化以及参数设置,中断回调函数等;
usbd_cdc_if.c是USB的CDC类应用层文件,里面包含虚拟串口的接收,发送和控制等函数,也是我们主要关注的一个文件。
打开usbd_cdc_if.c文件,找到CDC_Receive_FS和CDC_Transmit_FS这两个函数,它们就是应用层实现收、发的函数。
先看发送函数,这个函数可以直接被用户使用:
简单地调用这个函数,只要输入发送数据的首地址、长度,就能把数据从usb虚拟串口发送出去了。
这里为了更方便地使用,我们添加以下重定向代码:
和串口输出的重定向一样,我们将usb输出也重定向到一个函数USBVcom_printf,这样我们也能像使用printf一样使用usb向外输出数据了。
与串口重定向的实现基本一样,只是把串口的语句发送替换成了USB的发送。
再看接收函数:
选中的两行是我们需要添加的,其他的都是HAL库自动生成的。
这个函数实现了接收数据,把接收到的(*Len)个数据存放在Buf地址中。由于这个函数是static类型的,只能在该文件内使用,不要在用户的代码中调用它;所以我们只添加两条语句,将数据和长度传出来就行了。
Memcpy()函数实现了把Buf中的数拷贝到usb_rx_data中。
改写完发送和接收函数,就可以开始测试了。
3)系统测试
在主函数的循环中添加如下测试用代码:
这里将发送和接收都测试了一下。
USBVcom_printf()函数每1s固定从usb虚拟串口发出一串数据,用来验证发送;
if(...) {... } 代码段中,检测usb虚拟串口是否有收到数,如果长度不为0则收到了数,把收到的数通过实际的串口1发送回去;再重置长度标志为0,等待下一次接收。
到这里,测试代码就编写完了。
在测试前,先确认一下开发板的硬件状态,开发板的usb口需要用usb线连接到计算机的U口;另外,硬件上,DP(也就是PA12)需要用电阻上拉,否则计算机不能识别出usb设备:
编译代码、下载运行后,可发现计算机多识别出了一个串口5:
(有些系统较老的计算机可能需要安装驱动程序,可在文末获取代码和驱动下载)
用两个串口调试助手进行试验。
一个打开com5,一个打开com3;可以看到com5每1s可以收到一串数据,是usb虚拟串口发出来的;从com5发送一串数据出去,可以看到com3打印了出来,说明stm32端通过虚拟串口收到了数据,并从实际的串口打印出来了:
注意,usb虚拟串口的波特率(com5)可以设为其他值,能够自动识别。
Cubemx生成的虚拟串口,只实现了基本的功能,实际工程中使用时,还需要增加许多提高稳定性、容错性的代码,才能成为可靠的产品。
好了,本节usb虚拟串口的简单使用,就讲到这里了。