USB协议学习笔记 - 虚拟串口Virtual Port Com LED控制

文章目录[隐藏]

前言

  • STM32 的USB 可以虚拟成一个串口,功能还挺强,感觉比HID好用
  • 这里使用USB 虚拟的串口,做个控制LED的小程序
  • 控制LED这里使用自定义的AT命令方式,如红灯亮:AT+LEDR_ON,红灯灭:AT+LEDR_OFF

程序如下

  • 首先STM32 USB虚拟成串口的操作,参考前面的文章
  • LED.c
#include "led.h"

/* all LEDS gpio init */
void leds_gpio_init(void)
{
    GPIO_InitTypeDef GPIO_InitStruct = {0};

    LEDR_GPIO_RCC_ENABLE();
    LEDG_GPIO_RCC_ENABLE();
    LEDB_GPIO_RCC_ENABLE();

    HAL_GPIO_WritePin(LEDR_GPIO_PORT, LEDR_GPIO_PINS, GPIO_PIN_SET);
    HAL_GPIO_WritePin(LEDG_GPIO_PORT, LEDG_GPIO_PINS, GPIO_PIN_SET);
    HAL_GPIO_WritePin(LEDB_GPIO_PORT, LEDB_GPIO_PINS, GPIO_PIN_SET);

    GPIO_InitStruct.Pin = LEDR_GPIO_PINS;
    GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
    HAL_GPIO_Init(LEDR_GPIO_PORT, &GPIO_InitStruct);

    GPIO_InitStruct.Pin = LEDG_GPIO_PINS;
    GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
    HAL_GPIO_Init(LEDG_GPIO_PORT, &GPIO_InitStruct);

    GPIO_InitStruct.Pin = LEDB_GPIO_PINS;
    GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
    HAL_GPIO_Init(LEDB_GPIO_PORT, &GPIO_InitStruct);
}

/* LEDR power control */
void LEDR_power_ctrl(unsigned int bon)
{
    if (bon == 0x01) /* LEDR ON */
    {
        HAL_GPIO_WritePin(LEDR_GPIO_PORT, LEDR_GPIO_PINS, GPIO_PIN_RESET);
    }
    else
    {
        HAL_GPIO_WritePin(LEDR_GPIO_PORT, LEDR_GPIO_PINS, GPIO_PIN_SET);
    }
}

/* LEDG power control */
void LEDG_power_ctrl(unsigned int bon)
{
    if (bon == 0x01) /* LEDG ON */
    {
        HAL_GPIO_WritePin(LEDG_GPIO_PORT, LEDG_GPIO_PINS, GPIO_PIN_RESET);
    }
    else
    {
        HAL_GPIO_WritePin(LEDG_GPIO_PORT, LEDG_GPIO_PINS, GPIO_PIN_SET);
    }
}

/* LEDB power control */
void LEDB_power_ctrl(unsigned int bon)
{
    if (bon == 0x01)
    {
        HAL_GPIO_WritePin(LEDB_GPIO_PORT, LEDB_GPIO_PINS, GPIO_PIN_RESET);
    }
    else
    {
        HAL_GPIO_WritePin(LEDB_GPIO_PORT, LEDB_GPIO_PINS, GPIO_PIN_SET);
    }
}
  • led.h
#ifndef __LED_H__
#define __LED_H__

#include "stm32l4xx_hal.h"

#define LEDR_GPIO_RCC_ENABLE()  __HAL_RCC_GPIOE_CLK_ENABLE()
#define LEDR_GPIO_PORT          GPIOE
#define LEDR_GPIO_PINS          GPIO_PIN_7

#define LEDG_GPIO_RCC_ENABLE()  __HAL_RCC_GPIOE_CLK_ENABLE()
#define LEDG_GPIO_PORT          GPIOE
#define LEDG_GPIO_PINS          GPIO_PIN_8

#define LEDB_GPIO_RCC_ENABLE()  __HAL_RCC_GPIOE_CLK_ENABLE()
#define LEDB_GPIO_PORT          GPIOE
#define LEDB_GPIO_PINS          GPIO_PIN_9

void leds_gpio_init(void);
void LEDG_power_ctrl(unsigned int bon);
void LEDR_power_ctrl(unsigned int bon);
void LEDB_power_ctrl(unsigned int bon);

#endif

  • 这里修改usbd_cdc_if.c 中的串口数据接收函数:CDC_Receive_FS
extern void ata_buff_put(uint8_t *buf);
/**
  * @brief  Data received over USB OUT endpoint are sent over CDC interface
  *         through this function.
  *
  *         @note
  *         This function will issue a NAK packet on any OUT packet received on
  *         USB endpoint until exiting this function. If you exit this function
  *         before transfer is complete on CDC interface (ie. using DMA controller)
  *         it will result in receiving more data while previous ones are still
  *         not sent.
  *
  * @param  Buf: Buffer of data to be received
  * @param  Len: Number of data received (in bytes)
  * @retval Result of the operation: USBD_OK if all operations are OK else USBD_FAIL
  */

