1、单片机型号:STM32H743IIT6;正点原子-阿波罗版
2、Keil-MDK:V5.32
3、CubeMX:6.7.0
4、HAL:STM32Cube FW_H7 V1.11.0
5、参考文章:
1.STM32 USB使用记录:使用CDC类虚拟串口(VCP)进行通讯
2.STM32CubeIDE 简单配置USB虚拟串口 并实现printf
3.STM32Cube配置USB虚拟串口发送与接收回传
4.STM32USB开发备忘之CDC_VCP实验
主要修改usbd_cdc_if.c和main.c,会使用这四个函数,就可以用单片机与PC进行USB基本通信:
CDC_Control_FS()
来自主机请求的回调函数;CDC控制命令处理,列举了主机有可能向设备发送的一些命令。没有具体的处理过程,需要用户自己编写。其中包括串口参数的设置,要做串口转USB通信的话需要修改这里。只是为了用USB与PC通信则不用管这里。每个命令具体的意思需要查询CDC类手册。
CDC_Receive_FS()
接收数据回调函数;Buf为接收缓存。这个缓存实际上就是CDC_Init_FS()中设置的UserRxBufferFS[]数组。这个全局数组的定义在usbd_cdc_if.c文件中。Len为接收到数据的长度。这个变量不是全局的,需要用户声明变量把这个传出去。
CDC_Transmit_FS()
用来发送数据;
CDC_TransmitCplt_FS()
发送完成回调函数;
#include "usbd_core.h"
#include "usbd_cdc.h"
#include "usbd_cdc_if.h"
char USB_TxBuf[32];
uint16_t len;
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
len=sprintf(USB_TxBuf,"Hello GJtech!\r\n");
CDC_Transmit_FS((uint8_t*)USB_TxBuf,len);
HAL_Delay(1000);
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
}
接收函数在usbd_cdc_if.h中并没有给出,而是在usbd_cdc_if.c中以static关键字给出的,这个函数其实是在USB接收时自动进入中断并调用的,可以直接在其中将接收缓冲区的内容做处理或转存。
static int8_t CDC_Receive_FS(uint8_t* Buf, uint32_t *Len)
{
CDC_Transmit_FS(Buf,*Len);
USBD_CDC_SetRxBuffer(&hUsbDeviceFS, &Buf[0]);
USBD_CDC_ReceivePacket(&hUsbDeviceFS);
return (USBD_OK);
}
/* USER CODE BEGIN PRIVATE_FUNCTIONS_IMPLEMENTATION */
#include
void usb_printf(const char *format, ...)
{
va_list args;
uint32_t length;
va_start(args, format);
length = vsnprintf((char *)UserTxBufferFS, APP_TX_DATA_SIZE, (char *)format, args);
va_end(args);
CDC_Transmit_FS(UserTxBufferFS, length);
}
/* USER CODE END PRIVATE_FUNCTIONS_IMPLEMENTATION */
在此正点原子单片机上,编写Python代码测试速度,可得到单片机发送数据速度为868.352K Byte/s(6.9M bps),接收速度为804.864K Byte/s(6.4M bps)。
因为相比硬件串口而言,USB虚拟的串口速度可以变得非常快,图形化的串口工具已经无法用来测速了,所以用python写了个脚本进行测试,测试脚本如下:
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
from typing import Counter
import serial
import serial.tools.list_ports
import time
import datetime
print('正在搜索串口……')
port_list = list(serial.tools.list_ports.comports())
print('发现串口:')
for i in range(0, len(port_list)):
print(port_list[i])
print('')
port = input('请输入串口号,并按回车确认: ')
print('')
ser = serial.Serial(port, 22333, timeout=5)
run = True
count = 0
starttime = int(round(time.time() * 1000))
print(datetime.datetime.now().strftime('%H:%M:%S.%f') + ':开始测试单片机向上位机发送数据……')
ser.write('S'.encode('utf-8'))
while (run):
ser.read(2048) # 接收来自单片机的数据
count += 1
currenttime = int(round(time.time() * 1000))
run = False if (currenttime - starttime) >= 1000 else True
ser.write('E'.encode('utf-8'))
print(datetime.datetime.now().strftime('%H:%M:%S.%f') + ':结束测试,速度约为 ' + str(count * 2048 / 1000) + 'K Byte/s' +'='+ str(count * 2048 / 1000*8) + 'K bps\n')
sendbuf = bytes(2048)
run = True
count = 0
starttime = int(round(time.time() * 1000))
print(datetime.datetime.now().strftime('%H:%M:%S.%f') + ':开始测试单片机接收上位机的数据……')
while (run):
count += ser.write(sendbuf) # 向单片机发送数据
currenttime = int(round(time.time() * 1000))
run = False if (currenttime - starttime) >= 1000 else True
print(datetime.datetime.now().strftime('%H:%M:%S.%f') + ':结束测试,速度约为 ' + str(count / 1000) + 'K Byte/s' +'=' +str(count / 1000*8) + 'K bps\n')
ser.close()
exit()