STM32F103 USB实现虚拟串口

STM32F103 USB实现虚拟串口

最近买了一个STM32F103C8T6最小核心板,使用CubeIDE无法识别该芯片,发现该芯片的flash是128Kbytes,ST的标准库是64Kbytes,奇怪啊!也许是国产替代的,国产化太先进了,导致原厂落后了,不认识先进的东西了。
只好又在某宝买了5.5元的STM32F103C6T6最小核心板,CubeID环境下正常工作和调试。感谢万能的某宝!最便宜的东西才能工作正常,好无语啊!

实验环境

STM32F103C6T6A最小系统板, CubeIDE 1.10.1, ST-LINK;在这里插入图片描述

实验目的

实现USB的串口数据传输;

操作步骤

  1. cubeIDE建立工程并生成代码。
  2. 设置晶振RCC在这里插入图片描述
  3. 设置SYS, 调试方式在这里插入图片描述
  4. 设置USB,激活USB在这里插入图片描述
  5. 设置Middleware, USB vitrual port, 在这里插入图片描述
  6. 保存并generate code,进行编译一遍,通常是不能编译通过的。
  7. 修改usb_cdc_if.h 文件
/* USER CODE BEGIN INCLUDE */
 #define USB_REC_LEN   256 //定义USB串口接收字节数
 extern uint8_t USB_RX_BUF[USB_REC_LEN];//接收缓冲
 extern uint16_t USB_RX_STA;//接收标记
 /* USER CODE END INCLUDE */`
  1. 修改usb_cdc_if.c文件 在这里插入图片描述
/* USER CODE BEGIN PV */
/* Private variables ---------------------------------------------------------*/
 uint8_t USB_RX_BUF[USB_REC_LEN];//接收缓冲,最大USB_REC_LEN个字节.
 uint16_t USB_RX_STA=0;//接收状态标记(接收到的有效字节数量)
/* USER CODE END PV */

修改接收函数代码

static int8_t CDC_Receive_FS(uint8_t* Buf, uint32_t *Len)
{
	if(*Len<USB_REC_LEN)//判断收到数据量是否小于寄存器上限
	{
	   uint16_t i;
	   USB_RX_STA = *Len;//将数据量值放入标志位
	   for(i=0;i<*Len;i++)//循环
		   USB_RX_BUF[i] = Buf[i];//将数据内容放入数据寄存器
	}
  USBD_CDC_SetRxBuffer(&hUsbDeviceFS, &Buf[0]);  //将接收数组buff清空
  USBD_CDC_ReceivePacket(&hUsbDeviceFS);  //再次虚拟串口接收
  return (USBD_OK);
  /* USER CODE END 6 */
}

修改发送函数代码

uint8_t CDC_Transmit_FS(uint8_t* Buf, uint16_t Len)
{
  uint8_t result = USBD_OK;
  /* USER CODE BEGIN 7 */
  uint32_t TimeStart = HAL_GetTick();
  USBD_CDC_HandleTypeDef *hcdc =  (USBD_CDC_HandleTypeDef*)hUsbDeviceFS.pClassData;
  if(hcdc == 0) return  USBD_FAIL;  //避免未插入USB设备,出现死机的情况。
  //if (hcdc->TxState != 0) return  USBD_BUSY;
  while(hcdc->TxState)
  {
     if(HAL_GetTick()-TimeStart > 10)
    	 return USBD_BUSY;
     else
    	 break;
  }
  USBD_CDC_SetTxBuffer(&hUsbDeviceFS, Buf,  Len);
  result =  USBD_CDC_TransmitPacket(&hUsbDeviceFS);
  TimeStart = HAL_GetTick();
  while(hcdc->TxState)
	{
		if(HAL_GetTick()-TimeStart > 10)
		return USBD_BUSY;
	}
  /* USER CODE END 7 */
  return result;
}

添加输出函数

#include <stdarg.h>
void USB_printf(const char *format, ...)//USB模拟串口的打印函数
{
    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);
}
  1. 修改main.c
    添加include文件
	/* USER CODE BEGIN Includes */
#include "../../USB_DEVICE/App/usbd_cdc_if.h"
    /* USER CODE END Includes */ 

修改main函数的while循环

  /* 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 */
  1. 修改堆栈和堆;在这里插入图片描述

11.修改编译优化在这里插入图片描述

设置编译优化: Properties for F10****/ C/C++ Build / Settings / MCU GCC Compiler / Optimization \ Optimization level = “Optimize for size(-Os)”
否则会出现错误如下:

\tools\arm-none-eabi\bin\ld.exe: F103C6T6Atest.elf section .text' will not fit in region FLASH’ \tools\arm-none-eabi\bin\ld.exe: region
`FLASH’ overflowed by 1656 bytes collect2.exe: error: ld returned 1
exit status make: *** [makefile:68: F103C6T6Atest.elf] Error 1 “make
-j8 all” terminated with exit code 2. Build might be incomplete.