static int8_t CDC_Receive_FS(uint8_t* Buf, uint32_t *Len)
{
    /* USER CODE BEGIN 6 */
    USBD_CDC_SetRxBuffer(&hUsbDeviceFS, &Buf[0]);
    USBD_CDC_ReceivePacket(&hUsbDeviceFS);

    ata_buff_put(UserRxBufferFS); /* recv user command */
    return (USBD_OK);
    /* USER CODE END 6 */
}
  • main.c
#include "main.h"
#include "usb_device.h"
#include "usbd_cdc_if.h"
#include <stdio.h>
#include <stdarg.h>
#include "led.h"

void SystemClock_Config(void);
static void MX_GPIO_Init(void);

#define ENABLE_ATA_TEST
#define DBG_BUFF_MAX_LEN          256
#define ATA_BUFF_MAX_LEN          256

static uint8_t ata_buf[ATA_BUFF_MAX_LEN] = { 0 };
static uint8_t ata_recv_flag = 0x00;

void ata_buff_put(uint8_t *buf)
{
    if (buf == 0)
        return;
    strncpy((char *)ata_buf, (const char *)buf, ATA_BUFF_MAX_LEN);
    ata_recv_flag = 0x01;
}

void usb_vcom_puts(uint8_t *buf)
{
    CDC_Transmit_FS(buf, strlen((const char *)buf));
}

/* debug print : support float double */
int printk(const char *fmt, ...)
{
    va_list args;
    static char log_buf[DBG_BUFF_MAX_LEN] = { 0 };

    va_start(args, fmt);
    int length = vsnprintf(log_buf, sizeof(log_buf) - 1, fmt, args);

    usb_vcom_puts((uint8_t *)log_buf);

    return length;
}

void ata_notify_handler(void)
{
#ifdef ENABLE_ATA_TEST
    if (ata_recv_flag == 0)
        return;

    uint8_t sendbuffer[ATA_BUFF_MAX_LEN];

    if (strlen((char *)ata_buf) <= 5) /* AT+XX\r\n */
        return;

    memset(sendbuffer,0,sizeof(sendbuffer));

    if(strncmp((char *)ata_buf,"AT+LEDR_ON",strlen("AT+LEDR_ON"))==0) /* LEDR ON */
    {
        LEDR_power_ctrl(1);
        printk("OK\r\n");
    }
    else if(strncmp((char *)ata_buf,"AT+LEDR_OFF",strlen("AT+LEDR_OFF"))==0) /* LEDR OFF */
    {
        LEDR_power_ctrl(0);
        printk("OK\r\n");
    }
    else if(strncmp((char *)ata_buf,"AT+LEDG_ON",strlen("AT+LEDG_ON"))==0) /* LEDG ON */
    {
        LEDG_power_ctrl(1);
        printk("OK\r\n");
    }
    else if(strncmp((char *)ata_buf,"AT+LEDG_OFF",strlen("AT+LEDG_OFF"))==0) /* LEDG OFF */
    {
        LEDG_power_ctrl(0);
        printk("OK\r\n");
    }
    else if(strncmp((char *)ata_buf,"AT+LEDB_ON",strlen("AT+LEDB_ON"))==0) /* LEDB ON */
    {
        LEDB_power_ctrl(1);
        printk("OK\r\n");
    }
    else if(strncmp((char *)ata_buf,"AT+LEDB_OFF",strlen("AT+LEDB_OFF"))==0) /* LEDB OFF */
    {
        LEDB_power_ctrl(0);
        printk("OK\r\n");
    }
    else
    {
        printk("NO CMD found! %s\r\n", ata_buf);
    }
    ata_recv_flag = 0x00;
#endif
}

int main(void)
{
    uint32_t cnt = 0x00;
    HAL_Init();
    SystemClock_Config();
    MX_GPIO_Init();
    leds_gpio_init();
    MX_USB_DEVICE_Init();

    HAL_Delay(2000);
    printk("%s : STM32 USB Virtual Port Com LED Test!\r\n", __func__, cnt);
    while (1)
    {
        ata_notify_handler();
    }
}

烧写验证

  • 编译下载后,电脑端打开串口助手,并打开STM32虚拟的USB串口
  • 尝试在串口助手发送:AT+LEDG_OFF AT+LEDG_ON 等LED指令(注意追加回车换行),发现LED可以正常的控制亮灭

在这里插入图片描述

小结

  • USB 虚拟串口,功能还是挺使用的,可以用于普通的串口的输入与输出,可以用于通信与控制,比USB HID要简单一些
  • 继续研究USB的应用(使用),并不断的整理USB相关的资料,深入学习USB协议与应用技术

版权声明:本文为CSDN博主「张世争」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/tcjy1000/article/details/122832898

生成海报
点赞 0

张世争

我还没有学会写个人说明!

暂无评论

发表评论

相关推荐

USB协议学习笔记 - CUSTOM HID控制LED

简介 前面了解了 STM32 CUSTOM HID 设备,但是有几个细节没有处理好,如接收到主机的报告后,如何接收到指定的数组,并实现通信功能,如控制LED亮灭&#xff1