• 【正点原子STM32连载】第五十八章 USB虚拟串口(Slave)实验 摘自【正点原子】MiniPro STM32H750 开发指南_V1.1


    1)实验平台:正点原子MiniPro H750开发板
    2)平台购买地址:https://detail.tmall.com/item.htm?id=677017430560
    3)全套实验源码+手册+视频下载地址:http://www.openedv.com/thread-336836-1-1.html
    4)对正点原子STM32感兴趣的同学可以加群讨论:879133275

    第五十八章 USB虚拟串口(Slave)实验

    本章,我们将向大家介绍如何利用USB在开发板实现一个USB虚拟串口,通过USB与电脑数据数据交互。
    本章分为如下几个小节:
    58.1 USB虚拟串口简介
    58.2 硬件设计
    58.3 程序设计
    58.4 下载验证

    58.1 USB虚拟串口简介

    USB虚拟串口,简称VCP,是Virtual COM Port的简写,它是利用USB的CDC类来实现的一种通信接口。
    我们可以利用STM32自带的USB功能,来实现一个USB虚拟串口,从而通过USB,实现电脑与STM32的数据互传。上位机无需编写专门的USB程序,只需要一个串口调试助手即可调试,非常实用。
    同上一章一样,我们直接移植官方的USB VCP例程,官方例程路径::8,STM32参考资料1,STM32CubeH7固件包 STM32Cube_FW_H7_V1.6.0ProjectsSTM32H743I-EVALApplicationsUSB_DeviceCDC_Standalone,该例程采用USB CDC类来实现,利用STM32的USB接口,实现一个USB转串口的功能。

    58.2 硬件设计

    1. 例程功能
      本实验利用STM32自带的USB功能,连接电脑USB,虚拟出一个USB串口,实现电脑和开发板的数据通信。本例程功能完全同实验5(串口通信实验),只不过串口变成了STM32的USB虚拟串口。当USB连接电脑(USB线插入USB_SLAVE接口),开发板将通过USB和电脑建立连接,并虚拟出一个串口(注意:需要先安装:光盘\6,软件资料\1,软件\STM32 USB虚拟串口驱动\VCP_V1.4.0_Setup.exe这个驱动软件,虚拟串口驱动我们还可以在论坛上下载,链接是:http://www.openedv.com/thread-284178-1-1.html)。
      LED0闪烁,提示程序运行。USB和电脑连接成功后,LED1常亮。
    2. 硬件资源
      1)RGB灯
      RED :LED0 - PB4
      GREEN :LED1 - PE6
      2)串口1(PA9/PA10连接在板载USB转串口芯片CH340上面)
      3)正点原子2.8/3.5/4.3/7/10寸TFTLCD模块(仅限MCU屏,16位8080并口驱动)
      4)USB_SLAVE接口(D-/D+连接在PA11/PA12上)
      58.3 程序设计
      58.3.1 程序流程图
      在这里插入图片描述

    图58.3.1.1 USB虚拟串口(Slave)实验程序流程图
    58.3.2 程序解析
    这里我们只讲解核心代码,详细的源码请大家参考光盘本实验对应源码。
    本实验,在上一个实验的基础上,把不需要的文件从工程中移除,并对照官方VCP例子,将相关文件拷贝到USB文件夹下。然后,添加USB相关代码到工程中,最终得到如图58.3.2.1所示的工程:
    在这里插入图片描述

    图58.3.2.1 USB虚拟串口工程分组
    注意:因为USB驱动库需要用到内存管理,因此我们保留了相关代码(malloc.c)。

    1. USB驱动代码
      可以看到,USB部分代码,同上一个实验的在结构上是一模一样的,只是.c文件稍微有些变化。同样,我们移植需要修改的代码,就是USB_APP里面的这三个.c文件了。
      usbd_conf.c代码,和上一个实验一样,不需要修改,可以直接使用上一个实验的代码。
      usbd_desc.c代码,同上一个实验不一样,上一个实验描述符是USB Audio设备,本实验变成了USB虚拟串口了(CDC),所以直接用ST官方的就行。
      usbd_cdc_interface.c代码,是重点要修改的,首先介绍usbd_cdc_interface.h文件的相关宏定义,具体如下:
    #define USB_USART_REC_LEN       200     /* USB串口接收缓冲区最大字节数 */
    
    /* 轮询周期,最大65ms,最小1ms */
    #define CDC_POLLING_INTERVAL    1       /* 轮询周期,最大65ms,最小1ms */
    
    • 1
    • 2
    • 3
    • 4

    USB_USART_REC_LEN宏定义是用于定义USB串口接收缓冲区最大字节数,这里设置为200。CDC_POLLING_INTERVAL宏定义是用于定义USB发送数据轮询周期,作为delay_ms函数的参数,最大65ms,最小1ms,这里设置为最小值即可。
    下面重点介绍usbd_cdc_interface.c文件,首先是一些结构体变量、数组和变量的定义,具体如下:

    /* USB虚拟串口相关配置参数 */
    USBD_CDC_LineCodingTypeDef LineCoding =
    {
        115200,     /* 波特率 */
        0x00,       /* 停止位,默认1位 */
        0x00,       /* 校验位,默认无 */
        0x08        /* 数据位,默认8位 */
    };
    
    /* usb_printf发送缓冲区, 用于vsprintf */
    uint8_t g_usb_usart_printf_buffer[USB_USART_REC_LEN];
    
    /* USB接收的数据缓冲区,最大USART_REC_LEN个字节,用于USBD_CDC_SetRxBuffer函数 */
    uint8_t g_usb_rx_buffer[USB_USART_REC_LEN];
    
    /* 用类似串口1接收数据的方法,来处理USB虚拟串口接收到的数据 */
    uint8_t g_usb_usart_rx_buffer[USB_USART_REC_LEN];       /* 接收缓冲,最大USART_REC_LEN个字节 */
    
    /* 接收状态
     * bit15   , 接收完成标志
     * bit14   , 接收到0x0d
     * bit13~0 , 接收到的有效字节数目
     */
    uint16_t g_usb_usart_rx_sta=0;  /* 接收状态标记 */
    
    extern USBD_HandleTypeDef USBD_Device;
    static int8_t CDC_Itf_Init(void);
    static int8_t CDC_Itf_DeInit(void);
    static int8_t CDC_Itf_Control(uint8_t cmd, uint8_t *pbuf, uint16_t length);
    static int8_t CDC_Itf_Receive(uint8_t *pbuf, uint32_t *Len);
    
    /* 虚拟串口配置函数(供USB内核调用) */
    USBD_CDC_ItfTypeDef USBD_CDC_fops =
    {
        CDC_Itf_Init,
        CDC_Itf_DeInit,
        CDC_Itf_Control,
        CDC_Itf_Receive
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39

    首先是定义一个USBD_CDC_LineCodingTypeDef结构体类型的变量LineCoding,并赋值。波特率为115200,停止位和校验位都为0,数据位,默认8位。
    g_usb_usart_printf_buffer是发送缓冲区,大小由USB_USART_REC_LEN宏来定义,数组是uint8_t类型,所以数字大小为200字节。
    g_usb_rx_buffer则是USB接收的数据缓冲区,用于USBD_CDC_SetRxBuffer函数,大小也是200字节。
    g_usb_usart_rx_buffer是用做类似串口1接收数据的方法,来处理USB虚拟串口接收到的数据,在cdc_vcp_data_rx函数中被调用,大小也是200字节。
    g_usb_usart_rx_sta变量用于表示接收状态,位15表示接收完成标志,位14表示接收到0x0d,位13~位0表示接收到的有效字节数目。
    最后定义一个USBD_CDC_ItfTypeDef结构体类型的变量USBD_CDC_fops,供USB内核调用,并把四个函数的首地址赋值给其成员。下面会介绍到这几个函数,以及一些其它的函数。
    首先是初始化CDC函数,其定义如下:

    /**
     * @brief       初始化 CDC
     * @param       无
     * @retval      USB状态
     *   @arg       USBD_OK(0)   , 正常;
     *   @arg       USBD_BUSY(1) , 忙;
     *   @arg       USBD_FAIL(2) , 失败;
     */
    static int8_t CDC_Itf_Init(void)
    {
        USBD_CDC_SetRxBuffer(&USBD_Device, g_usb_rx_buffer);
        return USBD_OK;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    CDC_Itf_Init用于初始化VCP,在初始化的时候由USB内核调用,这里我们调用函数:USBD_CDC_SetRxBuffer,设置USB接收数据缓冲区。USB虚拟串口收到的数据,会先缓存在这个buf里面。
    下面介绍的是复位CDC函数,其定义如下:

    /**
     * @brief       复位 CDC
     * @param       无
     * @retval      USB状态
     *   @arg       USBD_OK(0)   , 正常;
     *   @arg       USBD_BUSY(1) , 忙;
     *   @arg       USBD_FAIL(2) , 失败;
     */
    static int8_t CDC_Itf_DeInit(void)
    {
        return USBD_OK;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    CDC_Itf_DeInit用于复位VCP,我们用不到,所以直接返回USBD_OK即可。
    下面介绍的是控制CDC的设置函数,其定义如下:

    /**
     * @brief       控制 CDC 的设置
     * @param       cmd     : 控制命令
     * @param       buf     : 命令数据缓冲区/参数保存缓冲区
     * @param       length  : 数据长度
     * @retval      USB状态
     *   @arg       USBD_OK(0)   , 正常;
     *   @arg       USBD_BUSY(1) , 忙;
     *   @arg       USBD_FAIL(2) , 失败;
     */
    static int8_t CDC_Itf_Control(uint8_t cmd, uint8_t *pbuf, uint16_t length)
    {
        switch (cmd)
        {
            case CDC_SEND_ENCAPSULATED_COMMAND:
                break;
            case CDC_GET_ENCAPSULATED_RESPONSE:
                break;
            case CDC_SET_COMM_FEATURE:
                break;
            case CDC_GET_COMM_FEATURE:
                break;
            case CDC_CLEAR_COMM_FEATURE:
                break;
            case CDC_SET_LINE_CODING:
                LineCoding.bitrate = (uint32_t) (pbuf[0] | (pbuf[1] << 8) |
                                                 (pbuf[2] << 16) | (pbuf[3] << 24));
                LineCoding.format = pbuf[4];
                LineCoding.paritytype = pbuf[5];
                LineCoding.datatype = pbuf[6];
                /* 打印配置参数 */
                printf("linecoding.format:%d\r\n", LineCoding.format);
                printf("linecoding.paritytype:%d\r\n", LineCoding.paritytype);
                printf("linecoding.datatype:%d\r\n", LineCoding.datatype);
                printf("linecoding.bitrate:%d\r\n", LineCoding.bitrate);
                break;
            case CDC_GET_LINE_CODING:
                pbuf[0] = (uint8_t) (LineCoding.bitrate);
                pbuf[1] = (uint8_t) (LineCoding.bitrate >> 8);
                pbuf[2] = (uint8_t) (LineCoding.bitrate >> 16);
                pbuf[3] = (uint8_t) (LineCoding.bitrate >> 24);
                pbuf[4] = LineCoding.format;
                pbuf[5] = LineCoding.paritytype;
                pbuf[6] = LineCoding.datatype;
                break;
            case CDC_SET_CONTROL_LINE_STATE:
                break;
            case CDC_SEND_BREAK:
                break;
            default:
                break;
        }
        return USBD_OK;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    CDC_Itf_Control用于控制VCP的相关参数,根据cmd的不同,执行不同的操作,这里主要用到CDC_SET_LINE_CODING命令,该命令用于设置VCP的相关参数,比如波特率、数据类型(位数)、校验类型(奇偶校验)等,保存在linecoding结构体里面,在需要的时候,应用程序可以读取LineCoding结构体里面的参数,以获得当前VCP的相关信息。
    
    • 1

    下面介绍的是CDC数据接收函数和处理从USB虚拟串口接收到的数据函数,它们的定义如下:

    /**
     * @brief       CDC 数据接收函数
     * @param       buf     : 接收数据缓冲区
     * @param       len     : 接收到的数据长度
     * @retval      USB状态
     *   @arg       USBD_OK(0)   , 正常;
     *   @arg       USBD_BUSY(1) , 忙;
     *   @arg       USBD_FAIL(2) , 失败;
     */
    static int8_t CDC_Itf_Receive(uint8_t *buf, uint32_t *len)
    {
        SCB_CleanDCache_by_Addr((uint32_t *)buf, *len);
        USBD_CDC_ReceivePacket(&USBD_Device);
        cdc_vcp_data_rx(buf, *len);
        return USBD_OK;
    }
    
    /**
     * @brief       处理从 USB 虚拟串口接收到的数据
     * @param       buf     : 接收数据缓冲区
     * @param       len     : 接收到的数据长度
     * @retval      无
     */
    void cdc_vcp_data_rx (uint8_t *buf, uint32_t Len)
    {
        uint8_t i;
        uint8_t res;
    
        for (i = 0; i < Len; i++)
        {
            res = buf[i];
            if ((g_usb_usart_rx_sta & 0x8000) == 0)    	/* 接收未完成 */
            {
                if (g_usb_usart_rx_sta & 0x4000)        	/* 接收到了0x0d */
                {
                    if (res != 0x0a)
                    {
                        g_usb_usart_rx_sta = 0;          	/* 接收错误,重新开始 */
                    }
                    else
                    {
                        g_usb_usart_rx_sta |= 0x8000;   	/* 接收完成了 */
                    }
                }
                else    /* 还没收到0X0D */
                {
                    if (res == 0x0d)
                    {
                        g_usb_usart_rx_sta |= 0x4000;   	/* 标记接收到了0X0D */
                    }
                    else
                    {
                        g_usb_usart_rx_buffer[g_usb_usart_rx_sta & 0X3FFF] = res;
                        g_usb_usart_rx_sta++;
                        if (g_usb_usart_rx_sta > (USB_USART_REC_LEN - 1))
                        {
                            g_usb_usart_rx_sta = 0; 		/* 接收数据溢出 重新开始接收 */
                        }
                    }
                }
            }
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    CDC_Itf_Receive和cdc_vcp_data_rx,这两个函数一起,用于VCP数据接收,当STM32的USB接收到电脑端串口发送过来的数据时,由USB内核程序调用CDC_Itf_Receive,然后在该函数里面再调用cdc_vcp_data_rx函数,实现VCP的数据接收,只需要在该函数里面,将接收到的数据,保存起来即可,接收的原理和(实验5串口通信实验)完全一样。
    
    • 1

    下面介绍的是通过USB发送数据函数,其定义如下:

    /**
     * @brief       通过 USB 发送数据
     * @param       buf     : 要发送的数据缓冲区
     * @param       len     : 数据长度
     * @retval      无
     */
    void cdc_vcp_data_tx(uint8_t *data, uint32_t Len)
    {
        USBD_CDC_SetTxBuffer(&USBD_Device, data, Len);
        USBD_CDC_TransmitPacket(&USBD_Device);
        delay_ms(CDC_POLLING_INTERVAL);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    cdc_vcp_data_rx用于发送Len个字节的数据给VCP,由VCP通过USB传输给电脑,实现VCP的数据发送。
    
    • 1

    下面介绍的是通过USB格式化输出函数,其定义如下:

    /**
     * @brief       通过 USB 格式化输出函数
     *   @note      通过USB VCP实现printf输出
     *               确保一次发送数据长度不超USB_USART_REC_LEN字节
     * @param       格式化输出
     * @retval      无
     */
    void usb_printf(char *fmt, ...)
    {
        uint16_t i;
        va_list ap;
        va_start(ap, fmt);
        vsprintf((char *)g_usb_usart_printf_buffer, fmt, ap);
        va_end(ap);
        i = strlen((const char *)g_usb_usart_printf_buffer);  /* 此次发送数据的长度 */
        cdc_vcp_data_tx(g_usb_usart_printf_buffer, i);         /* 发送数据 */
        SCB_CleanDCache_by_Addr((uint32_t *)g_usb_usart_printf_buffer, i);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    usb_printf用于实现和普通串口一样的printf操作,该函数将数据格式化输出到USB VCP,功能完全同printf,方便大家使用。
    USB VCP相关代码,就给大家介绍到这里,详细的介绍,请大家参考:UM1734(STM32Cube USB device library).pdf这个文档。
    2. main.c代码
    下面是main.c的程序,具体如下:

    USBD_HandleTypeDef USBD_Device;          	/* USB Device处理结构体 */
    extern volatile uint8_t g_device_state;	/* USB连接 情况 */
    
    int main(void)
    {
        uint16_t len;
        uint16_t times = 0;
        uint8_t usbstatus = 0;
    
        sys_cache_enable();                   	/* 打开L1-Cache */
        HAL_Init();                             	/* 初始化HAL库 */
        sys_stm32_clock_init(240, 2, 2, 4);	/* 设置时钟, 480Mhz */
        delay_init(480);                       	/* 延时初始化 */
        usart_init(115200);                    /* 串口初始化为115200 */
        mpu_memory_protection();              /* 保护相关存储区域 */
        led_init();                             	/* 初始化LED */
        lcd_init();                             	/* 初始化LCD */
        key_init();                             	/* 初始化按键 */
        my_mem_init(SRAMIN);                  	/* 初始化内部内存池(AXI) */
        my_mem_init(SRAM12);                  	/* 初始化SRAM12内存池(SRAM1+SRAM2) */
        my_mem_init(SRAM4);                   	/* 初始化SRAM4内存池(SRAM4) */
        my_mem_init(SRAMDTCM);               	/* 初始化DTCM内存池(DTCM) */
        my_mem_init(SRAMITCM);               	/* 初始化ITCM内存池(ITCM) */
    
        lcd_show_string(30, 50, 200, 16, 16, "STM32", RED);
        lcd_show_string(30, 70, 200, 16, 16, "USB Virtual USART TEST", RED);
    lcd_show_string(30, 90, 200, 16, 16, "ATOM@ALIENTEK", RED);
    /* 提示USB开始连接 */
        lcd_show_string(30, 110, 200, 16, 16, "USB Connecting...", RED); 
    
        USBD_Init(&USBD_Device, &VCP_Desc, 0);
        USBD_RegisterClass(&USBD_Device, USBD_CDC_CLASS);
        USBD_CDC_RegisterInterface(&USBD_Device, &USBD_CDC_fops);
        USBD_Start(&USBD_Device);
    
        while (1)
        {
            if (usbstatus != g_device_state)   /* USB连接状态发生了改变 */
            {
                usbstatus = g_device_state;     /* 记录新的状态 */
                if (usbstatus == 1)
                {
    /* 提示USB连接成功 */
                    lcd_show_string(30, 110, 200, 16, 16, "USB Connected    ", RED); 
                    LED1(0);    /* 绿灯亮 */
                }
                else
                {
    /* 提示USB断开 */
                    lcd_show_string(30, 110, 200, 16, 16, "USB disConnected ", RED); 
                    LED1(1);    /* 绿灯灭 */
                }
            }
    
            if (g_usb_usart_rx_sta & 0x8000)
            {
                len = g_usb_usart_rx_sta & 0x3FFF;  /* 得到此次接收到的数据长度 */
                usb_printf("\r\n您发送的消息长度为:%d\r\n\r\n", len);
                cdc_vcp_data_tx(g_usb_usart_rx_buffer, len);;
                usb_printf("\r\n\r\n");/* 插入换行 */
                g_usb_usart_rx_sta = 0;
            }
            else
            {
                times++;
                if (times % 5000 == 0)
                {
                    usb_printf("\r\nMiniPRO STM32H7开发板USB虚拟串口实验\r\n");
                    usb_printf("正点原子@ALIENTEK\r\n\r\n");
                }
                if (times % 200 == 0)usb_printf("请输入数据,以回车键结束\r\n");
                if (times % 30 == 0)
                {
                    LED0_TOGGLE();  /* 闪烁LED,提示系统正在运行 */
                }
                delay_ms(10);
            }
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79

    此部分代码比较简单,首先定义了USBD_Device结构体,然后通过USBD_Init等函数初始化USB,不过本章实现的是USB虚拟串口的功能。然后在死循环里面轮询USB状态并检查是否接收到数据,如果接收到了数据,则通过VCP_DataTx将数据通过VCP原原本本的返回给电脑端串口调试助手。
    58.4 下载验证
    本例程的测试,需要在电脑上先安装ST提供的USB虚拟串口驱动软件,该软件(V1.5.0版)下载地址:http://www.openedv.com/thread-284178-1-1.html,下载完以后,根据自己电脑的系统,选择合适的驱动安装即可。
    将程序下载到开发板后(注意:USB数据线,要插在USB_SLAVE口!而不是USB_UART端口!),我们打开设备管理器(我用的是WIN10),在端口(COM和LPT)里面可以发现多出了一个COM15的设备,这就是USB虚拟的串口设备端口,如图58.4.1所示:
    在这里插入图片描述

    图58.4.1 通过设备管理器查看USB虚拟的串口设备端口
    如图58.4.1,STM32通过USB虚拟的串口,被电脑识别了,端口号为:COM15(可变),字符串名字为:STMicroelectronics Virtual COM Port(COM15)。此时,开发板的LDE1常亮,同时,LED0在闪烁,提示程序运行。开发板的LCD显示USB Connected,如图58.4.2所示:
    在这里插入图片描述

    图58.4.2 USB虚拟串口连接成功
    然后我们打开XCOM,选择COM15(需根据自己的电脑识别到的串口号选择),并打开串口(注意:波特率可以随意设置),就可以进行测试了,如图58.4.3所示:
    在这里插入图片描述

    图58.4.3 STM32虚拟串口通信测试
    可以看到,我们的串口调试助手,收到了来自STM32开发板的数据,同时,按发送按钮(串口助手必须勾选:发送新行),也可以收到电脑发送给STM32的数据(原样返回),说明我们的实验是成功的。实验现象同第十七章完全一样。
    至此,USB虚拟串口实验就完成了,通过本实验,我们就可以利用STM32的USB,直接和电脑进行数据互传了,具有广泛的应用前景。

  • 相关阅读:
    基于VUE + Echarts 实现可视化数据大屏景区管理平台
    难度上涨,减少专业!安徽大学计算机考研改考
    创邻科技,位居IDC MarketScape中国图数据库市场领导者类别
    震颤的分类是什么?
    回收站清空了怎么恢复?数据恢复,有这些就足够了
    蓝桥杯每日一题2023.10.2
    Java实验报告(三)
    二分查找(c语言)
    如何恢复电脑里的被删除的视频文件?最近教程
    2020 款丰田雷凌车组合仪表上多个故障灯偶发点亮
  • 原文地址:https://blog.csdn.net/weixin_55796564/article/details/127584489