当前位置: 首页> 游戏> 网游 > 在线旅游网站平台有哪些_电商网站设计实例_100个裂变营销案例_百度seo怎么把关键词优化上去

在线旅游网站平台有哪些_电商网站设计实例_100个裂变营销案例_百度seo怎么把关键词优化上去

时间:2025/7/14 6:00:02来源:https://blog.csdn.net/cheungxiongwei/article/details/146506737 浏览次数:0次
在线旅游网站平台有哪些_电商网站设计实例_100个裂变营销案例_百度seo怎么把关键词优化上去

基于ESP32和TinyUSB实现虚拟U盘功能的完整指南

  • 基于ESP32和TinyUSB实现虚拟U盘功能的完整指南
    • 摘要
    • 引言
    • 安装 esp_tinyusb 依赖
    • 自定义主机电脑卷标
    • USB描述符配置与初始化
    • MSC配置与SD卡初始化
      • SD卡初始化代码解析
    • 文件目录浏览与任务调度
    • 完整代码
    • 结论

摘要

本文详细介绍了如何利用ESP32与TinyUSB库实现虚拟U盘(Mass Storage Class, MSC)功能。通过对代码示例的解析,读者将了解到如何配置USB描述符、初始化SD卡、实现挂载与卸载操作,并学习如何将代码片段嵌入文章中。本文同时提供完整代码的占位符,方便开发者根据自身需求进行修改和调试。


引言

随着物联网和嵌入式设备的普及,利用ESP32实现多种外设功能已成为开发者的热门选择。本文重点介绍利用TinyUSB库在ESP32平台上构建虚拟U盘的实现方法。通过深入解析代码示例,我们将展示如何将SD卡内容以USB大容量存储设备的形式提供给主机系统。

在这篇文章中,我们将着重讨论以下几个关键点:

  • tinyusb依赖的安装:如何安装 esp-tinyusb 依赖。
  • U盘卷标的设置:如何自定义U盘驱动器卷标。
  • USB描述符的配置:如何为虚拟U盘定义设备、配置和接口描述符。
  • SD卡初始化和挂载:如何使用ESP-IDF的SDMMC驱动实现SD卡的初始化,并借助TinyUSB完成挂载。
  • 文件目录浏览:如何利用FreeRTOS任务和文件系统接口浏览SD卡中的文件。

这些内容不仅能帮助初学者快速上手,同时对于有经验的开发者来说也能提供优化思路。接下来我们将对代码进行详细剖析。

安装 esp_tinyusb 依赖

打开 esp32 组件仓库 https://components.espressif.com/

搜索 esp_tinyusb 关键字,然后安装 esp_tinyusb 组件

idf.py add-dependency "espressif/esp_tinyusb^1.7.2"

重启 vscode,刷新 sdkconfig 配置项,开启 MSC (Mass Storage Class) 选项。
在这里插入图片描述

自定义主机电脑卷标

  1. 使用 f_setlabel 函数
    在这里插入图片描述
ESP_ERROR_CHECK(tinyusb_msc_storage_mount(mount_point()));
// f_setlabel label max len less than 11 byte
// ref http://elm-chan.org/fsw/ff/doc/setlabel.html
if (auto ret = f_setlabel("XIONGWEI"); FR_OK != ret) {ESP_LOGI(TAG, "USB setlabel Failed code:%d", ret);
}
ESP_ERROR_CHECK(tinyusb_msc_storage_unmount());
  1. 使用 autorun.inf 配置文件

在这里插入图片描述

使用 autorun.inf 自定义驱动器的卷标(Volume Label)和驱动器图标(Drive Icon)

[AutoRun]
label=My Custom USB
icon=usb.ico

以下是一些关于 AutoRun.inf 文件的权威资源,供进一步参考:

  1. Microsoft Documentation (Legacy): AutoRun.inf Entries
    该文档详细介绍了 AutoRun.inf 文件中的各个条目及其用途,适用于早期版本的 Windows。

  2. Microsoft Documentation (Modern): AutoRun Commands
    该文档提供了关于 AutoRun.inf 文件中命令的现代解释,适用于当前版本的 Windows。

  3. Wikipedia: AutoRun.inf
    Wikipedia 上的文章提供了 AutoRun.inf 文件的概述,包括其历史、用途以及安全方面的考虑。


USB描述符配置与初始化

在代码的开头部分,我们定义了USB设备的描述符信息。描述符是USB设备与主机通信时所必须的元数据。下面代码片段展示了设备描述符的配置:

static tusb_desc_device_t descriptor_config = {.bLength = sizeof(descriptor_config),.bDescriptorType = TUSB_DESC_DEVICE,.bcdUSB = 0x0200,.bDeviceClass = TUSB_CLASS_MISC,.bDeviceSubClass = MISC_SUBCLASS_COMMON,.bDeviceProtocol = MISC_PROTOCOL_IAD,.bMaxPacketSize0 = CFG_TUD_ENDPOINT0_SIZE,.idVendor = 0x303A, // Espressif VID,用户可根据需求修改.idProduct = 0x4002,.bcdDevice = 0x100,.iManufacturer = 0x01,.iProduct = 0x02,.iSerialNumber = 0x03,.bNumConfigurations = 0x01
};

这段代码设置了ESP32设备的基本信息,包括厂商ID、产品ID以及USB标准版本。


MSC配置与SD卡初始化

为了实现虚拟U盘功能,必须配置MSC(Mass Storage Class)接口和初始化SD卡。以下代码片段展示了如何定义MSC配置描述符:

static uint8_t const msc_fs_configuration_desc[] = {TUD_CONFIG_DESCRIPTOR(1, ITF_NUM_TOTAL, 0, TUSB_DESC_TOTAL_LEN,TUSB_DESC_CONFIG_ATT_REMOTE_WAKEUP, 100),TUD_MSC_DESCRIPTOR(ITF_NUM_MSC, 0, EDPT_MSC_OUT, EDPT_MSC_IN, 64),
};

在虚拟U盘类 virtual_u_diskmount() 方法中,首先调用 storage_init_sdmmc(handle()) 来初始化SD卡,然后配置TinyUSB MSC存储参数。通过注册回调函数 storage_mount_changed_cb,系统能够实时反馈挂载状态变化。初始化成功后,TinyUSB驱动被安装,并通过 f_setlabel("XI") 设置存储卷标。

SD卡初始化代码解析

esp_err_t storage_init_sdmmc(sdmmc_card_t **card) {sdmmc_host_t host = SDMMC_HOST_DEFAULT();host.slot = SDMMC_HOST_SLOT_0;host.max_freq_khz = SDMMC_FREQ_HIGHSPEED;sd_pwr_ctrl_ldo_config_t ldo_config = {.ldo_chan_id = 4,};sd_pwr_ctrl_handle_t pwr_ctrl_handle = NULL;esp_err_t ret = sd_pwr_ctrl_new_on_chip_ldo(&ldo_config, &pwr_ctrl_handle);if (ret != ESP_OK) {ESP_LOGE(TAG, "Failed to create power control handle");return ret;}host.pwr_ctrl_handle = pwr_ctrl_handle;sdmmc_slot_config_t slot_config = SDMMC_SLOT_CONFIG_DEFAULT();slot_config.width = 4;slot_config.flags |= SDMMC_SLOT_FLAG_INTERNAL_PULLUP;sdmmc_card_t *sd_card = (sdmmc_card_t *)malloc(sizeof(sdmmc_card_t));(*host.init)();ESP_ERROR_CHECK(sdmmc_host_init_slot(host.slot, (const sdmmc_slot_config_t *)&slot_config));while (sdmmc_card_init(&host, sd_card)) {ESP_LOGE(TAG, "The detection pin of the slot is disconnected (Insert uSD card). Retrying...");vTaskDelay(pdMS_TO_TICKS(1000));}sdmmc_card_print_info(stdout, sd_card);*card = sd_card;return ESP_OK;
}

这段代码展示了如何配置SDMMC主机、初始化电源控制以及反复尝试初始化SD卡,确保系统在检测不到SD卡时能够持续重试。对于嵌入式系统开发者而言,这种防护机制尤为重要。


文件目录浏览与任务调度

代码中还提供了一个 list_files 方法,用于遍历指定目录中的文件和子目录。该方法利用了标准C库中的 opendirreaddir 接口,并结合ESP32的日志打印机制输出结果:

static void list_files(const char *path) {DIR *dir = opendir(path);if (!dir) {ESP_LOGE(TAG, "Failed to open directory: %s", path);return;}struct dirent *entry;while ((entry = readdir(dir)) != NULL) {if (entry->d_type == DT_DIR) {// 处理目录文件ESP_LOGI(TAG, "DIR: %s", entry->d_name);} else if (entry->d_type == DT_REG) {// 处理常规文件ESP_LOGI(TAG, "FILE: %s", entry->d_name);} else {ESP_LOGI(TAG, "UNKNOWN: %s", entry->d_name);}}closedir(dir);
}

该函数不仅提高了代码的可读性,同时也为开发者提供了一个简单的示例,如何在嵌入式系统中实现目录遍历功能,这对于调试和日志记录非常有用。


完整代码

完整代码包括:

  1. 包含头文件部分
  2. USB描述符和MSC配置部分
  3. virtual_u_disk类的定义和方法实现
  4. SD卡初始化和文件浏览函数
  5. app_main函数,作为程序入口
#ifdef __cplusplus
extern "C" {
#endif#include "esp_log.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "sdkconfig.h"#include "tinyusb.h"
#include "tusb_msc_storage.h"#include "diskio_sdmmc.h"
#include "sd_pwr_ctrl_by_on_chip_ldo.h"#include <dirent.h>
#include <string.h>#ifdef __cplusplus
}
#endifstatic constexpr char TAG[] = "usb";/* TinyUSB descriptorsgoto sdkconfig Enable Massive Storage Class (MSC) Option
********************************************************************* */
#define EPNUM_MSC 1
#define TUSB_DESC_TOTAL_LEN (TUD_CONFIG_DESC_LEN + TUD_MSC_DESC_LEN)enum { ITF_NUM_MSC = 0, ITF_NUM_TOTAL };enum {EDPT_CTRL_OUT = 0x00,EDPT_CTRL_IN = 0x80,EDPT_MSC_OUT = 0x01,EDPT_MSC_IN = 0x81,
};static tusb_desc_device_t descriptor_config = {.bLength = sizeof(descriptor_config),.bDescriptorType = TUSB_DESC_DEVICE,.bcdUSB = 0x0200,.bDeviceClass = TUSB_CLASS_MISC,.bDeviceSubClass = MISC_SUBCLASS_COMMON,.bDeviceProtocol = MISC_PROTOCOL_IAD,.bMaxPacketSize0 = CFG_TUD_ENDPOINT0_SIZE,.idVendor = 0x303A, // This is Espressif VID. This needs to be changed// according to Users / Customers.idProduct = 0x4002,.bcdDevice = 0x100,.iManufacturer = 0x01,.iProduct = 0x02,.iSerialNumber = 0x03,.bNumConfigurations = 0x01};static uint8_t const msc_fs_configuration_desc[] = {// Config number, interface count, string index, total length, attribute,// power in mATUD_CONFIG_DESCRIPTOR(1, ITF_NUM_TOTAL, 0, TUSB_DESC_TOTAL_LEN,TUSB_DESC_CONFIG_ATT_REMOTE_WAKEUP, 100),// Interface number, string index, EP Out & EP In address, EP sizeTUD_MSC_DESCRIPTOR(ITF_NUM_MSC, 0, EDPT_MSC_OUT, EDPT_MSC_IN, 64),
};#if (TUD_OPT_HIGH_SPEED)
static const tusb_desc_device_qualifier_t device_qualifier = {.bLength = sizeof(tusb_desc_device_qualifier_t),.bDescriptorType = TUSB_DESC_DEVICE_QUALIFIER,.bcdUSB = 0x0200,.bDeviceClass = TUSB_CLASS_MISC,.bDeviceSubClass = MISC_SUBCLASS_COMMON,.bDeviceProtocol = MISC_PROTOCOL_IAD,.bMaxPacketSize0 = CFG_TUD_ENDPOINT0_SIZE,.bNumConfigurations = 0x01,.bReserved = 0};static uint8_t const msc_hs_configuration_desc[] = {// Config number, interface count, string index, total length, attribute,// power in mATUD_CONFIG_DESCRIPTOR(1, ITF_NUM_TOTAL, 0, TUSB_DESC_TOTAL_LEN,TUSB_DESC_CONFIG_ATT_REMOTE_WAKEUP, 100),// Interface number, string index, EP Out & EP In address, EP sizeTUD_MSC_DESCRIPTOR(ITF_NUM_MSC, 0, EDPT_MSC_OUT, EDPT_MSC_IN, 512),
};
#endif // TUD_OPT_HIGH_SPEEDstatic char const *string_desc_arr[] = {(const char[]){0x09, 0x04}, // 0: is supported language is English (0x0409)"TinyUSB",                  // 1: Manufacturer"TinyUSB Device",           // 2: Product"123456",                   // 3: Serials"Example MSC",              // 4. MSC
};
/*********************************************************************** TinyUSB* descriptors*/class virtual_u_disk {
public:esp_err_t mount() {ESP_ERROR_CHECK(storage_init_sdmmc(handle()));tinyusb_msc_sdmmc_config_t config_sdmmc = {.card = *handle(),.callback_mount_changed =storage_mount_changed_cb,.mount_config{.max_files = 5}};ESP_ERROR_CHECK(tinyusb_msc_storage_init_sdmmc(&config_sdmmc));ESP_ERROR_CHECK(tinyusb_msc_register_callback(TINYUSB_MSC_EVENT_MOUNT_CHANGED, storage_mount_changed_cb));ESP_ERROR_CHECK(tinyusb_msc_storage_mount(mount_point()));// f_setlabel label max len less than 11 byte// ref http://elm-chan.org/fsw/ff/doc/setlabel.htmlif (auto ret = f_setlabel("XIONGWEI"); FR_OK != ret) {ESP_LOGI(TAG, "USB setlabel Failed code:%d", ret);}ESP_ERROR_CHECK(tinyusb_msc_storage_unmount());const tinyusb_config_t tusb_cfg = {.device_descriptor = &descriptor_config,.string_descriptor = string_desc_arr,.string_descriptor_count =sizeof(string_desc_arr) / sizeof(string_desc_arr[0]),.external_phy = false,
#if (TUD_OPT_HIGH_SPEED).fs_configuration_descriptor = msc_fs_configuration_desc,.hs_configuration_descriptor = msc_hs_configuration_desc,.qualifier_descriptor = &device_qualifier,
#else.configuration_descriptor = msc_fs_configuration_desc,
#endif // TUD_OPT_HIGH_SPEED};ESP_ERROR_CHECK(tinyusb_driver_install(&tusb_cfg));ESP_LOGI(TAG, "USB MSC initialization DONE");return ESP_OK;}esp_err_t unmount() {ESP_ERROR_CHECK(tinyusb_msc_storage_unmount());return ESP_OK;}sdmmc_card_t **handle() {static sdmmc_card_t *sdcard_handle{nullptr};return &sdcard_handle;}static void list_files(const char *path) {DIR *dir = opendir(path);if (!dir) {ESP_LOGE(TAG, "Failed to open directory: %s", path);return;}struct dirent *entry;while ((entry = readdir(dir)) != NULL) {if (entry->d_type == DT_DIR) {DIR *subdir = opendir(path);int file_count = 0;if (subdir) {while (readdir(subdir) != NULL) {file_count++;}closedir(subdir);}ESP_LOGI(TAG, "DIR (%d): %s", file_count, entry->d_name);} else if (entry->d_type == DT_REG) {ESP_LOGI(TAG, "FILE: %s", entry->d_name);} else {ESP_LOGI(TAG, "UNKNOWN: %s", entry->d_name);}}closedir(dir);}private:static void storage_mount_changed_cb(tinyusb_msc_event_t *event) {ESP_LOGI(TAG, "Storage mounted to application: %s",event->mount_changed_data.is_mounted ? "Yes" : "No");}esp_err_t storage_init_sdmmc(sdmmc_card_t **card) {sdmmc_host_t host = SDMMC_HOST_DEFAULT();host.slot = SDMMC_HOST_SLOT_0;host.max_freq_khz = SDMMC_FREQ_HIGHSPEED;sd_pwr_ctrl_ldo_config_t ldo_config = {.ldo_chan_id = 4,};sd_pwr_ctrl_handle_t pwr_ctrl_handle = NULL;esp_err_t ret = sd_pwr_ctrl_new_on_chip_ldo(&ldo_config, &pwr_ctrl_handle);if (ret != ESP_OK) {ESP_LOGE(TAG, "Failed to create power control handle");return ret;}host.pwr_ctrl_handle = pwr_ctrl_handle;sdmmc_slot_config_t slot_config = SDMMC_SLOT_CONFIG_DEFAULT();slot_config.width = 4;slot_config.flags |= SDMMC_SLOT_FLAG_INTERNAL_PULLUP;sdmmc_card_t *sd_card = (sdmmc_card_t *)malloc(sizeof(sdmmc_card_t));(*host.init)();ESP_ERROR_CHECK(sdmmc_host_init_slot(host.slot, (const sdmmc_slot_config_t *)&slot_config));while (sdmmc_card_init(&host, sd_card)) {ESP_LOGE(TAG, "The detection pin of the slot is disconnected(Insert uSD ""card). Retrying...");vTaskDelay(pdMS_TO_TICKS(1000));}sdmmc_card_print_info(stdout, sd_card);*card = sd_card;return ESP_OK;}const char *mount_point() { return MOUNT_POINT; }static constexpr char MOUNT_POINT[] = "/usb";
};// sdkconfig Enable Massive Storage Class (MSC) Option
// sdkconfig Enable Use FATFS volume label option to call f_setlabel function
extern "C" void app_main(void) {virtual_u_disk usb;usb.mount();
}

在这里插入图片描述


结论

本文详细讲解了如何基于ESP32和TinyUSB实现虚拟U盘功能,从USB描述符配置、MSC接口设置,到SD卡的初始化及文件系统的操作,都进行了全面的说明和代码解析。对于希望在嵌入式项目中实现USB大容量存储功能的开发者而言,这篇文章提供了一个从头到尾的实现思路。希望通过本文的学习,读者能够灵活运用这些技术,开发出符合实际需求的产品。

关键字:在线旅游网站平台有哪些_电商网站设计实例_100个裂变营销案例_百度seo怎么把关键词优化上去

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com

责任编辑: