前言

  • 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_9void 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          256static 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_TESTif (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协议与应用技术

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

  1. USB协议学习笔记 - 虚拟串口Virtual Port Com用于LOG打印

    前言 上一篇讲了STM32 USB 虚拟串口的功能实现,可以通过STM32输出信息到PC端 这篇简单的做个应用:打印LOG(日志)信息到虚拟串口 操作方法 基于上篇的STM32 USB Virtual ...

  2. USB协议学习笔记 - CUSTOM HID 设备

    简介 这里使用STM32平台进行USB 协议的学习与USB 设备的调试开发 USB HID设备,协议较固定,无法实现数据的自由接收与发送 USB CUSTOM HID设备(自定义HID协议)可以实现简 ...

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

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

  4. KEIL 5.38的ARM-CM3/4 ARM汇编设计学习笔记3——串口Stdio实现

    KEIL 5.38的ARM-CM3/4 ARM汇编设计学习笔记3--串口Stdio实现 一.介绍 任务目标 二.工程创建 三.软件设计 第一步,BSP构建 1, 添加前面的pll_config文件 2 ...

  5. Servlet和HTTP请求协议-学习笔记02【Servlet_体系结构与urlpartten配置、HTTP请求协议】

    Java后端 学习路线 笔记汇总表[黑马程序员] Servlet和HTTP请求协议-学习笔记01[Servlet_快速入门-生命周期方法.Servlet_3.0注解配置.IDEA与tomcat相关配置 ...

  6. Qt5学习笔记之串口助手四:增加16进制/ASCII切换、周期发送

    目录 1. 概述 2. 16进制/ASCII发送 2.1 功能实现 2.2 界面修改 3. 接收框显示发送内容 3.1 以16进制/ASCII显示 3.1.1 界面修改 3.1.2 功能实现 3.2 ...

  7. 极客HTTP协议学习笔记破冰篇(1-7)

    极客HTTP协议学习笔记破冰篇(1-7) 前言 各篇章笔记链接 一.学习笔记 1.HTTP的前世今生 2.HTTP是什么 3.与HTTP相关的各种概念(上) 4.与HTTP相关的各种概念(下) 5.常 ...

  8. Servlet和HTTP请求协议-学习笔记01【Servlet_快速入门-生命周期方法、Servlet_3.0注解配置、IDEA与tomcat相关配置】

    Java后端 学习路线 笔记汇总表[黑马程序员] Servlet和HTTP请求协议-学习笔记01[Servlet_快速入门-生命周期方法.Servlet_3.0注解配置.IDEA与tomcat相关配置 ...

  9. stm32学习笔记----双串口同时打开时的printf()问题

    stm32学习笔记----双串口同时打开时的printf()问题 最近因为要使用串口2外接PN532芯片实现通信,另一方面,要使用串口1来将一些提示信息输出到上位机,于是重定义了printf(),使其 ...

最新文章

  1. 19行关键代码,带你轻松入门PaddlePaddle单机训练
  2. 线扫相机——机器视觉中无限制物体的检测
  3. 为什么深度学习不能取代传统的计算机视觉技术?
  4. MySQL 命令行下执行.sql脚本
  5. 真是O(1)吗?想清楚了没?
  6. 如何测试一个网页登陆界面
  7. easycode不推荐使用_为什么?mysql不推荐使用uuid或者雪花id作为主键?
  8. mysql 递归查找父节点_MYSQL递归查询所有父节点
  9. 拓端tecdat|R语言用逻辑回归、决策树和随机森林对信贷数据集进行分类预测
  10. 算法:二叉树从树叶到根部每层构成的数组队列107. Binary Tree Level Order Traversal II
  11. 【平面设计基础】01:抠图—薄、透、露的朦胧美
  12. linux中的段定义的,Linux中的段
  13. SkipList算法原理分析
  14. 卡方检验值转换为P值
  15. 关于跳跃连接 卷积网络
  16. 极力推荐的微信小程序,超级实用,一定要收藏
  17. Vue+ElementUI table表格分页
  18. 杨绛与钱钟书,人世间最理想的婚姻
  19. mac系统安装手机安装包
  20. 分享一个基于QT的自定义串口助手

热门文章

  1. 安卓手机主题软件_安卓手机赚钱软件
  2. 秘鲁地震与Stallman失踪之谜
  3. lcd显示数字+0x30
  4. MySQL死锁问题如何分析锁表后查看死锁和去除死锁快速解决方法
  5. 统计学习导论之R语言应用(四):分类算法R语言代码实战
  6. 20230326作业
  7. Easyexcel 获取表格具体位置的内容
  8. JAVASE之多线程初识
  9. qq家园里游戏c语言,盘点腾讯旗下5款过气游戏,全部玩过的人都该结婚了吧
  10. 高等数学(预备知识之对数函数)