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

Android USB串口通信问题:仅回显发送的数据

USB串口通信收到回发数据的问题排查与修复

问题描述

使用usb-serial-for-android库与USB设备通信,能够检测设备、打开端口并发送数据,但接收的数据始终是刚发送的内容。

代码中的关键问题点

1. 权限请求的死循环错误

代码中用while (!manager.hasPermission(device)) { manager.requestPermission(device, pendingIntent); }的死循环请求权限,这是错误的:

  • requestPermission是异步操作,不会立刻返回权限结果,死循环会导致CPU占用过高,甚至应用无响应。
  • 正确做法是通过广播接收器接收权限申请结果,而非同步等待。

2. 主线程执行耗时操作

直接在主线程调用Thread.sleep(1000)以及串口打开、数据发送等操作,会触发应用无响应(ANR),所有硬件交互必须放在子线程中执行。

3. 发送冗余空字节

request数组以端口最大包大小初始化,但仅填充前6个有效字节,发送时会将整个数组(含大量空字节)发给设备,可能导致设备无法正常响应,甚至触发硬件回环。

4. 串口参数匹配问题

需确认设备实际的串口参数(波特率、停止位、奇偶校验)是否与代码中port.setParameters(1200, 8, UsbSerialPort.STOPBITS_2, UsbSerialPort.PARITY_NONE)完全一致,参数不匹配会导致通信异常。

修复方案

步骤1:替换权限请求逻辑,使用广播接收器

private static final String ACTION_USB_PERMISSION = "com.your.package.USB_PERMISSION";
private BroadcastReceiver usbPermissionReceiver;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    
    // 注册权限广播接收器
    usbPermissionReceiver = new BroadcastReceiver() {
        @Override
        public void onReceive(Context context, Intent intent) {
            String action = intent.getAction();
            if (ACTION_USB_PERMISSION.equals(action)) {
                synchronized (this) {
                    UsbDevice device = intent.getParcelableExtra(UsbManager.EXTRA_DEVICE);
                    if (intent.getBooleanExtra(UsbManager.EXTRA_PERMISSION_GRANTED, false)) {
                        if (device != null) {
                            // 权限获取成功,在子线程处理设备连接
                            new Thread(() -> connectToDevice(device)).start();
                        }
                    } else {
                        runOnUiThread(() -> Toast.makeText(context, "USB权限被拒绝", Toast.LENGTH_SHORT).show());
                    }
                }
            }
        }
    };
    IntentFilter filter = new IntentFilter(ACTION_USB_PERMISSION);
    registerReceiver(usbPermissionReceiver, filter);
    
    // 初始化设备检测
    initUsbDeviceDetection();
}

private void initUsbDeviceDetection() {
    UsbManager manager = (UsbManager) getSystemService(Context.USB_SERVICE);
    UsbSerialProber usbDefaultProber = UsbSerialProber.getDefaultProber();
    HashMap<String, UsbDevice> deviceList = manager.getDeviceList();
    
    if (deviceList.isEmpty()) {
        runOnUiThread(() -> {
            Toast.makeText(this, "未检测到USB设备", Toast.LENGTH_LONG).show();
            infos.setText("未检测到USB设备");
        });
        spinner.setVisibility(View.GONE);
        return;
    }
    
    for (UsbDevice device : deviceList.values()) {
        runOnUiThread(() -> {
            Toast.makeText(this, "检测到设备:" + device.getProductName(), Toast.LENGTH_LONG).show();
            Toast.makeText(this, "设备信息:VendorId=" + device.getVendorId() + " ProductId=" + device.getProductId(), Toast.LENGTH_LONG).show();
        });
        
        UsbSerialDriver driver = usbDefaultProber.probeDevice(device);
        if (driver == null) {
            ProbeTable customTable = new ProbeTable();
            customTable.addProduct(device.getVendorId(), device.getProductId(), Cp21xxSerialDriver.class);
            UsbSerialProber customProber = new UsbSerialProber(customTable);
            driver = customProber.probeDevice(device);
        }
        
        if (driver != null) {
            // 请求权限
            PendingIntent pendingIntent;
            if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
                pendingIntent = PendingIntent.getBroadcast(this, 0, new Intent(ACTION_USB_PERMISSION), PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_MUTABLE);
            } else {
                pendingIntent = PendingIntent.getBroadcast(this, 0, new Intent(ACTION_USB_PERMISSION), PendingIntent.FLAG_UPDATE_CURRENT);
            }
            manager.requestPermission(device, pendingIntent);
        } else {
            runOnUiThread(() -> Toast.makeText(this, "无可用驱动", Toast.LENGTH_LONG).show());
            spinner.setVisibility(View.GONE);
        }
    }
}

