0
点赞
收藏
分享

微信扫一扫

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`
```c
#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`
```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协议与应用技术
举报

相关推荐

0 条评论