前言
- 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
暂无评论