运行测试

1.设备管理器可以看到串口;
2.使用串口工具,发送接收数据正常。
在这里插入图片描述
CubeIDE1.10.1 环境下的源代码:https://download.csdn.net/download/qq_23313467/87824117

注意事项
tip1:STM32F103C6T6的存储容量比较小,实现USB的虚拟串口基本上用完了内存和flash,如果再添加别的复杂功能,估计存储就不够了。参看了一下生成的hex文件,已经达到38k了!

tip2:程序重启后,需要硬件拔插一下USB接口,PC才能使用串口。加入下面代码可以避免这种情况。

/*USB 重新枚举函数
 * 解决问题:每次下载完程序后都要重新拔插一次USB PC才能识别串口,这是由于芯片在下载完程序后没有重新枚举所导致的。需要在MCU上电后对USB进行关闭,PC才能重新枚举识别。
 * 解决方法为将USB DP(PA12)引脚拉低一段时间后即可*/
void USB_Reset(void)
{
  	GPIO_InitTypeDef GPIO_InitStruct = {0};
	__HAL_RCC_GPIOA_CLK_ENABLE();
	GPIO_InitStruct.Pin = GPIO_PIN_12;
	GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
	GPIO_InitStruct.Pull = GPIO_NOPULL;
	GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
	HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
	HAL_GPIO_WritePin(GPIOA,GPIO_PIN_12,GPIO_PIN_RESET);
	HAL_Delay(100);
	HAL_GPIO_WritePin(GPIOA,GPIO_PIN_12,GPIO_PIN_SET);
}

参考链接

  • 16
    点赞
  • 48
    收藏
    觉得还不错? 一键收藏
  • 9
    评论
实现STM32F103USB虚拟串口功能,可以按照以下步骤进行操作: 1. 在CubeIDE中创建一个新的工程,并生成代码。 2. 在RCC设置中选择合适的晶振频率,并将调试方式设置为USB。 3. 激活USB设置,在Middleware中选择USB virtual port,并保存并生成代码。 4. 修改usb_cdc_if.h文件,定义USB串口接收缓冲区的长度和接收标志位。例如,可以定义USB_REC_LEN为256,并声明一个长度为USB_REC_LEN的uint8_t数组USB_RX_BUF作为接收缓冲区,同时声明一个uint16_t变量USB_RX_STA作为接收标志位。 5. 修改usb_cdc_if.c文件,将USB_RX_BUF和USB_RX_STA定义为全局变量,确保在整个程序中可以使用。 6. 实现数据发送函数send_data_to_usb,该函数接收一个包含数据的缓冲区指针和数据的数量。在函数中,使用一个循环将数据逐个存储到USB_RX_BUF中,并更新buffer_tail_position指针。如果buffer_tail_position超过了缓冲区的大小,将其重置为0。最后,调用usb_send_data函数将数据发送到USB接口。 这样,你就可以在主函数的while循环中添加相应的逻辑来处理USB串口的数据接收和发送了。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* [STM32F103 USB实现虚拟串口](https://blog.csdn.net/qq_23313467/article/details/130884586)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v92^chatsearchT3_1"}}] [.reference_item style="max-width: 50%"] - *3* [stm32f103 usb虚拟成pc端的串口](https://blog.csdn.net/zailushangha/article/details/8333722)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v92^chatsearchT3_1"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 9
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值