开发环境:
IDE:MKD 5.38a
STM32CubeMX: V6.12.0
开发板:STM32H7S78-DK开发板
MCU:STM32H7S7L8H6H
1 USB 虚拟串口简介
USB 虚拟串口,简称 VCP,是 Virtual COM Port 的简写,它是利用 USB 的 CDC 类来实现的一种通信接口。
我们可以利用 STM32 自带的 USB 功能,来实现一个 USB 虚拟串口,从而通过 USB,实现电脑与 STM32 的数据互传。上位机无需编写专门的 USB 程序,只需要一个串口调试助手即可调试,非常实用。
2 USB硬件电路
USB的硬件电路如下:
Figure 2-1 USB的硬件电路
USB接口PM11和PM12。
3 USB实现虚拟串口(VPC)
3.1 STM32CubeMX配置工程
首先打开USB使能。配置USB设备,选择USB Device功能,速度为默认全速USB设备12MHZ。
使能USB_DEVICE库,选择Virtual Port Com (虚拟串口,VPC),使用默认配置。
配置USB FS的时钟为48MHz。
然后生成工程。
3.2 虚拟串口软件实现
数据收发的接口在usbd_cdc_if.c文件下。
/**
* [url=home.php?mod=space&uid=159083]@brief[/url] Data received over USB OUT endpoint are sent over CDC interface
* through this function.
*
* @note
* This function will issue a NAK packet on any OUT packet received on
* USB endpoint until exiting this function. If you exit this function
* before transfer is complete on CDC interface (ie. using DMA controller)
* it will result in receiving more data while previous ones are still
* not sent.
*
* @param Buf: Buffer of data to be received
* @param Len: Number of data received (in bytes)
* @retval Result of the operation: USBD_OK if all operations are OK else USBD_FAIL
*/
static int8_t CDC_Receive_FS(uint8_t* Buf, uint32_t *Len)
{
/* USER CODE BEGIN 6 */
USBD_CDC_SetRxBuffer(&hUsbDeviceFS, &Buf[0]);
USBD_CDC_ReceivePacket(&hUsbDeviceFS);
return (USBD_OK);
/* USER CODE END 6 */
}
/**
* @brief CDC_Transmit_FS
* Data to send over USB IN endpoint are sent over CDC interface
* through this function.
* @note
*
*
* @param Buf: Buffer of data to be sent
* @param Len: Number of data to be sent (in bytes)
* @retval USBD_OK if all operations are OK else USBD_FAIL or USBD_BUSY
*/
uint8_t CDC_Transmit_FS(uint8_t* Buf, uint16_t Len)
{
uint8_t result = USBD_OK;
/* USER CODE BEGIN 7 */
USBD_CDC_HandleTypeDef *hcdc = (USBD_CDC_HandleTypeDef*)hUsbDeviceFS.pClassData;
if (hcdc->TxState != 0){
return USBD_BUSY;
}
USBD_CDC_SetTxBuffer(&hUsbDeviceFS, Buf, Len);
result = USBD_CDC_TransmitPacket(&hUsbDeviceFS);
/* USER CODE END 7 */
return result;
}
打印输出
当然也可以把USB作为类似于uart的printf来输出当前需要的log信息。我们只需要把这个函数改就下可以使用USB,VCP来打印输出信息。
int fputc(int ch, FILE *f)
{
while(CDC_Transmit_FS((uint8_t *)&ch, 1) == USBD_BUSY);
return ch;
}
主函数代码如下:
/**
* @brief The application entry point.
* @retval int
*/
int main(void)
{
/* USER CODE BEGIN 1 */
/* USER CODE END 1 */
/* MPU Configuration--------------------------------------------------------*/
MPU_Config();
/* MCU Configuration--------------------------------------------------------*/
/* Reset of all peripherals, Initializes the Flash interface and the Systick. */
HAL_Init();
/* USER CODE BEGIN Init */
/* USER CODE END Init */
/* Configure the system clock */
SystemClock_Config();
/* USER CODE BEGIN SysInit */
/* USER CODE END SysInit */
/* Initialize all configured peripherals */
MX_GPIO_Init();
MX_UART4_Init();
MX_USB_DEVICE_Init();
/* USER CODE BEGIN 2 */
HAL_UART_Receive_IT(&huart4, (uint8_t *)&RxBuffer, 1);
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
HAL_GPIO_TogglePin(LED1_GPIO_Port, LED1_Pin);
/* Insert delay 200 ms */
HAL_Delay(200);
HAL_GPIO_TogglePin(LED2_GPIO_Port, LED2_Pin);
/* Insert delay 200 ms */
HAL_Delay(200);
HAL_GPIO_TogglePin(LED3_GPIO_Port, LED3_Pin);
/* Insert delay 200 ms */
HAL_Delay(200);
HAL_GPIO_TogglePin(LED4_GPIO_Port, LED4_Pin);
/* Insert delay 200 ms */
HAL_Delay(200);
printf("USB CDC, %s \r\n", UserRxBufferFS);
memset(UserRxBufferFS, 0, APP_RX_DATA_SIZE);
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
}
/* USER CODE END 3 */
}
3.3 实验现象
将USB插入电脑,在电脑设备管理器中将显示新的串口设备。如果没有安装VPC驱动需要先安装。
查看USB的硬件信息。
上面的VID和PID可以在文件usbd_desc.c中找到。
使用串口助手接上设备,即可打印如下信息。
发送数据后,虚拟串口则将接收的数据打印处理。