You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

基于UsbSerialForAndroid的USB主机功能无法接收串口数据问题求助

问题描述

我用OTG线让搭载Android 9系统的moto e6 play作为USB主机对接AdaFruit Trinket M0。Trinket出厂默认上电后会循环发送串口文本字符串,我在Windows PC端用Putty连接该设备已经验证该功能正常。
我在手机端基于Xamarin移植的UsbSerialForAndroid编写代码,代码可以成功识别设备并打开端口,但收不到任何设备发来的串口数据。具体表现为UsbSerialPort.Read方法内的UsbDeviceConnection.RequestWait调用会永久阻塞,如果把RequestWait替换为1秒休眠操作,缓冲区里也没有任何数据。我也试过UsbSerialForAndroid支持的所有协议(包括CdcAcmSerialDriver等),都没有效果。另外手机会把Trinket识别为键盘设备,我原本认为这种情况不会影响其他代码访问该设备。
以下是简化后去掉错误检查的Xamarin代码:

usbManager = GetSystemService(Context.UsbService) as UsbManager;

var usbDevice = usbManager.DeviceList.ToList()[0].Value;

if (!usbManager.HasPermission(usbDevice))
   usbManager.RequestPermission(usbDevice, null);

var table = UsbSerialProber.DefaultProbeTable;

var type = typeof(Hoho.Android.UsbSerial.Driver.CdcAcmSerialDriver);
               
table.AddProduct(0x239A, 0x801F, type);

var prober = new UsbSerialProber(table);

var drivers = prober.FindAllDrivers(usbManager);

var driver = drivers[0];

UsbDeviceConnection connection = usbManager.OpenDevice(driver.GetDevice());

var ports = driver.GetPorts(); // 多数设备只有一个端口(端口0)

var port = ports[0]; // 多数设备只有一个端口(端口0)

port.Open(connection);

// 以下串口参数和我在Windows上用Putty成功连接的参数完全一致
port.SetParameters(9600, 8, Hoho.Android.UsbSerial.Driver.StopBits.One, UsbSerialPort.PARITY_NONE);

var bytes = new byte[32];

var len = port.Read(bytes, 32); // <-- 代码执行到这里会卡在RequestWait调用上
排查与解决方案
  • 处理系统设备占用问题:Android识别Trinket为键盘属于HID设备默认挂载,系统会优先持有该设备的访问权限,普通应用无法直接抢占,需要在port.Open(connection)之后添加代码强制抢占设备接口:
// 强制抢占设备所有接口,第二个参数设为true代表忽略系统内核驱动的占用
for (int i = 0; i < usbDevice.InterfaceCount; i++)
{
    connection.ClaimInterface(usbDevice.GetInterface(i), true);
}
  • 调整读操作超时配置:UsbSerialPort.Read方法默认无超时参数时会永久阻塞,给读调用添加超时参数即可避免卡死:
// 第二个参数为超时时间,单位毫秒,这里设置1000毫秒超时
var len = port.Read(bytes, 1000);
  • 修正端点识别配置:AdaFruit Trinket M0的USB串口使用TinyUSB实现的CDC-ACM协议,部分旧版UsbSerialForAndroid的CdcAcmSerialDriver对该设备的端点识别存在问题,可手动指定bulk in端点:
// 打开端口后手动设置输入端点,Trinket M0的CDC数据输入端点通常为0x81
var usbInterface = usbDevice.GetInterface(1);
var inEndpoint = usbInterface.GetEndpoint(0);
port.SetInEndpoint(inEndpoint);
  • 禁用系统HID输入拦截:在AndroidManifest.xml中添加USB设备访问过滤配置,避免系统将设备识别为输入设备后分发给输入服务占用:
<activity ...>
    <intent-filter>
        <action android:name="android.hardware.usb.action.USB_DEVICE_ATTACHED" />
    </intent-filter>
    <meta-data android:name="android.hardware.usb.action.USB_DEVICE_ATTACHED" android:resource="@xml/device_filter" />
</activity>

在res/xml目录下新建device_filter.xml,添加对应设备ID配置:

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <usb-device vendor-id="9114" product-id="32799" /> <!-- 对应十六进制0x239A、0x801F -->
</resources>

内容的提问来源于stack exchange,提问作者Digiproc

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.27 11:06:06