ESP32-S2应用开发——USB通信(CDC类)

2023-11-16

ESP32S2应用开发——USB通信(CDC类)

前言

ESP32-S2是继ESP32之后新出的一款的MCU,而USB接口是ESP32-S2的一大特色,虽然使用的只是USB1.1协议,但是相比于串口而言传输速度还是要快很多的。对于音频或者视频等数据的传输,使用usb明显是比串口有优势的。
因为前段时间项目需求,需要用到ESP32-S2的USB,于是就花了些时间研究了一下,发现网上关于ESP32-S2 USB的介绍很少而且大多资料都过时了,于是就有了这篇博客。
好了,废话不多说了,马上开始讲解。

1 硬件介绍

本文的硬件配置如下:

模块 型号 说明
ESP32-S2 ESP32-S2-WROVER 这是乐鑫的一款模组,内部主要是用乐鑫的ESP32-S2再加上一个4M FLASH和2M PSRAM组成,开发板用的是乐鑫的ESP32-S2-SAOLA

ESP32-S2的引脚很多我就不一一介绍了,这一讲主要用到的UART0和USB(GPIO19,GPIO20)。

1.1 硬件连接

我这里用的是开发板,硬件连接比较简单。
UART0通过USB转TTL芯片连接到PC端。
USB通过GPIO19和GPIO20直连PC端的USB接口。

引脚 描述 说明
GPIO19 USB D- USB信号线,直连PC端即可,不需要接转换芯片
GPIO20 USB D+ USB信号线,直连PC端即可,不需要接转换芯片
U0TXD 串口TX 方便调试使用,需要接USB转换TTL才能连接到PC端
U0RXD 串口RX 方便调试使用,需要接USB转换TTL才能连接到PC端

2 软件开发

2.1 安装开发板

关于ESP32-S2 Arduino的环境搭建我之前出过教程了,这里就不多说了,不懂的同学可以先看下我之前的博客。

2.2 安装库

打开Arduino IDE,依次打开 工具 -> 管理库…
在搜索框输入需要安装的库名称,找到对应的库,点击安装即可。

本文需要使用的Arduino库如下:

Arduino库 版本 说明
ESP32TinyUSB 1.3.4 USB相关库,使用该库要确保ESP32库版本在2.0.0以上
esp32 2.0.1 建议使用该版本,v2.0.2有个usb相关的结构体定义改了,跟ESP32TinyUSB库不兼容。
如果非要用2.0.2以上版本就需要在ESP32TinyUSB和esp32两者之前选择一个把client_event_callback的定义改掉
在这里插入图片描述

2.3 运行示例代码

ESP32TinyUSB库自带很多examples,我们打开一个cdc的示例代码先测试一下USB通讯。
示例代码如下:

/**
 * Simple CDC device connect with putty to use it
 * author: chegewara
 * Serial - used only for logging
 * Serial1 - can be used to control GPS or any other device, may be replaced with Serial
 */
#include "cdcusb.h"
#if CFG_TUD_CDC
CDCusb USBSerial;

class MyUSBCallbacks : public CDCCallbacks {
    void onCodingChange(cdc_line_coding_t const* p_line_coding)
    {
        int bitrate = USBSerial.getBitrate();
        Serial.printf("new bitrate: %d\n", bitrate);
    }

    bool onConnect(bool dtr, bool rts)
    {
        Serial.printf("connection state changed, dtr: %d, rts: %d\n", dtr, rts);
        return true;  // allow to persist reset, when Arduino IDE is trying to enter bootloader mode
    }

    void onData()
    {
        int len = USBSerial.available();
        Serial.printf("\nnew data, len %d\n", len);
        uint8_t buf[len] = {};
        USBSerial.read(buf, len);
        Serial.write(buf, len);
    }

    void onWantedChar(char c)
    {
        Serial.printf("wanted char: %c\n", c);
    }
};


void setup()
{
    Serial.begin(115200);
    USBSerial.setCallbacks(new MyUSBCallbacks());
    USBSerial.setWantedChar('x');

    if (!USBSerial.begin())
        Serial.println("Failed to start CDC USB stack");

}

void loop()
{
    while (Serial.available())
    {
        int len = Serial.available();
        char buf1[len];
        Serial.read(buf1, len);
        int a = USBSerial.write((uint8_t*)buf1, len);
    }
}

#endif

