android-USB-STM32
usbDevice.getInterfaceCount()
usbDevice.getInterfaceCount() 这个方法返回该USB设备提供的接口(Interface)的数量。
一个USB设备就像一个公司,而接口(Interface) 就像是这个公司里的不同部门。每个部门有自己特定的功能和工作方式。
USB设备有几个接口?
一个USB设备至少有一个接口。
复杂的USB设备(如多功能打印机、集线器)可能有多个接口。
这完全取决于设备的类型和功能。对于你的STM32 CDC设备,答案很典型:通常是 2 个接口。
接口索引 | 接口类型 | 类代码 | 作用 | 比喻 |
接口 0 (管理接口) | 通信接口 (Control Interface) | USB_CLASS_COMM (2) | 管理连接。 用于设置波特率、数据位、流控等通信参数。 | 公司的行政部门。不处理具体业务,只负责制定规则和管理(如:我们公司今天9点上班,用中文沟通)。 |
接口 1 (数据接口) | 数据接口 (Data Interface) | USB_CLASS_CDC_DATA (10) | 传输数据。 所有实际要发送和接收的字节数据都通过这个接口。 | 公司的业务部门。真正干活的部门,按照行政部门定好的规则进行实际工作(如:销售部根据"用中文沟通"的规则去谈客户) |
如何用代码找到正确的接口?
在你的Android代码中,你需要遍历所有接口,找到那个真正用于数据传输的数据接口。
// 遍历设备的所有接口
for (i in 0 until usbDevice.interfaceCount) {val usbIf = usbDevice.getInterface(i)// 打印接口信息用于调试(非常重要!)Log.d("USB", "接口索引: $i")Log.d("USB", "接口类: ${usbIf.interfaceClass}")Log.d("USB", "接口子类: ${usbIf.interfaceSubclass}")Log.d("USB", "接口协议: ${usbIf.interfaceProtocol}")// 寻找CDC数据接口:类代码为 10 (0x0A)if (usbIf.interfaceClass == UsbConstants.USB_CLASS_CDC_DATA) { // USB_CLASS_CDC_DATA = 10usbInterface = usbIf // 这就是我们要找的"业务部门"!Log.d("USB", "找到数据接口!")break}
}
找到了接口,然后呢?端点是做什么的?
找到了正确的接口(部门)后,还需要找到这个部门里的具体工作人员,这就是端点(Endpoint)。
每个接口可以有多个端点。
端点是数据通信的最终目的地。
端点有方向:
UsbConstants.USB_DIR_OUT
(0): 输出,主机→设备 (Android→STM32)UsbConstants.USB_DIR_IN
(128): 输入,设备→主机 (STM32→Android)
端点有类型:
- 批量传输(Bulk Transfer): 用于大量、可靠的数据传输(文件、串行数据)。你的项目就用这种。
- 中断传输(Interrupt Transfer): 用于频繁、小量、保证延迟的数据(鼠标、键盘)。
- 等时传输(Isochronous Transfer): 用于实时数据流(音频、视频),可能丢失数据但保证速度。
在你的STM32 CDC设备的数据接口中,通常有2个端点:
一个
Bulk Out
端点(用于Android发送数据给STM32)一个
Bulk In
端点(用于STM32发送数据给Android)
查找端点的代码:
usbInterface?.let { interface ->// 遍历该接口的所有端点for (i in 0 until interface.endpointCount) {val ep = interface.getEndpoint(i)when (ep.direction) {UsbConstants.USB_DIR_OUT -> {// 找到输出端点,用于发送数据给STM32endpointOut = epLog.d("USB", "找到Bulk Out端点: 地址=${ep.address}")}UsbConstants.USB_DIR_IN -> {// 找到输入端点,用于接收来自STM32的数据endpointIn = epLog.d("USB", "找到Bulk In端点: 地址=${ep.address}")}}}
}