步骤2:在子线程中处理设备连接与数据发送

private void connectToDevice(UsbDevice device) {
    UsbManager manager = (UsbManager) getSystemService(Context.USB_SERVICE);
    UsbSerialProber usbDefaultProber = UsbSerialProber.getDefaultProber();
    UsbSerialDriver driver = usbDefaultProber.probeDevice(device);
    
    if (driver == null) {
        ProbeTable customTable = new ProbeTable();
        customTable.addProduct(device.getVendorId(), device.getProductId(), Cp21xxSerialDriver.class);
        UsbSerialProber customProber = new UsbSerialProber(customTable);
        driver = customProber.probeDevice(device);
    }
    
    if (driver == null) {
        runOnUiThread(() -> Toast.makeText(this, "无可用驱动", Toast.LENGTH_LONG).show());
        spinner.setVisibility(View.GONE);
        return;
    }
    
    try {
        UsbDeviceConnection connection = manager.openDevice(device);
        if (connection == null) {
            runOnUiThread(() -> Toast.makeText(this, "无法建立连接", Toast.LENGTH_LONG).show());
            spinner.setVisibility(View.GONE);
            return;
        }
        
        runOnUiThread(() -> {
            infos.setText("发送数据中...");
            Toast.makeText(this, "发送数据中...", Toast.LENGTH_LONG).show();
        });
        
        UsbSerialPort port = driver.getPorts().get(0);
        port.open(connection);
        // 确认设备实际参数与这里一致
        port.setParameters(1200, 8, UsbSerialPort.STOPBITS_2, UsbSerialPort.PARITY_NONE);
        
        // 初始化仅包含有效数据的数组
        byte[] request = new byte[6];
        request[0] = hexIntToByte(0x80);
        request[1] = hexIntToByte(0x3F);
        request[2] = hexIntToByte(0x01);           
        request[3] = hexIntToByte(0x05); // CRC MSByte
        request[4] = hexIntToByte(0x8A); // CRC LSByte
        request[5] = hexIntToByte(0x0D); // Stop Byte
        
        // 启动串口IO管理器
        SerialInputOutputManager usbIoManager = new SerialInputOutputManager(port, this);
        usbIoManager.start();
        
        // 发送数据(仅发送有效字节)
        port.write(request, 0);
        
        runOnUiThread(() -> {
            String infosText = "信息\n";
            infosText += "发送的数据 = " + byteArrayToHexString(request) + "\n";
            infos.setText(infosText);
        });
        
    } catch (Exception e) {
        String erreur = e.toString();
        runOnUiThread(() -> {
            Toast.makeText(this, "错误:" + erreur, Toast.LENGTH_LONG).show();
            String erreurText = "错误\n";
            erreurText += "发送的数据 = " + byteArrayToHexString(request) + "\n";
            erreurText += "错误信息 = " + erreur + "\n";
            infos.setText(erreurText);
        });
    } finally {
        runOnUiThread(() -> spinner.setVisibility(View.GONE));
    }
}

步骤3:检查硬件连接

如果修复后仍收到回发数据,需确认设备的TX与RX引脚是否被短接(硬件回环),这会导致发送的数据被直接回传到接收端。

数据接收方法保持不变

@Override
public void onNewData(byte[] data) {
    runOnUiThread(() -> infos.append(byteArrayToHexString(data)));
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.05 13:44:52