在这里插入图片描述
运行结果如下:
设备管理器能看到两个com口(一个是串口转换芯片,一个是ESP32-S2的USB)。
在这里插入图片描述
用串口助手先打开UART对应的端口,波特率115200。再打开一个串口助手,连接USB虚拟串口对应的com口,此时能看到UART会出现一些log。
在这里插入图片描述
USB连接上之后,两个串口助手之间可以互发数据,说明USB通讯是没问题的。
在这里插入图片描述
提示:如果烧录程序之后出现一直重启的现象,可能是因为MCU原本出厂的固件有一部分没有被擦除导致的,可以使用乐鑫的flash烧录工具对整个MCU进行擦除之后再烧录Arduino的程序。

2.4 USB传输速度测试

简单写一个测试代码用来测试USB数据传输的速度。
示例代码如下:

#include "cdcusb.h"
#include "Arduino.h"
#include <esp_heap_caps.h>

#define FILE_SIZE 971240   // 测试文件的大小
uint8_t *rx_buf;
uint32_t rx_num = 0;
uint8_t first_time_flag = 1;
long lTime;

CDCusb CDCUSBSerial;

class MyCDCCallbacks : public CDCCallbacks {
    void onCodingChange(cdc_line_coding_t const* p_line_coding)
    {
        int bitrate = CDCUSBSerial.getBitrate();
        Serial.printf("new bitrate: %d\n", bitrate);
    }

    bool onConnect(bool dtr, bool rts)
    {
        Serial.printf("connection state changed, dtr: %d, rts: %d\n", dtr, rts);
        return true;  // allow to persist reset, when Arduino IDE is trying to enter bootloader mode
    }

    void onData()
    {
        if(first_time_flag)
        {
            first_time_flag = 0;
            lTime = micros();
        }

        int len = CDCUSBSerial.available();
        CDCUSBSerial.read(&rx_buf[rx_num], len);
        rx_num += len;

        if(rx_num >= FILE_SIZE)
        {
            lTime = micros() - lTime;
            Serial.printf("time: %f s \n", lTime / 1000000.0);
            Serial.printf("speed:%f kb/s", ((float)FILE_SIZE / 1024.0) / (lTime / 1000000.0));
            first_time_flag = 1;
            rx_num = 0;
        }
    }
};

void setup()
{
    Serial.begin(115200);

    if (!CDCUSBSerial.begin())
        Serial.println("Failed to start CDC USB stack");

    CDCUSBSerial.setCallbacks(new MyCDCCallbacks());

    rx_buf = (uint8_t*)ps_malloc(FILE_SIZE);
}

void loop()
{

}

通过串口助手往USB发送一个大文件(971240字节,约948.5kb)。
提示:这里串口助手打开文件时显示的时间是按当前波特率估算出来的,但是实际上我们用的是虚拟串口,USB传输是没有波特率这个参数的,这里波特率不管设置为多少,实际的速度都一样,都是以USB传输速度为准。
在这里插入图片描述

通过ESP32-S2的串口0打印实际的传输的时间和速度。
在这里插入图片描述
经过sscom这个串口助手传输文件测试,ESP32-S2 USB的最大传输速度在190kb/s左右,实际上加上一些应用代码之后,速度会有所下降,约160kb/s左右(这个速度跟具体的应用有关)。
因为USB接收是中断处理的,MCU如果一直处于闲置状态,那USB的数据传输速度可以达到最大。反之,MCU如果一直在运行其他应用代码,那么在接收USB数据时只能通过频繁的中断来完成数据的读取,此时接收的效率明显是要下降一些的。另外,传输速度跟MCU的接收方式也有关系,USB1.1最大支持一次接收64字节,所以MCU在进入回调函数时,应该根据把当前收到的所有数据一次性读取完,而不是每次回调只读一个字节。

后期测试补充:
在使用sscom这个串口助手时,文件的传输速度跟设置的波特率无关,但是后来用另外一个串口助手(UartAssist)时发现用这个工具设置的波特率跟实际传输速度有关联,这就很奇怪了,因为这个只是虚拟串口,实际上是按照USB1.1协议来传输数据的,理论上不应该出现这种情况的。然后我测试了多种不同的波特率,发现波特率较小时,实际传输速度与波特率基本一致,波特率越大速度越快,当波特率增大到2M时,速度与之前sscom串口助手测试的速度接近。继续增大波特率到某个值之后,不管波特率设置多少,速度都不再增大了。最大传输速度在270kb/s左右。
从目前的现象来看,USB的传输速度跟串口工具本身也有关系,具体的原因还没搞清楚,有懂的老哥解答一下吗?

