0%

STM32使用USB虚拟串口

使用cubeide配置usb虚拟串口

工程配置

新建一个stm32工程,配置好时钟,其中USB配置48MHz
img

修改堆空间大小,如果太小会导致无法识别usb设备
img

使能USB资源,选择模式配置为Device Only
img

Middleware配置选择虚拟串口
img

以上配置完成以后生成代码

软件配置

解决不同版本固件库导致的无法连接

修改CDC_Control_FS函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
USBD_CDC_LineCodingTypeDef linecoding =
{
115200, /* baud rate*/
0x01, /* stop bits-1*/
0x00, /* parity - none*/
0x08 /* nb. of bits 8*/
};

static int8_t CDC_Control_FS(uint8_t cmd, uint8_t* pbuf, uint16_t length)
{
/* USER CODE BEGIN 5 */
switch(cmd)
{
case CDC_SEND_ENCAPSULATED_COMMAND:

break;

case CDC_GET_ENCAPSULATED_RESPONSE:

break;

case CDC_SET_COMM_FEATURE:

break;

case CDC_GET_COMM_FEATURE:

break;

case CDC_CLEAR_COMM_FEATURE:

break;

/*******************************************************************************/
/* Line Coding Structure */
/*-----------------------------------------------------------------------------*/
/* Offset | Field | Size | Value | Description */
/* 0 | dwDTERate | 4 | Number |Data terminal rate, in bits per second*/
/* 4 | bCharFormat | 1 | Number | Stop bits */
/* 0 - 1 Stop bit */
/* 1 - 1.5 Stop bits */
/* 2 - 2 Stop bits */
/* 5 | bParityType | 1 | Number | Parity */
/* 0 - None */
/* 1 - Odd */
/* 2 - Even */
/* 3 - Mark */
/* 4 - Space */
/* 6 | bDataBits | 1 | Number Data bits (5, 6, 7, 8 or 16). */
/*******************************************************************************/
case CDC_SET_LINE_CODING:
linecoding.bitrate = (uint32_t)(pbuf[0] | (pbuf[1] << 8) |\
(pbuf[2] << 16) | (pbuf[3] << 24));
linecoding.format = pbuf[4];
linecoding.paritytype = pbuf[5];
linecoding.datatype = pbuf[6];
break;

case CDC_GET_LINE_CODING:
pbuf[0] = (uint8_t)(linecoding.bitrate);
pbuf[1] = (uint8_t)(linecoding.bitrate >> 8);
pbuf[2] = (uint8_t)(linecoding.bitrate >> 16);
pbuf[3] = (uint8_t)(linecoding.bitrate >> 24);
pbuf[4] = linecoding.format;
pbuf[5] = linecoding.paritytype;
pbuf[6] = linecoding.datatype;
break;

case CDC_SET_CONTROL_LINE_STATE:

break;

case CDC_SEND_BREAK:

break;

default:
break;
}

return (USBD_OK);
/* USER CODE END 5 */
}

发送数据

发送数据只要调用函数即可,比较简单,需要注意的是长度必须是32bit对齐,如果数据少了会强制补齐

1
CDC_Transmit_FS(UserTxBufferFS, length);

格式化输出

在usbd_cdc_if.c添加格式化输出函数,最大输出长度可配置

1
2
3
4
5
6
7
8
9
10
11
12
#include <stdarg.h>

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);
}

接收数据

单次接收的最大数据量为64byte

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
static int8_t CDC_Receive_FS(uint8_t* Buf, uint32_t *Len)
{
/* USER CODE BEGIN 6 */


__disable_irq();
for( uint32_t i = 0; i < *Len; i ++ ){
rxData[rxLen+i] = Buf[i];
}
rxLen += *Len;
__enable_irq();

USBD_CDC_SetRxBuffer(&hUsbDeviceFS, &Buf[0]);
USBD_CDC_ReceivePacket(&hUsbDeviceFS);
//CDC_Transmit_FS( Buf, *Len );
return (USBD_OK);
/* USER CODE END 6 */
}