USB VCP虚拟串口通讯详细配置步骤(STM32H732)

USB VCP虚拟串口通讯详细配置步骤(STM32H732)

  • 一、软件版本
  • 二、CodeMX配置
        • 1、使能外部高速时钟。
        • 2、开启USB外设,选择USB Device功能,速度为默认全速USB设备12Mbps,使用默认配置。
        • 3、配置中间层使能CDC(VPC),参数依然全默认。
        • 4、时钟配置,选用外部HSE时钟源,将USB时钟配置为48MHz。
        • 5、修改Heap Size和Stack Size大小,太小导致串口识别不到或者识别错误出现黄色感叹号。
        • 6、生成Keil工程,编译运行代码。
        • 7、打开设备管理器,复位单片机,识别到虚拟串口。
  • 三、软件配置
        • 1、单片机向PC发送,在main.c中声明发送字符串和长度。
        • 2、PC向单片机发送,在usbd_cdc_if.c修改函数,实现接收回传。
        • 3、添加USB_printf打印函数,在usbd_cdc_if.c添加函数,方便直接输出字符串。
  • 四、速度测试

一、软件版本

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实验

二、CodeMX配置

1、使能外部高速时钟。

USB VCP虚拟串口通讯详细配置步骤(STM32H732)_第1张图片

2、开启USB外设,选择USB Device功能,速度为默认全速USB设备12Mbps,使用默认配置。

USB VCP虚拟串口通讯详细配置步骤(STM32H732)_第2张图片

3、配置中间层使能CDC(VPC),参数依然全默认。

USB VCP虚拟串口通讯详细配置步骤(STM32H732)_第3张图片

4、时钟配置,选用外部HSE时钟源,将USB时钟配置为48MHz。

USB VCP虚拟串口通讯详细配置步骤(STM32H732)_第4张图片
USB VCP虚拟串口通讯详细配置步骤(STM32H732)_第5张图片

5、修改Heap Size和Stack Size大小,太小导致串口识别不到或者识别错误出现黄色感叹号。

USB VCP虚拟串口通讯详细配置步骤(STM32H732)_第6张图片

6、生成Keil工程,编译运行代码。

USB VCP虚拟串口通讯详细配置步骤(STM32H732)_第7张图片

7、打开设备管理器,复位单片机,识别到虚拟串口。

USB VCP虚拟串口通讯详细配置步骤(STM32H732)_第8张图片

USB VCP虚拟串口通讯详细配置步骤(STM32H732)_第9张图片

三、软件配置

主要修改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()

发送完成回调函数;

1、单片机向PC发送,在main.c中声明发送字符串和长度。
#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 */
}

USB VCP虚拟串口通讯详细配置步骤(STM32H732)_第10张图片

USB VCP虚拟串口通讯详细配置步骤(STM32H732)_第11张图片

2、PC向单片机发送,在usbd_cdc_if.c修改函数,实现接收回传。

接收函数在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);
}

USB VCP虚拟串口通讯详细配置步骤(STM32H732)_第12张图片
USB VCP虚拟串口通讯详细配置步骤(STM32H732)_第13张图片

3、添加USB_printf打印函数,在usbd_cdc_if.c添加函数,方便直接输出字符串。
/* 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 */

USB VCP虚拟串口通讯详细配置步骤(STM32H732)_第14张图片

四、速度测试

在此正点原子单片机上,编写Python代码测试速度,可得到单片机发送数据速度为868.352K Byte/s(6.9M bps),接收速度为804.864K Byte/s(6.4M bps)。
USB VCP虚拟串口通讯详细配置步骤(STM32H732)_第15张图片

因为相比硬件串口而言,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()

你可能感兴趣的:(蓝桥杯,stm32,单片机,嵌入式硬件,python)