结束语

好了,关于ESP32-S2 USB的使用就介绍到这里。如果这篇文章对你有帮助,可以点赞收藏,如果还有什么问题,欢迎在评论区留言或者私信给我。

补充说明:
最近我经常收到一些私信,这是不是真的USB?这是串口转USB吧?
所以我这里统一补充说明一下,如何区分USB CDC和串口。
CDC类USB和HID不同,它枚举出来的设备确实是一个串行设备,看着是很像串口,但实际上是不一样的。
主要有以下几个区别:

区别 USB 串口
1 两个USB之间是直连的,不需要转换电平 串口是TTL电平的,如果没有转换芯片,是没法直接连接PC端的USB接口的。常用的转换IC如:CH340、CP2102、PL2303、FT232、MAX232等
2 传输速度快 传输速度慢
3 遵循USB协议(可通过逻辑分析仪抓取和解析) 遵循串口协议(可通过逻辑分析仪抓取和解析)
4 USB有枚举过程(可通过BusHound抓取通讯过程) 串口不存在枚举过程

Arduino开发教程汇总:
https://blog.csdn.net/ShenZhen_zixian/article/details/121659482

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

ESP32-S2应用开发——USB通信(CDC类) 的相关文章

  • 使用什么 ffmpeg 命令将无符号整数列表转换为音频文件?

    我有一个文件 其中包含大约四万个整数的列表 这些整数以空格分隔 每个整数的值都在 0 到 255 之间 这里是这个文件 https github com johnlai2004 sound project blob master integ
  • Fedora 中的 Arduino 上传错误“stk500_recv(): 程序员没有响应”

    我正在尝试上传库存Blink在 Fedora Core 15 Linux 中使用 Arduino IDE 绘制草图 我收到此错误 avrdude stk500 recv 程序员没有响应 要重现该问题 通过 USB 线插入 Arduino U
  • Mac OS 10.9 不显示 Arduino 的 USB 调制解调器

    我正在尝试选择 dev tty usbmodem on my Arduino Lenardo设备 操作系统是Mac OSX 10 9 问题是它没有显示 我什至尝试安装FTDI http www ftdichip com Drivers VC
  • Arduino I2S 正弦波

    我正在开发一个项目 我想通过组合不同的正弦波来生成 简单 声音 我使用的是 arduino mkrZero 因为它内置了 I2S 接口 并且似乎有足够的处理能力来满足我的需求 I have wired my system exactly l
  • 如何在 Arduino 上比较 __FlashStringHelper* 和 char*?

    我有一个将文本行输出到串行的板 我需要将这些文本行与我所知道的文本进行比较 本质上 我想做strcmp thestring F knownstring 但是似乎没有一个采用 FlashStringHelper 类型的 strcmp 版本 有
  • Python自动选择串口(适用于Arduino)

    目前 Python 程序必须知道设备 Arduino 位于哪个端口 然后 Python 才能与设备进行通信 Problem 每当设备拔出并重新插入时 其 COM 端口都会发生变化 因此必须再次向 Python 提供正确的串行端口 以便它找到
  • 如何实现Android Open Accessory模式即服务?

    我一直在研究 Android 开放配件开发套件 依照指示Google 提供的 DemoKit 示例 http developer android com guide topics usb accessory html 我在使解决方案适应我的
  • Arduino - 高效地迭代 C 数组

    我有以下数组 PROGMEM prog uint16 t show hide info 4216 8900 4380 580 500 600 500 580 1620 580 500 600 500 580 500 600 480 600
  • C#读取Arduino

    我正在尝试制作一个从 Arduino 读取传出信号的应用程序 但我无法使其在 C 中工作Windows 窗体 http en wikipedia org wiki Windows Forms 仅在控制台中 我的 C Windows 窗体代码
  • Arduino 上的 Serial 和 Stream 有什么区别,Serial.write 是如何实现的?

    我很难理解串行和流这两个术语之间的区别 串行不是流的一种吗 我对作业有一些我不明白的问题 计算机通过使用 流或串行 读取 彼此发送的数据来确定每个字节的含义 Also Serial write 我也很困惑 它返回一个字节的数据 对吗 一个字
  • 使用 Java 控制 Arduino

    我正在寻找一个LED http en wikipedia org wiki Light emitting diode用Java程序打开和关闭 我用 C 完成了这个项目大约 5 分钟 但用 Java 似乎更具挑战性 我让 Arduino 等待
  • 如何提高 PySerial 读取速度

    我目前正在构建一台使用 Arduino Mega2560 作为主控制器的机器 Arduino 通过串口连接 获取命令 执行它并每 1ms 吐出一堆测量数据 我有一个运行 Python 的 Raspberry Pi 为用户提供一个漂亮的 GU
  • Arduino C++ 代码:可以使用虚函数和异常吗?

    跟进这条评论 https stackoverflow com questions 452139 writing firmware assembly or high level 452401从问题中编写固件 汇编还是高级 https stac
  • Arduino 错误:未命名类型?

    我已经编写了一个库 但遇到错误未命名类型的问题 我已经尝试了一切 搜索了几个小时 但没有运气 库放置在arduino sketch文件夹的 libraries 文件夹中 请帮忙 我使用的是 OSX 但 Windows 上也出现同样的问题 这
  • 带 firebase 的 Nodemcu(ESP8266)

    这是我上传到 ESP8266 以连接到 firebase 的代码 include
  • 云到设备 Azure IoT REST API

    我探索了如何使用 Azure REST API 将数据从设备发送到云 它运行无缝 没有任何问题 我没有找到有关使用 Azure IoT Hub REST API 向 Arduino 板发送云到设备消息的好文章 有人可以就此提供建议吗 您还可
  • Arduino sprintf float 未格式化

    我有这个arduino草图 char temperature 10 float temp 10 55 sprintf temperature f F temp Serial println temperature 温度打印为 F 关于如何格
  • 类中的易失性变量:“‘易失性’之前预期有非限定 ID”?

    我有两个static volatile我的类中定义的变量ADC 该类写为 裁剪以节省空间 pragma once include PeriodicProcess PeriodicProcess h include
  • 如何将 Android 应用程序正确连接到支持蓝牙的 Arduino 微控制器上的 RFCOMM 套接字?

    我正在与我大学的一些学生合作开发一个简单的蓝牙 Android 应用程序 该应用程序将用于与连接有蓝牙模块的 Arduino 微控制器进行串行通信 RFCOMM 据我所知 我正在使用正确的蓝牙地址和 UUIDRFCOMM SPP 00001
  • Arduino 上的串行消息到整数

    我希望我的 Arduino 通过串行通信接收一个整数 你能帮我解决这个问题吗 它应该是这样的形式 int value strtoint Serial read 有多种方法可以读取整数Serial 很大程度上取决于数据发送时的编码方式 Ser

