• 野火指南者(STM32F103VET6)应用:实现USB虚拟串口(CDC_VPC)


    MCU:STM32F103VET6

    开发环境:STM32CubeMX+MDK5

     

    实现USB的虚拟串口不需要去理解USB的底层驱动,只需要STM32CubeMX去配置生成工程即可。在野火的指南者中,是没有这一类的视频和示例的,博主使用这款开发板实现USB虚拟串口。

    首先需要打开STM32CubeMX工具。输入开发板MCU对应型号,找到开发板对应封装的MCU型号,双击打开(图中第三)。

     

    此时,双击完后会关闭此界面,然后打开一个新界面。

     

    然后,我们开始基本配置。

     

    现在我们选择一个LED作为系统LED,该步骤可以忽略,只是本人喜欢这样子。以硬件原理图的绿灯为例子。

     

    基本配置除了时钟树外,基本上已经配置好了。

    现在来配置USB_Device。STM32F1系列USB只支持USB_Device。

     

    选中USB类型后,还需要细化其中的类型。

     

    一切配置都是基于硬件原理图的。硬件配置除常规配置外,还是需要看硬件原理图的。在硬件原理图中,可以看到只有PD6拉低时,USB才使能。(针对野火指南者开发板)

     

    现在配置时钟树

     

    配置完成,完善工程,生成工程。

    到此,STM32CubeMX工具的使用结束!可以发现在桌面已经生成了USB_VPC工程。

     

    USB虚拟串口还需要装驱动才能被是识别到,在Win7、Win8机型PC中需要到ST官网下载。win10及以上机型在本地已有驱动,无需安装。

    使用MDK5打开USB_VPC工程打开。点击魔法棒,勾选微库。选择对应的下载器,勾选下载完复位允许。USB线一端接开发板USB_Device,一端接PC。

     

    现在可以开始实验了,实现VPC的发送与回传,并重定向printf函数。

    在此之前,简单描述一下生成的USB文件以及重要函数。

    然后再插播一条,看帖子说是,刚下载完程序时,是识别不出端口的。需要在上电的情况下从PC那拔插一次USB线。然后可以使用一个函数解决这个问题。可以在gpio.c中写入函数,然后记得在头文件声明。使用要在MX_USB_DEVICE_Iint()之前。

    (我没遇到这个问题,但是我还是放到工程了,但是我没用这函数。)

    复制代码
     1 /* USER CODE BEGIN 2 */
     2 /*USB 重新枚举函数*/
     3 void USB_Reset(void)
     4 {
     5     GPIO_InitTypeDef GPIO_InitStruct = {0};
     6     
     7     __HAL_RCC_GPIOA_CLK_ENABLE();
     8     
     9     GPIO_InitStruct.Pin = GPIO_PIN_12;
    10     GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
    11     GPIO_InitStruct.Pull = GPIO_NOPULL;
    12     GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
    13     HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
    14     
    15     HAL_GPIO_WritePin(GPIOA,GPIO_PIN_12,GPIO_PIN_RESET);
    16     HAL_Delay(100);
    17     HAL_GPIO_WritePin(GPIOA,GPIO_PIN_12,GPIO_PIN_SET);
    18 }
    19 /* USER CODE END 2 */
    复制代码

     

    实验环节:发送与回传

    在main.c中(截取片段,修改部分)

    复制代码
     1 /* Private includes ----------------------------------------------------------*/
     2 /* USER CODE BEGIN Includes */
     3 #include "usbd_cdc_if.h"
     4 /* USER CODE END Includes */
     5 
     6 /* Private typedef -----------------------------------------------------------*/
     7 /* USER CODE BEGIN PTD */
     8 
     9 /* USER CODE END PTD */
    10 
    11 /* Private define ------------------------------------------------------------*/
    12 /* USER CODE BEGIN PD */
    13 /* USER CODE END PD */
    14 
    15 /* Private macro -------------------------------------------------------------*/
    16 /* USER CODE BEGIN PM */
    17 
    18 /* USER CODE END PM */
    19 
    20 /* Private variables ---------------------------------------------------------*/
    21 
    22 /* USER CODE BEGIN PV */
    23 
    24 /* USER CODE END PV */
    25 
    26 /* Private function prototypes -----------------------------------------------*/
    27 void SystemClock_Config(void);
    28 /* USER CODE BEGIN PFP */
    29 
    30 /* USER CODE END PFP */
    31 
    32 /* Private user code ---------------------------------------------------------*/
    33 /* USER CODE BEGIN 0 */
    34 
    35 /* USER CODE END 0 */
    36 
    37 /**
    38   * @brief  The application entry point.
    39   * @retval int
    40   */
    41 int main(void)
    42 {
    43   /* USER CODE BEGIN 1 */
    44     char str[] = "Hello World!\r\n";
    45   /* USER CODE END 1 */
    46 
    47   /* MCU Configuration--------------------------------------------------------*/
    48 
    49   /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
    50   HAL_Init();
    51 
    52   /* USER CODE BEGIN Init */
    53 
    54   /* USER CODE END Init */
    55 
    56   /* Configure the system clock */
    57   SystemClock_Config();
    58 
    59   /* USER CODE BEGIN SysInit */
    60 //    USB_Reset();
    61   /* USER CODE END SysInit */
    62 
    63   /* Initialize all configured peripherals */
    64   MX_GPIO_Init();
    65   MX_USB_DEVICE_Init();
    66   /* USER CODE BEGIN 2 */
    67 
    68   /* USER CODE END 2 */
    69 
    70   /* Infinite loop */
    71   /* USER CODE BEGIN WHILE */
    72   while (1)
    73   {
    74     /* USER CODE END WHILE */
    75     CDC_Transmit_FS((uint8_t*)str, 14);
    76     HAL_Delay(2000);
    77     /* USER CODE BEGIN 3 */
    78   }
    79   /* USER CODE END 3 */
    80 }
    复制代码

    在usbd_cdc_if.c中(截取片段,修改部分)

    复制代码
     1 /**
     2   * @brief  Data received over USB OUT endpoint are sent over CDC interface
     3   *         through this function.
     4   *
     5   *         @note
     6   *         This function will issue a NAK packet on any OUT packet received on
     7   *         USB endpoint until exiting this function. If you exit this function
     8   *         before transfer is complete on CDC interface (ie. using DMA controller)
     9   *         it will result in receiving more data while previous ones are still
    10   *         not sent.
    11   *
    12   * @param  Buf: Buffer of data to be received
    13   * @param  Len: Number of data received (in bytes)
    14   * @retval Result of the operation: USBD_OK if all operations are OK else USBD_FAIL
    15   */
    16 static int8_t CDC_Receive_FS(uint8_t* Buf, uint32_t *Len)
    17 {
    18   /* USER CODE BEGIN 6 */
    19     CDC_Transmit_FS(Buf, *Len);
    20     
    21   USBD_CDC_SetRxBuffer(&hUsbDeviceFS, &Buf[0]);
    22   USBD_CDC_ReceivePacket(&hUsbDeviceFS);
    23   return (USBD_OK);
    24   /* USER CODE END 6 */
    25 }
    复制代码

    实验结果(波特率随意选)

     

     

     实验环节:打印重定向

     在usbd_cdc_if.c中(截取片段,修改部分),声明在usbd_cdc_if.h文件。

    复制代码
     1 /* USER CODE BEGIN PRIVATE_FUNCTIONS_IMPLEMENTATION */
     2 #include "stdarg.h"
     3 #include "stdio.h"
     4 
     5 uint8_t usbtemp[64];
     6 void usbvcom_printf(const char *format,...)
     7 {
     8     uint16_t     len;
     9     va_list     args;
    10     
    11     va_start(args, format);
    12     len = vsnprintf((char *)usbtemp, sizeof(usbtemp)+1, (char *)format, args);
    13     va_end(args);
    14     
    15     CDC_Transmit_HS(usbtemp, len);
    16 }
    17 
    18 /* USER CODE END PRIVATE_FUNCTIONS_IMPLEMENTATION */
    复制代码

    然后就可以像printf那样使用了,实测过是正常的!

     

    时代越来越好,开发效率越来越高,希望能帮助到你!!!

    还有就是,开源万岁。 

  • 相关阅读:
    移动App安全检测的必要性,app安全测试报告的编写注意事项
    Vue2路由的详细讲解
    iPhone升级iOS17出现无法连接互联网的错误提示怎么办?
    PointNet 和 PointNet++ 作者讲座学习笔记
    C++ 纠错题总结2
    艾美捷Abnova NEUROD6单克隆抗体(M17)说明书
    Git上传新项目
    【Linux】线程互斥
    Docker 命令大全
    Jmeter---非GUI命令行的执行生成报告、使用ant插件执行接口测试脚本生成报告
  • 原文地址:https://www.cnblogs.com/couvrir/p/17461078.html