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

Xamarin Forms Android与ESP32 USB串口通信读取数据实现咨询

Android端USB连接ESP32读取串口数据实现方案

你不需要直接操作/dev/bus/usb路径下的设备节点,Android系统的SELinux权限规则默认禁止普通应用直接访问这类节点,直接读写必然失败。你已经完成了USB设备枚举,剩下的流程只需要按照USB Host模式的标准流程走即可,和Windows下System.IO.Ports的使用逻辑差异不大。


1 前置权限配置

首先在你的Android项目AndroidManifest.xml里添加以下权限和特性声明:

<uses-feature android:name="android.hardware.usb.host" android:required="true" />
<uses-permission android:name="android.permission.USB_PERMISSION" />

枚举到目标ESP32设备后,必须先申请访问权限,没有授权的情况下任何USB操作都会被拒绝:

// 替换为你枚举到的目标ESP32设备实例
UsbDevice targetEsp32Device = null;
// 这里补全你之前的枚举逻辑,通过VID/PID匹配到ESP32后赋值给targetEsp32Device

private const string USB_PERMISSION_ACTION = "com.yourpackagename.USB_PERMISSION";
private UsbManager _usbManager;
private BroadcastReceiver _usbPermissionReceiver;

protected override void OnCreate(Bundle savedInstanceState)
{
    base.OnCreate(savedInstanceState);
    _usbManager = (UsbManager)GetSystemService(UsbService);
    
    // 注册权限申请结果广播
    _usbPermissionReceiver = new UsbPermissionReceiver(this);
    RegisterReceiver(_usbPermissionReceiver, new IntentFilter(USB_PERMISSION_ACTION));
    
    // 发起权限申请
    PendingIntent permissionIntent = PendingIntent.GetBroadcast(
        this, 
        0, 
        new Intent(USB_PERMISSION_ACTION), 
        PendingIntentFlags.Mutable
    );
    _usbManager.RequestPermission(targetEsp32Device, permissionIntent);
}

// 权限结果接收类
private class UsbPermissionReceiver : BroadcastReceiver
{
    private readonly MainActivity _activity;
    public UsbPermissionReceiver(MainActivity activity) => _activity = activity;

    public override void OnReceive(Context context, Intent intent)
    {
        if (intent.GetBooleanExtra(UsbManager.ExtraPermissionGranted, false))
        {
            _activity.OpenSerialPort(targetEsp32Device);
        }
    }
}

2 串口连接与数据读取

不需要自己解析USB CDC协议,直接安装NuGet包UsbSerialForAndroid即可,这个库封装了所有常见USB转串口芯片(CH340、CP2102、FTDI)以及原生CDC-ACM设备(ESP32原生USB串口)的驱动,API逻辑和Windows下的SerialPort高度相似。
拿到权限后调用以下方法初始化串口、读取数据:

private UsbSerialPort _serialPort;
private UsbDeviceConnection _connection;
private CancellationTokenSource _readCts;

private void OpenSerialPort(UsbDevice device)
{
    // 匹配设备驱动
    UsbSerialProber prober = UsbSerialProber.GetDefaultProber();
    UsbSerialDriver driver = prober.ProbeDevice(device);
    // 如果默认探针没识别到原生ESP32 USB CDC设备,手动创建CDC驱动
    driver ??= new CdcAcmSerialDriver(device, 0);

    _connection = _usbManager.OpenDevice(device);
    if (_connection == null) return;

    _serialPort = driver.Ports[0];
    _serialPort.Open(_connection);
    // 波特率、数据位、停止位、校验位必须和ESP32端输出配置完全一致
    _serialPort.SetParameters(
        baudRate: 115200, 
        dataBits: 8, 
        stopBits: UsbSerialPort.Stopbits1, 
        parity: UsbSerialPort.ParityNone
    );

    // 启动子线程循环读取数据
    _readCts = new CancellationTokenSource();
    _ = Task.Run(async () =>
    {
        byte[] buffer = new byte[4096];
        while (!_readCts.IsCancellationRequested && _serialPort.IsOpen)
        {
            try
            {
                int readLen = _serialPort.Read(buffer, 500); // 读超时500ms
                if (readLen > 0)
                {
                    string receivedData = Encoding.UTF8.GetString(buffer, 0, readLen);
                    // 此处处理接收到的RFID/iButton序列号
                    System.Diagnostics.Debug.WriteLine($"串口收到数据: {receivedData}");
                }
            }
            catch (Exception ex)
            {
                System.Diagnostics.Debug.WriteLine($"串口读取异常: {ex.Message}");
                break;
            }
        }
    }, _readCts.Token);
}

// 页面销毁时记得释放资源
protected override void OnDestroy()
{
    base.OnDestroy();
    _readCts?.Cancel();
    if (_serialPort?.IsOpen == true) _serialPort.Close();
    _connection?.Close();
    UnregisterReceiver(_usbPermissionReceiver);
}

3 常见问题说明

  • 不要尝试直接通过文件IO访问/dev/bus/usb/下的节点,普通应用没有该路径的访问权限,Android 10及以上版本的SELinux规则会直接拦截这类操作。
  • 如果收到乱码,优先检查两端串口参数是否匹配,尤其是波特率是否和ESP32代码中配置的一致。
  • 所有串口读写操作必须放在子线程执行,不能在主线程做阻塞式IO,否则会触发应用无响应(ANR)。
  • 如果是定制的自助终端Android系统,可以在系统设置中将你的App设置为USB设备默认处理应用,避免每次插入设备都弹出授权弹窗。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.01 23:45:35