随机推荐

  • 【随笔】年轻人的存款多少取决于个人或家庭的消费观

    近日 有调查称 大概五分之一的年轻人存款在一万元以内 10万元存款是一个 坎 存款超过10万就会超过53 7 的人 年轻人 存款 两个词碰撞在一起 引来了广泛的关注和讨论 你认为年轻人存款难吗 可以从以下几个角度发表你的看法 目录 一 灵魂
  • 脑机接口BCI技术概述

    脑机接口BCI技术概述 前言 一 脑机接口BCI是什么 二 BCI的框架 1 信号采集 2 信号处理 2 1 预处理 2 2 特征提取 2 3 模式分类 3 BCI应用 三 脑控系统中常用的BCI范式 1 基于感觉运动节律的BCI 2 基于
  • v-text的用法

    v text指令 相当于原生js中的innerText 用于将数据填充到标签中 作用于插值表达式类似 但是没有闪动问题 如果数据中有HTML标签会将html标签一并输出 注意 此处为单向绑定 数据对象上的值改变 插值会发生变化 但是当插值发
  • 安卓智能手机开发,打地鼠实例(登录页面+游戏界面+课程设计)

    主要为大家详细介绍了Android实现打地鼠小游戏 文中示例代码介绍的非常详细 具有一定的参考价值 感兴趣的小伙伴们可以参考一下 文件 url80 ctfile com f 25127180 743379579 b297fb p 55168
  • JavaSe学习日记

    前言 How to study 需求 工作需要 跳槽 对方需要 技术控 看看传统技术能否解决 能解决 不完美 解决不了 问清楚新技术到底有什么优异 引出我们学习的新技术和知识点 学习新技术或者知识点的基本原理和基本语法 先不要考虑细节 快速
  • Qt 5.9.6 配置MSVC 2017编译器

    一 安装Visual Studio 使用MSVC 2017的最低版本为Visual Studio 2017 高版本适用 我使用的是Visual Studio Community 2019 VS官网下载 选择安装通用Windows平台开发和使
  • GCC - structure/union前端解析说明

    以GCC8 2 0版本为例 介绍gcc语法解析器 parser 对声明即函数定义的解析过程以及structure union的简单解析说明 1 GCC中声明和定义的解析过程 1 1 解析入口 c parse file GCC中gcc c c
  • 双指针算法模板

    什么是同向双指针 什么是相向双指针 双指针的鼻祖题 两数之和 Two Sum 链表上的快慢指针算法 快速排序 归并排序 几乎所有 Two Sum 变种 Partition Quick Select 分成两个部分 分成三个部分 一些你没听过的
  • 关于keil中内存分配的问题,局部变量、全局变量,堆栈的分配

    看 map文件 从 map文件中可以看出 ram中的数据是如何摆放的 1 首先从0x20000000开始 放全局变量的数据 如上图2所示 0x20000000以及0x200000004 0x20000008的地方的数据 存放的是全局变量 分
  • 基于STM32F407的摄像头(不带FIFO的OV7670)图像采集及LCD显示实验-笔记整理

    硬件说明 STM32F4开发板 stm32f4系列的芯片处理的能力可以说非常强大了的 而且内部还自带有数字摄像头接口 DCMI 可以说stm32f407的核心板和不带FIFO的摄像头模块OV7670简直就是绝配 我手上的这块张这个样子 图片
  • 安卓studio 配置Flutter

    1 下载Flutter SDK Flutter SDK 我的安卓studio版本是4 2 1 下载的Flutter SDK 是Dev channel Windows 2 6 0版本 2 将压缩包解压到指定目录 例如C src flutter
  • 最新如何在kali linux中安装搜狗输入法

    在安装之前我们先来更新我们的源 更新方法 leafpad etc apt sources list 在打开的文件中输入下面的源 保存退出 阿里云源 deb http mirrors aliyun com kali sana main non
  • javaFX用IDEA打包导出exe后图片不显示问题

    今天在用idea打包完成了JavaFX项目时 查到了两种方法 一种是用eclipse中的ant直接打包形成可安装的exe文件 见https code makery ch zh cn library javafx tutorial part7
  • docker-compose deploy 高可用 elasticsearch TLS

    文章目录 1 sysctl 2 swap 3 hosts 4 配置 instances yaml 5 创建证书 6 部署 7 修改 kibanna 密码 8 清理 1 sysctl root github es tls cat etc sy
  • 用canvas绘制的饼状图,颜色随机,动态生成

    想想自己平时太懒了 像jQuery一样 write less do more 但是 我决定改变了 write more do more 这里贴上我用canvas绘制的饼状图 均分6等分 颜色随机
  • 点击table表格单元格修改数据同时更新数据库

    XML HTML Code
  • matlab读取excel数据并画图

    Matlab可以使用函数 xlsread 来读取Excel数据 语法 num txt raw xlsread filename 其中 filename 是Excel文件的名称 num 是读取的数字数据 txt 是读取的文本数据 raw 是读
  • word2016页码设置(包括目录去除页码)

    word2016页码设置 包括目录去除页码 把你鼠标的光标 移到正文 最开始 点击布局 选择 分隔符 里面的 下一页 开始插入页码 然后设置页码格式 点击链接到前一节 手动删除你目录上的页码 操作流程 1 把你鼠标的光标 移到正文 最开始
  • stm32单片机控制28BYJ48步进电机原理及代码

    命名方式 以28BYJ48步进电机为例 28BYJ48步进电机的编号 28 步进电机的有效最大外径是28毫米 B 表示步进电机 Y 表示永磁式 J 表示减速型 48 表示四相八拍 工作原理 1 五线四相步进电机 不同相位得电会让步进电机的转
  • ESP32-S2应用开发——USB通信(CDC类)

    ESP32S2应用开发 USB通信 CDC类 目录 ESP32S2应用开发 USB通信 CDC类 前言 1 硬件介绍 1 1 硬件连接 2 软件开发 2 1 安装开发板 2 2 安装库 2 3 运行示例代码 2 4 USB传输速度测试 结束