ARTICLE DETAIL

建站实战干货

来自一线的建站与推广经验沉淀,每一条都经过真实交付验证。

ESP IoT Solution 中 USB 主机 CDC 驱动(iot_usbh_cdc)使用指南:从热插拔匹配到数据收发

2026/9/20 3:45:02 拓冰建站 浏览量
ESP IoT Solution 中 USB 主机 CDC 驱动(iot_usbh_cdc)使用指南:从热插拔匹配到数据收发 ESP IoT Solution 中 USB 主机 CDC 驱动iot_usbh_cdc使用指南从热插拔匹配到数据收发【免费下载链接】esp-iot-solutionEspressif IoT Library. IoT Device Drivers, Documentations and Solutions.项目地址: https://gitcode.com/GitHub_Trending/es/esp-iot-solutioniot_usbh_cdc是 ESP IoT Solution 提供的一个简化版 USB 主机 CDCCommunications Device Class驱动组件它让 ESP32 系列芯片能以 USB 主机身份连接并通信各类 CDC 设备如 4G 模块、USB 串口、AT 指令设备等。本文基于 USB 主机 CDC 文档 并结合仓库源码完整讲解驱动的安装配置、设备匹配、端口打开、数据收发、描述符支持范围与典型注意事项帮助你快速在自己的应用中集成 USB CDC 主机功能。组件概览与核心特性iot_usbh_cdc组件位于仓库的 components/usb/iot_usbh_cdc 目录核心源文件为 iot_usbh_cdc.c对外头文件为 iot_usbh_cdc.h。根据组件 README.md 与源码实现该组件具备以下特性支持标准 USB CDC 设备如 USB 转串口、CDC-ACM 设备支持厂商自定义Vendor Specific的 CDC 设备描述符如手机/模块的 Mobile AT Interface支持 CDC 多接口multiple interface可在同一设备上打开多个端口支持通过 USB HUB 连接多个 USB 设备内置热插拔事件处理设备连接/断开时自动回调通知可选启用内部环形缓冲区ringbuffer简化数据收发降低应用层对时序的依赖驱动内部可直接完成 USB Host Driver 协议栈的初始化也可跳过初始化与其他 USB 驱动共存。从源码结构看组件内部维护了三类核心对象见 iot_usbh_cdc.c全局驱动对象usbh_cdc_obj_t持有 USB Host client 句柄、事件组、互斥锁及设备/端口链表、设备对象usbh_cdc_dev_t封装设备句柄与控制传输、端口对象usbh_cdc_port_t封装通知/数据端点传输与收发环形缓冲区。添加组件依赖在使用组件管理器IDF Component Manager的工程中执行以下命令即可将组件加入依赖CMake 阶段会自动下载idf.py add-dependency espressif/iot_usbh_cdc*也可以使用create-project-from-example直接基于官方示例模板创建工程idf.py create-project-from-example espressif/iot_usbh_cdc*:usb_cdc_basic仓库自带的完整可运行示例位于 examples/usb/host/usb_cdc_basic此外还有面向 4G 模块的 examples/usb/host/usb_cdc_4g_module 可作为实战参考。安装驱动并初始化 USB Host Driver 协议栈安装驱动使用usbh_cdc_driver_install参数为usbh_cdc_driver_config_t配置结构。原文档给出的最小配置如下/* 安装 USB CDC 驱动并由驱动内部初始化好 USB Host Driver 协议栈 */ usbh_cdc_driver_config_t config { .task_stack_size 1024 * 4, .task_priority 5, .task_coreid 0, .skip_init_usb_host_driver false, }; usbh_cdc_driver_install(config);各配置字段的含义与取值范围依据 iot_usbh_cdc.h 与 Kconfig配置字段含义说明task_stack_size驱动任务栈大小字节示例中使用1024 * 4需满足驱动内部usbh_cdc_client_task的运行需求task_priority驱动任务优先级示例中使用 5Kconfig 中USBH_TASK_BASE_PRIORITY默认值为 5task_coreid驱动任务绑定的核心设为-1表示不指定核心tskNO_AFFINITY示例中使用 0Kconfig 中USBH_TASK_CORE_ID默认 0范围 -1~1skip_init_usb_host_driver是否跳过 USB Host Driver 初始化false时由驱动内部初始化协议栈true时跳过适用于其他驱动已初始化的情况关键点skip_init_usb_host_driver的使用场景。当你的应用中还有其他 USB 驱动例如 USB MSC、UVC、RNDIS 等也需要使用 USB Host Driver 协议栈时应将此配置项置为true以避免重复初始化。从源码看iot_usbh_cdc.c当该选项为false时驱动会创建名为usb_lib的任务该任务内部通过usb_host_lib_info检查协议栈是否已被其他模块安装若未安装则以usb_host_install完成初始化若已安装则直接复用。整个安装流程还包括分配驱动对象、创建事件组与互斥锁、创建usbh_cdc客户端任务、注册 USB Host clientusb_host_client_register。驱动安装失败的返回值定义在 iot_usbh_cdc.hESP_ERR_INVALID_ARG配置参数为 NULL 或参数非法ESP_ERR_INVALID_STATE驱动已被安装重复调用ESP_ERR_NO_MEM内存分配失败ESP_FAIL任务创建失败或 USB Host 初始化失败。注册设备事件回调与设备匹配列表设备热插拔通过usbh_cdc_register_dev_event_cb注册回调实现。该函数接收三个参数设备匹配列表dev_match_id_list、事件回调event_cb、用户数据user_data。static void device_event_cb(usbh_cdc_device_event_t event, usbh_cdc_device_event_data_t *event_data, void *user_ctx) { switch (event) { case CDC_HOST_DEVICE_EVENT_CONNECTED: { ESP_LOGI(TAG, Device connected: dev_addr%d, matched_intf_num%d, event_data-new_dev.dev_addr, event_data-new_dev.matched_intf_num); /* 在此处根据应用需要打开一个或多个端口 */ } break; case CDC_HOST_DEVICE_EVENT_DISCONNECTED: ESP_LOGI(TAG, Device disconnected: dev_addr%d, dev_hdl%p, event_data-dev_gone.dev_addr, event_data-dev_gone.dev_hdl); break; default: break; } } const static usb_device_match_id_t match_id_list[] { { .match_flags USB_DEVICE_ID_MATCH_VENDOR | USB_DEVICE_ID_MATCH_PRODUCT, .idVendor USB_DEVICE_VENDOR_ANY, .idProduct USB_DEVICE_PRODUCT_ANY, }, { 0 } }; usbh_cdc_register_dev_event_cb(match_id_list, device_event_cb, NULL);关于dev_match_id_list的规范原文档明确说明数组不能位于栈上必须是静态或全局存储因为驱动内部会保存该指针供后续匹配使用见 iot_usbh_cdc.c必须以空项结尾示例中的{ 0 }驱动遍历列表时以此判断结束数组中的每一项都是一组匹配条件满足任一条件即触发回调使用USB_DEVICE_VENDOR_ANY值为 0与USB_DEVICE_PRODUCT_ANY值为 0可匹配所有设备指定具体idVendor/idProduct则可精确匹配特定厂商与产品。更丰富的匹配条件通过match_flags可以组合更多匹配维度完整的标志位定义在 usbh_helper.h匹配标志含义USB_DEVICE_ID_MATCH_VENDOR匹配设备描述符的 idVendorUSB_DEVICE_ID_MATCH_PRODUCT匹配设备描述符的 idProductUSB_DEVICE_ID_MATCH_DEV_BCD匹配设备版本号 bcdDeviceUSB_DEVICE_ID_MATCH_DEV_CLASS/DEV_SUBCLASS/DEV_PROTOCOL匹配设备描述符中的类/子类/协议USB_DEVICE_ID_MATCH_INT_CLASS/INT_SUBCLASS/INT_PROTOCOL匹配接口描述符中的类/子类/协议USB_DEVICE_ID_MATCH_INT_NUMBER匹配接口编号USB_DEVICE_ID_MATCH_ALL匹配所有字段0xFFFF对应的匹配结构体usb_device_match_id_t与匹配辅助函数usbh_match_device、usbh_match_interface、usbh_match_id_from_list等也在 usbh_helper.h 中提供可被其他 USB 驱动复用。若想匹配任意设备可直接使用组件导出的预置列表宏ESP_USB_DEVICE_MATCH_ID_ANY——官方示例 usb_cdc_basic_main.c 正是这样使用的。回调中的事件数据与死锁警示事件数据联合体usbh_cdc_device_event_data_t定义在 iot_usbh_cdc.h连接事件携带dev_addr设备地址、matched_intf_num匹配到的接口编号-1 表示无效、device_desc设备描述符指针、active_config_desc活动配置描述符指针断开事件携带dev_addr与dev_hdl设备句柄。重要限制device_event_cb回调运行在 USB 任务上下文中不允许在其中调用usbh_cdc_write_bytes等与设备通信的函数否则会导致死锁。正确的做法是在回调中创建一个新任务或通过事件组/队列发送事件到应用任务由应用任务执行实际的设备通信。官方示例中正是采用这一模式连接回调内只做usbh_cdc_port_open和创建cdc_task见 usb_cdc_basic_main.c数据收发全部放在独立任务中完成。驱动还提供了usbh_cdc_unregister_dev_event_cb用于注销回调usbh_cdc_driver_uninstall调用时也会自动清理所有已注册的回调。打开 CDC 端口当设备匹配成功并触发CDC_HOST_DEVICE_EVENT_CONNECTED事件后即可在回调中通过usbh_cdc_port_open打开设备的一个或多个端口进行通信。usbh_cdc_port_config_t是端口配置的核心结构定义见 iot_usbh_cdc.husbh_cdc_port_handle_t cdc_port NULL; usbh_cdc_port_config_t cdc_port_config { .dev_addr event_data-new_dev.dev_addr, .itf_num 0, .in_transfer_buffer_size 512, .out_transfer_buffer_size 512, .cbs { .notif_cb NULL, .recv_data NULL, .closed NULL, .user_data NULL, }, }; usbh_cdc_port_open(cdc_port_config, cdc_port);各字段说明字段含义dev_addrCDC 设备的设备地址取自事件数据new_dev.dev_addritf_num要打开的接口编号对应设备配置描述符中的 bInterfaceNumberin_ringbuf_size接收环形缓冲区大小设为 0 表示不使用接收 ringbufferout_ringbuf_size发送环形缓冲区大小设为 0 表示不使用发送 ringbufferin_transfer_buffer_sizeIN 传输缓冲区大小接收不能为 0源码中会校验见 iot_usbh_cdc.cout_transfer_buffer_sizeOUT 传输缓冲区大小发送不能为 0cbs端口事件回调集合见下文flags端口配置标志如USBH_CDC_FLAGS_DISABLE_NOTIFICATION端口回调集合usbh_cdc_port_event_callbacks_t提供三个可选回调均可置 NULLclosed端口关闭时回调recv_data收到数据时回调通知应用有数据就绪notif_cb收到 CDC 通知如串口状态、网络连接状态、速率变化时回调参数为iot_cdc_notification_t *notif其中bNotificationCode可取USB_CDC_NOTIFY_NETWORK_CONNECTION、USB_CDC_NOTIFY_SERIAL_STATE、USB_CDC_NOTIFY_SPEED_CHANGE等定义见 iot_usbh_cdc_type.hData负载可解析为usb_cdc_serial_state_t位域结构查看 DCD/DSR/break/ring 及各类错误位user_data透传给以上回调的用户数据指针。官方示例展示了recv_data与notif_cb的典型用法usb_cdc_basic_main.c接收回调中先usbh_cdc_get_rx_buffer_size查询数据量再usbh_cdc_read_bytes读取通知回调则分别处理网络连接变化、链路速率和串口状态事件。示例还演示了在同一设备上打开多个接口端口通过EXAMPLE_BULK_ITF_NUM控制同时打开接口 0 和接口 1这正是组件多接口能力的直接体现。从源码实现看usbh_cdc_port_open的完整流程包括校验参数、检查端口是否重复打开、按地址查找/新建设备对象、解析接口描述符cdc_parse_interface_descriptor、按需创建收发 ringbuffer、分配并配置三个 USB 传输通知 INTR 端点、BULK IN 端点、BULK OUT 端点、claim 数据接口必要时同时 claim 通知接口、提交 BULK IN 与 INTR IN 轮询传输最后通过usb_host_client_unblock唤醒客户端任务见 iot_usbh_cdc.c。数据收发接收、发送与环形缓冲区端口打开后主机会自动从 CDC 设备接收 USB 数据到 USB 缓冲区应用层有两种获取数据的方式轮询方式调用usbh_cdc_get_rx_buffer_size查询接收缓冲区中已就绪的数据大小然后调用usbh_cdc_read_bytes读取回调方式注册recv_data回调数据就绪时驱动自动通知。/* 查询并读取接收数据 */ size_t data_len 0; usbh_cdc_get_rx_buffer_size(cdc_port, data_len); if (data_len 0) { data_len data_len sizeof(buf) ? sizeof(buf) : data_len; usbh_cdc_read_bytes(cdc_port, buf, data_len, 0); }in_ringbuf_size的作用当in_ringbuf_size大于 0 时驱动会创建内部接收 ringbufferIN 传输完成的数据先缓存到 ringbuffer 中应用层随时可取接收时机灵活从源码可见ringbuffer 满时新数据会被丢弃并打印告警iot_usbh_cdc.c因此应根据实际吞吐量合理设置大小。当in_ringbuf_size为 0 时不使用 ringbuffer此时建议在recv_data回调中直接调用usbh_cdc_read_bytes文档与头文件注释均如此建议且读取长度必须等于内部传输缓冲区大小否则返回ESP_ERR_INVALID_ARG见 iot_usbh_cdc.h。发送数据使用usbh_cdc_write_bytesusbh_cdc_write_bytes(cdc_port, (uint8_t *)buff, len, pdMS_TO_TICKS(100));当out_ringbuf_size大于 0 时数据会先写入内部发送 ringbuffer由驱动后台逐步提交到 OUT 传输当其为 0 时数据直接通过 OUT 传输发送到设备此时可通过ticks_to_wait实现阻塞式写入。官方示例即以usbh_cdc_write_bytes周期性地向 4G 模块发送AT\r\n指令usb_cdc_basic_main.c。此外组件还提供以下辅助 APIusbh_cdc_flush_rx_buffer/usbh_cdc_flush_tx_buffer清空收发缓冲区仅 ringbuffer 模式支持非 ringbuffer 模式返回ESP_ERR_NOT_SUPPORTEDusbh_cdc_send_custom_request向设备发送自定义控制请求支持 IN/OUT 双向可用于读取字符串描述符、设置线路编码等标准请求之外的场景usbh_cdc_desc_print打印设备与配置描述符便于调试usbh_cdc_get_dev_handle获取底层 USB 设备句柄可配合usb_host_get_device_descriptor、usb_host_get_active_config_descriptor使用usbh_cdc_port_get_intf_desc获取解析后的通知接口与数据接口描述符。热插拔异步性的注意事项由于 USB 设备热插拔是异步的设备可能在运行时的任何时刻被拔出。调用usbh_cdc_write_bytes、usbh_cdc_read_bytes等函数前必须确认设备仍连接且端口已打开否则这些函数会返回错误通常为ESP_ERR_INVALID_STATE。从源码看当设备断开USB_HOST_CLIENT_EVENT_DEV_GONE时驱动会自动关闭该设备上的所有端口并回调CDC_HOST_DEVICE_EVENT_DISCONNECTED事件iot_usbh_cdc.c应用应在此事件中清理状态、置空端口句柄。官方示例使用事件组USB_DEV_DISCONNECTED_BIT通知发送任务退出循环避免对已断开设备继续写入usb_cdc_basic_main.c。关闭端口与卸载驱动使用usbh_cdc_port_close关闭已打开的端口并释放其资源。关闭流程见 iot_usbh_cdc.c包括置位to_close标志、注销端口回调、重置相关端点、释放 claim 的接口、释放传输与 ringbuffer并且当该设备上所有端口都已关闭时自动关闭底层 USB 设备并释放设备对象。使用usbh_cdc_driver_uninstall可完全卸载驱动并释放所有资源。需要注意当仍有设备连接时无法直接卸载会返回ESP_ERR_INVALID_STATE源码中会检查cdc_devices_list是否为空见 iot_usbh_cdc.c必须先关闭所有设备卸载过程中会通过事件组CDC_TEARDOWN通知客户端任务退出并等待CDC_TEARDOWN_COMPLETE随后注销 USB Host client、释放驱动对象超时会返回ESP_ERR_NOT_FINISHED。支持的 CDC 设备描述符驱动支持以下标准 CDC 设备描述符布局典型 CDC-ACM 设备含 IAD 描述符 通知接口 数据接口------------------- IAD Descriptor -------------------- bLength : 0x08 (8 bytes) bDescriptorType : 0x0B (Interface Association Descriptor) bFirstInterface : 0x00 (Interface 0) bInterfaceCount : 0x02 (2 Interfaces) bFunctionClass : 0x02 (Communications and CDC Control) bFunctionSubClass : 0x06 bFunctionProtocol : 0x00 iFunction : 0x07 (String Descriptor 7) Language 0x0409 : ---------------- Interface Descriptor ----------------- bLength : 0x09 (9 bytes) bDescriptorType : 0x04 (Interface Descriptor) bInterfaceNumber : 0x00 (Interface 0) bAlternateSetting : 0x00 bNumEndpoints : 0x01 (1 Endpoint) bInterfaceClass : 0x02 (Communications and CDC Control) bInterfaceSubClass : 0x06 (Ethernet Networking Control Model) bInterfaceProtocol : 0x00 (No class specific protocol required) iInterface : 0x07 (String Descriptor 7) Language 0x0409 : ----------------- Endpoint Descriptor ----------------- bLength : 0x07 (7 bytes) bDescriptorType : 0x05 (Endpoint Descriptor) bEndpointAddress : 0x87 (DirectionIN EndpointID7) bmAttributes : 0x03 (TransferTypeInterrupt) wMaxPacketSize : 0x0020 Bits 15..13 : 0x00 (reserved, must be zero) Bits 12..11 : 0x00 (0 additional transactions per microframe - allows 1..1024 bytes per packet) Bits 10..0 : 0x20 (32 bytes per packet) bInterval : 0x09 (256 microframes - 32 ms) ---------------- Interface Descriptor ----------------- bLength : 0x09 (9 bytes) bDescriptorType : 0x04 (Interface Descriptor) bInterfaceNumber : 0x01 (Interface 1) bAlternateSetting : 0x00 bNumEndpoints : 0x00 (Default Control Pipe only) bInterfaceClass : 0x0A (CDC-Data) bInterfaceSubClass : 0x00 bInterfaceProtocol : 0x00 iInterface : 0x00 (No String Descriptor) ---------------- Interface Descriptor ----------------- bLength : 0x09 (9 bytes) bDescriptorType : 0x04 (Interface Descriptor) bInterfaceNumber : 0x01 (Interface 1) bAlternateSetting : 0x01 bNumEndpoints : 0x02 (2 Endpoints) bInterfaceClass : 0x0A (CDC-Data) bInterfaceSubClass : 0x00 bInterfaceProtocol : 0x00 iInterface : 0x00 (No String Descriptor) ----------------- Endpoint Descriptor ----------------- bLength : 0x07 (7 bytes) bDescriptorType : 0x05 (Endpoint Descriptor) bEndpointAddress : 0x0C (DirectionOUT EndpointID12) bmAttributes : 0x02 (TransferTypeBulk) wMaxPacketSize : 0x0200 (max 512 bytes) bInterval : 0x00 (never NAKs) ----------------- Endpoint Descriptor ----------------- bLength : 0x07 (7 bytes) bDescriptorType : 0x05 (Endpoint Descriptor) bEndpointAddress : 0x83 (DirectionIN EndpointID3) bmAttributes : 0x02 (TransferTypeBulk) wMaxPacketSize : 0x0200 (max 512 bytes) bInterval : 0x00 (never NAKs)该布局的特征IAD 将两个接口通知接口 数据接口关联为一个功能通知接口含 1 个 IN 中断端点用于接收 CDC 通知如串口状态、网络状态数据接口的激活备选设置bAlternateSetting 1含 1 个 IN 批量端点和 1 个 OUT 批量端点用于数据传输。驱动同时支持部分厂商自定义的 CDC 设备描述符典型例子如下一个接口内同时包含中断、IN 批量、OUT 批量三种端点接口类为 0xFF 厂商特定常见于手机 Modem 的 Mobile AT Interface---------------- Interface Descriptor ----------------- bLength : 0x09 (9 bytes) bDescriptorType : 0x04 (Interface Descriptor) bInterfaceNumber : 0x03 (Interface 3) bAlternateSetting : 0x00 bNumEndpoints : 0x03 (3 Endpoints) bInterfaceClass : 0xFF (Vendor Specific) bInterfaceSubClass : 0x00 bInterfaceProtocol : 0x00 iInterface : 0x09 (String Descriptor 9) Language 0x0409 : Mobile AT Interface ----------------- Endpoint Descriptor ----------------- bLength : 0x07 (7 bytes) bDescriptorType : 0x05 (Endpoint Descriptor) bEndpointAddress : 0x85 (DirectionIN EndpointID5) bmAttributes : 0x03 (TransferTypeInterrupt) wMaxPacketSize : 0x0010 Bits 15..13 : 0x00 (reserved, must be zero) Bits 12..11 : 0x00 (0 additional transactions per microframe - allows 1..1024 bytes per packet) Bits 10..0 : 0x10 (16 bytes per packet) bInterval : 0x09 (256 microframes - 32 ms) ----------------- Endpoint Descriptor ----------------- bLength : 0x07 (7 bytes) bDescriptorType : 0x05 (Endpoint Descriptor) bEndpointAddress : 0x82 (DirectionIN EndpointID2) bmAttributes : 0x02 (TransferTypeBulk) wMaxPacketSize : 0x0200 (max 512 bytes) bInterval : 0x00 (never NAKs) ----------------- Endpoint Descriptor ----------------- bLength : 0x07 (7 bytes) bDescriptorType : 0x05 (Endpoint Descriptor) bEndpointAddress : 0x0B (DirectionOUT EndpointID11) bmAttributes : 0x02 (TransferTypeBulk) wMaxPacketSize : 0x0200 (max 512 bytes) bInterval : 0x00 (never NAKs)从描述符解析源码iot_usbh_descriptor.c可以印证支持的判定逻辑标准 CDC 设备通过“设备类为每接口/通信类且接口类为 0x02CDC 控制”或“复合设备使用 IAD 且bFirstInterface匹配、bInterfaceCount为 2”来识别厂商自定义类型则解析接口内的中断、IN 批量、OUT 批量三类端点。相关类型常量通信类子类、协议码、CDC 请求码、功能描述符结构等统一定义在 iot_usbh_cdc_type.h。多设备与 USB HUB 场景下的注意事项组件支持通过 USB HUB 连接多个 USB 设备驱动内部会跳过 HUB 设备本身见 iot_usbh_cdc.c。但需注意在使用 USB HUB 连接多个设备时如果出现主机的 channel 不够用的情况可以通过usbh_cdc_port_config_t的flags打开USBH_CDC_FLAGS_DISABLE_NOTIFICATION标志位强制禁用中断通知端点从而减少一个 channel 的使用。如果设备本身就没有中断端点则该标志无效。启用方式usbh_cdc_port_config_t cdc_port_config { .dev_addr event_data-new_dev.dev_addr, .itf_num 0, .in_transfer_buffer_size 512, .out_transfer_buffer_size 512, .flags USBH_CDC_FLAGS_DISABLE_NOTIFICATION, /* 禁用通知端点节省一个 channel */ .cbs { 0 }, };从源码看该标志在usbh_cdc_port_open中会将解析出的通知端点强制置空iot_usbh_cdc.c从而跳过中断端点的 claim 与轮询传输分配代价是notif_cb通知将不再工作。Kconfig 可调参数组件提供若干 Kconfig 编译期配置见 Kconfig可在menuconfig的 IoT USB Host CDC 菜单下调整配置项默认值作用USBH_TASK_CORE_ID0内部 USB Host 库任务绑定的核心范围 -1~1-1 不指定USBH_TASK_BASE_PRIORITY5内部 USB Host 库任务基础优先级USBH_CDC_CONTROL_TRANSFER_BUFFER_SIZE256控制传输缓冲区大小字节USBH_CDC_IN_EP_RETRY_COUNT3IN 端点传输失败后的重试次数超过后停止传输完整实战从安装到 AT 指令通信综合上述 API一个典型的 USB CDC 主机应用以连接 4G 模块发送 AT 指令为例的骨架如下/* 1. 安装驱动 */ usbh_cdc_driver_config_t driver_cfg { .task_stack_size 1024 * 4, .task_priority 5, .task_coreid 0, .skip_init_usb_host_driver false, }; usbh_cdc_driver_install(driver_cfg); /* 2. 注册设备事件回调匹配所有设备可改为指定 VID/PID */ usbh_cdc_register_dev_event_cb(ESP_USB_DEVICE_MATCH_ID_ANY, device_event_cb, NULL); /* 3. 在连接回调中打开端口并在独立任务中收发数据 */ static void device_event_cb(usbh_cdc_device_event_t event, usbh_cdc_device_event_data_t *event_data, void *ctx) { if (event CDC_HOST_DEVICE_EVENT_CONNECTED) { usbh_cdc_port_config_t port_cfg { .dev_addr event_data-new_dev.dev_addr, .itf_num 1, /* 数据接口编号 */ .in_ringbuf_size 2048, /* 启用接收 ringbuffer */ .out_ringbuf_size 2048, /* 启用发送 ringbuffer */ .in_transfer_buffer_size 512, .out_transfer_buffer_size 512, .cbs { .recv_data recv_cb, /* 数据就绪通知 */ .notif_cb notif_cb, /* CDC 通知 */ .user_data NULL, }, }; usbh_cdc_port_open(port_cfg, g_port); /* 打开端口 */ xTaskCreate(data_task, cdc_task, 4096, NULL, 5, NULL); /* 独立任务通信 */ } else if (event CDC_HOST_DEVICE_EVENT_DISCONNECTED) { g_port NULL; /* 清理状态 */ } } /* 4. 应用任务中发送数据 */ static void data_task(void *arg) { char cmd[] AT\r\n; while (g_port) { usbh_cdc_write_bytes(g_port, (uint8_t *)cmd, strlen(cmd), pdMS_TO_TICKS(100)); vTaskDelay(pdMS_TO_TICKS(1000)); } vTaskDelete(NULL); } /* 5. 接收回调中读取数据 */ static void recv_cb(usbh_cdc_port_handle_t port, void *arg) { uint8_t buf[256]; size_t len 0; usbh_cdc_get_rx_buffer_size(port, len); if (len 0) { len len sizeof(buf) ? sizeof(buf) : len; usbh_cdc_read_bytes(port, buf, len, 0); ESP_LOGI(TAG, recv %d bytes, len); } }完整的可编译示例请参考 examples/usb/host/usb_cdc_basic主逻辑见 usb_cdc_basic_main.c含 ESP32-S3 USB-OTG 引脚模式切换的硬件初始化代码以及 4G 模块场景的 examples/usb/host/usb_cdc_4g_module。组件的单元测试含设备事件、读写、多接口等用例位于 components/usb/iot_usbh_cdc/test_apps可作为 API 行为边界的补充参考。小结iot_usbh_cdc将 ESP-IDF 底层 USB Host 协议栈的 client 注册、设备枚举、接口 claim、传输轮询等繁琐流程封装为简洁的安装—注册—打开—收发四步模型同时通过匹配列表、事件回调、可选 ringbuffer 与端口回调兼顾了热插拔灵活性、多设备扩展性与易用性。实际开发中重点把握三件事其一dev_match_id_list必须是静态数组且以空项结尾其二设备事件回调中禁止直接通信应转移到独立任务其三正确评估 ringbuffer 是否启用以及USBH_CDC_FLAGS_DISABLE_NOTIFICATION在 HUB 多设备场景下的取舍即可稳定地将 USB CDC 设备接入 ESP32 应用。【免费下载链接】esp-iot-solutionEspressif IoT Library. IoT Device Drivers, Documentations and Solutions.项目地址: https://gitcode.com/GitHub_Trending/es/esp-iot-solution创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考