1、配置时钟
2、开启USB
3、开启USB设备:虚拟串口
4、生成工程
5、修改代码实现回环收发数据测试
在usbd_cdc_if.c文件中新定义一个结构体:
- USBD_CDC_LineCodingTypeDef USBD_CDC_LineCoding =
- {
- 115200, // 默认波特率
- 0X00, // 1位停止位
- 0X00, // 无奇偶校
- 0X08, // 无流控,8bit数据位
- };
复制代码
找到CDC_Control_FS函数,找到CDC_SET_LINE_CODING和CDC_GET_LINE_CODING分支,添加以下代码:
(CDC_SET_LINE_CODING:你在用串口助手选择波特率时候,STM32就会调用这个分支进行修改USB波特率)
(CDC_GET_LINE_CODING:获取STM32的USB波特率)
- case CDC_SET_LINE_CODING:
- USBD_CDC_LineCoding.bitrate = (pbuf[3] << 24) | (pbuf[2] << 16) | (pbuf[1] << 8) | pbuf[0];
- USBD_CDC_LineCoding.format = pbuf[4];
- USBD_CDC_LineCoding.paritytype = pbuf[5];
- USBD_CDC_LineCoding.datatype = pbuf[6];
- break;
- case CDC_GET_LINE_CODING:
- pbuf[0] = (uint8_t)(USBD_CDC_LineCoding.bitrate);
- pbuf[1] = (uint8_t)(USBD_CDC_LineCoding.bitrate >> 8);
- pbuf[2] = (uint8_t)(USBD_CDC_LineCoding.bitrate >> 16);
- pbuf[3] = (uint8_t)(USBD_CDC_LineCoding.bitrate >> 24);
- pbuf[4] = USBD_CDC_LineCoding.format;
- pbuf[5] = USBD_CDC_LineCoding.paritytype;
- pbuf[6] = USBD_CDC_LineCoding.datatype;
- break;
复制代码
如下图所示:
找到CDC_Receive_FS函数,这个函数如果USB虚拟串口数据收到就会被调用,我们在这个函数中将收到的数据在发回去,只需要添加CDC_Transmit_FS(Buf, *Len);这一句即可,如下图:
然后编译工程并下载,接上USB之后,设备管理器COM出现一个新的端口:
我们使用串口调试助手给它发数据:
6、实现USB转串口功能
发数据流程:串口调试助手发送数据->STM32的USB数据接收->STM32转发到串口3
收数据流程:STM32的串口3收到数据->转发到USB->STM32的USB发送到串口调试助手
第一步先在这里加入串口3的初始化操作:
贴一下串口3的初始化代码,这里我用到了队列,因为实际测试发现串口3接收数据量比较大的话,那么转发到USB虚拟串口的时候会丢数据,所以这里采用了缓存队列,当串口接收到的数据到达一定数据量之后才做一次转发到USB的操作,并且开启了空闲中断,作用是转发最后一包数据:
关于队列的使用可以查看我的另一篇博客:C/C++语言实现的一个缓存队列
- /*
- * myusart.c
- *
- * Created on: Mar 22, 2021
- * Author: hello
- */
- #include "myusart.h"
- #include "myqueue.h"
- // 队列大小,定义为USB_CDC的发送包大小
- #define QUEUE_SIZE APP_TX_DATA_SIZE
- // 队列数据空间。请使用宏QALIGN4,目的是为了根据队列大小计算实际需要的队列存储空间大小并对齐4字节
- uint8_t QueueBuffer[QALIGN4(QUEUE_SIZE)];
- // 队列句柄
- Queue Uart3QueueHandle = {0};
- #define UART3_QUEUE_Handle (&Uart3QueueHandle)
- // 串口转发到USB的缓冲,定义为USB包的一半大小
- static uint8_t buffer[APP_RX_DATA_SIZE >> 1];
- void UART3_Init(const USBD_CDC_LineCodingTypeDef *USBD_CDC_LineCoding)
- {
- __HAL_UART_DISABLE_IT(&huart3, UART_IT_RXNE);
- __HAL_UART_DISABLE_IT(&huart3, UART_IT_IDLE);
- HAL_UART_DeInit(&huart3);
- huart3.Instance = USART3;
- huart3.Init.BaudRate = USBD_CDC_LineCoding->bitrate;
- huart3.Init.HwFlowCtl = UART_HWCONTROL_NONE;
- huart3.Init.Mode = UART_MODE_TX_RX;
- huart3.Init.OverSampling = UART_OVERSAMPLING_16;
- switch (USBD_CDC_LineCoding->paritytype)
- {
- case 0:
- huart3.Init.Parity = UART_PARITY_NONE;
- break;
- case 1:
- huart3.Init.Parity = UART_PARITY_ODD;
- break;
- case 2:
- huart3.Init.Parity = UART_PARITY_EVEN;
- break;
- default:
- huart3.Init.Parity = UART_PARITY_NONE;
- break;
- }
- switch (USBD_CDC_LineCoding->datatype)
- {
- case 0x07:
- huart3.Init.WordLength = UART_WORDLENGTH_8B;
- break;
- case 0x08:
- if (huart3.Init.Parity == UART_PARITY_NONE)
- {
- huart3.Init.WordLength = UART_WORDLENGTH_8B;
- }
- else
- {
- huart3.Init.WordLength = UART_WORDLENGTH_9B;
- }
- break;
- default:
- huart3.Init.WordLength = UART_WORDLENGTH_8B;
- break;
- }
- switch (USBD_CDC_LineCoding->format)
- {
- case 0:
- huart3.Init.StopBits = UART_STOPBITS_1;
- break;
- case 2:
- huart3.Init.StopBits = UART_STOPBITS_2;
- break;
- default:
- huart3.Init.StopBits = UART_STOPBITS_1;
- break;
- }
- HAL_UART_Init(&huart3);
- Queue_Init(UART3_QUEUE_Handle, QUEUE_SIZE, QueueBuffer);
- __HAL_UART_ENABLE_IT(&huart3, UART_IT_RXNE);
- __HAL_UART_ENABLE_IT(&huart3, UART_IT_IDLE);
- }
- void USART3_IRQHandler(void)
- {
- static uint32_t nsent = 0;
- static uint8_t dat = 0;
- if (__HAL_UART_GET_FLAG(&huart3, UART_FLAG_RXNE) != RESET)
- {
- __HAL_UART_CLEAR_FLAG(&huart3, UART_FLAG_RXNE);
- dat = huart3.Instance->DR & 0XFF;
- Queue_PutByte(UART3_QUEUE_Handle, dat); // 入队一个字节的数据
- if (Queue_GetUsed(UART3_QUEUE_Handle) >= sizeof(buffer))
- {
- Queue_Read(UART3_QUEUE_Handle, buffer, sizeof(buffer));
- CDC_Transmit_FS(buffer, sizeof(buffer)); // 转发到USB
- }
- }
- if (__HAL_UART_GET_FLAG(&huart3, UART_FLAG_IDLE) != RESET)
- {
- nsent = Queue_GetUsed(UART3_QUEUE_Handle);
- if (nsent != 0)
- {
- Queue_Read(UART3_QUEUE_Handle, buffer, nsent);
- CDC_Transmit_FS(buffer, nsent); // 转发到USB
- }
- __HAL_UART_CLEAR_IDLEFLAG(&huart3);
- }
- }
- void UART3_SendData(const void *buf, uint32_t len)
- {
- const uint8_t *p = (const uint8_t*) buf;
- while (len--)
- {
- while (__HAL_UART_GET_FLAG(&huart3, UART_FLAG_TXE) != SET);
- huart3.Instance->DR = (uint8_t) (*p++ & 0XFF);
- while (__HAL_UART_GET_FLAG(&huart3, UART_FLAG_TC) != SET);
- }
- }
- //#ifdef __GNUC__
- //#define PUTCHAR_PROTOTYPE int __io_putchar(int ch)
- //#else
- //#define PUTCHAR_PROTOTYPE int fputc(int ch, FILE *f)
- //#endif
- //PUTCHAR_PROTOTYPE
- //{
- // while (__HAL_UART_GET_FLAG(&huart3, UART_FLAG_TXE) != SET);
- // huart3.Instance->DR = (uint8_t) (ch & 0XFF);
- // while (__HAL_UART_GET_FLAG(&huart3, UART_FLAG_TC) != SET);
- // return ch;
- //}
复制代码
然后在添加USB转发到串口的操作:
这样就实现了一个类似于USB转TTL模块的功能!
|