STM32F103 USB实现虚拟串口

STM32F103 USB实现虚拟串口

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

实验环境

STM32F103C6T6A最小系统板, CubeIDE 1.10.1, ST-LINK;STM32F103 USB实现虚拟串口_第1张图片

实验目的

实现USB的串口数据传输;

操作步骤

  1. cubeIDE建立工程并生成代码。
  2. 设置晶振RCCSTM32F103 USB实现虚拟串口_第2张图片
  3. 设置SYS, 调试方式STM32F103 USB实现虚拟串口_第3张图片
  4. 设置USB,激活USBSTM32F103 USB实现虚拟串口_第4张图片
  5. 设置Middleware, USB vitrual port, STM32F103 USB实现虚拟串口_第5张图片
  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文件 STM32F103 USB实现虚拟串口_第6张图片
/* 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

修改发送函数代码

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 
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. 修改堆栈和堆;STM32F103 USB实现虚拟串口_第7张图片

11.修改编译优化STM32F103 USB实现虚拟串口_第8张图片

设置编译优化: 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.使用串口工具,发送接收数据正常。
STM32F103 USB实现虚拟串口_第9张图片
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);
}

参考链接

你可能感兴趣的:(stm32,单片机,嵌入式硬件)