STM32CubeMX | 快速实现STM32 USB虚拟串口功能(回环测试、USB转TTL的功能)

STM32快速实现USB虚拟串口+回环测试+USB转TTL的功能


环境:

  • STM32F103RB
  • STM32CUBEIDE1.5.1

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_CODINGCDC_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模块的功能!


ends…

STM32F103是一款基于ARM Cortex-M3内核的微控制器,它可以通过USB接口实现虚拟串口功能虚拟串口是一种软件模拟的串口,它可以通过USB接口模拟出一个标准的串口,从而实现串口通信的功能。在STM32F103中,可以通过USB接口实现虚拟串口功能,具体步骤如下: 1. 配置USB接口:在STM32F103中,可以使用USB接口实现虚拟串口功能,需要先配置USB接口。可以使用STM32CubeMX工具进行配置,具体配置方法可以参考ST官方文档。 2. 实现USB虚拟串口驱动代码:可以参考正点原子提供的USB虚拟串口实现基础上进行改造,实现USB虚拟串口驱动代码。具体实现方法可以参考正点原子提供的相关教程。 3. 枚举成CH340设备:在Windows系统中,需要安装CH340的驱动才能使用USB虚拟串口。可以将STM32F103枚举成CH340设备,然后在Windows系统中安装CH340的驱动,就可以使用USB虚拟串口了。 下面是修改main函数的while循环的代码: ```c /* USER CODE BEGIN WHILE */ while (1) { /* USER CODE END WHILE */ /* USER CODE BEGIN 3 */ //USB模拟串口的查寻接收处理 if(USB_RX_STA!=0)//判断是否有 { //USB_printf("USB_RX:");//向USB模拟串口发字符串 CDC_Transmit_FS(USB_RX_BUF,USB_RX_STA);//USB串口:将接收的数据发回给电脑端 //USB_printf("\r\n");//向USB模拟串口发(回车) USB_RX_STA=0;//数据标志位清0 memset(USB_RX_BUF,0,sizeof(USB_RX_BUF));//USB串口数据寄存器清0 } } /* USER CODE END 3 */ ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

觉皇嵌入式

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值