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

Android与Arduino USB通信控制LED故障排查求助

问题描述

我正在开发一款通过USB与Arduino通信的Android应用,已实现设备连接类。Android端连接代码中,connection.controlTransfer始终返回-1,因此将这部分代码注释掉,移除后仍能正常连接设备,读写数据使用bulkTransfer方法。通过按钮点击分别发送byte[]{1}和byte[]{0}控制Arduino的LED开关。此前测试切换LED状态的代码可正常工作,但改用指令控制LED的代码后,Android端显示1字节发送成功,Arduino的LED却无响应,且无法使用串口监视器调试,求解决办法。

Android连接代码

public boolean openUsbConnection(UsbDevice usbDevice,int baudRate){
    _isConnected = false;
    if(connection != null) {
        _isConnected = true;
        return true;
    }
    else{
        PendingIntent permissionIntent = PendingIntent.getBroadcast(context, 0, new Intent(ACTION_USB_PERMISSION),
                PendingIntent.FLAG_IMMUTABLE);
        usbManager.requestPermission(usbDevice,permissionIntent);
        if(usbManager.hasPermission(usbDevice)){
            connection = usbManager.openDevice(usbDevice);
            if(connection!=null){
                //int res1 = connection.controlTransfer(0x21, 34, 0, 0, null, 0, 0);
                // res2 = connection.controlTransfer(0x21, 32, 0, 0, getLineEncoding(baudRate), 7, 0);
                //if(setTransferParameters(CDC_SET_LINE_CODING,0,getLineEncoding(baudRate)) >=0
                        //&& setTransferParameters(CDC_SET_CONTROL_LINE_STATE,CDC_CONTROL_LINE_ON,null)>=0){
                    if(getInOutEndPoint(usbDevice)){
                    _isConnected = true;
                    }
                //}

                return true;
            }
        }
    }
    return false;
}

Android读写数据代码

public int sendData(byte[] data, int timeout){
    if(_isConnected){
    Log.d("USB_DEBUG", "usbOutEndPoint: " + usbOutEndPoint);
    Log.d("USB_DEBUG", "connection: " + connection);
    int length = 0;
    if(data!=null)length= data.length;
   return connection.bulkTransfer(usbOutEndPoint, data, length, timeout);
    }
    else return -2;
}
public int readData(byte[] buffer, int timeout) {
    if (_isConnected) {
        try {
            Log.d("USB_DEBUG", "usbOutEndPoint: " + usbOutEndPoint);
            Log.d("USB_DEBUG", "connection: " + connection);

            int bytesRead = connection.bulkTransfer(usbInEndPoint, buffer, buffer.length, timeout);

            if (bytesRead < 0) {
                Log.e("USB_DEBUG", "Error occurred during bulk transfer. bytesRead: " + bytesRead);
            }

            return bytesRead;
        } catch (Exception e) {
            Log.e("USB_DEBUG", "Exception occurred during bulk transfer: " + e.getMessage(), e);
            return -1; // Return -1 to indicate an error occurred
        }
    } else {
        Log.e("USB_DEBUG", "USB is not connected.");
        return -2; // Return -2 if USB is not connected
    }
}

Android按钮发送代码

void BtnOnClick(View view) {
    if(view == startBtn)
    {
        int result = arduinoManager.sendData(new byte[]{1},5000);
        int result2 = arduinoManager.readData(new byte[1],5000);
    }
    else if(view == btn)
    {
        int result = arduinoManager.sendData(new byte[]{0},5000);
        int result2 = arduinoManager.readData(new byte[1],5000);
    }
}

Arduino控制代码

int led = 13;
bool ledState = LOW;

void setup() {
    // Initialize the LED pin as an output
    Serial.begin(115200);
    pinMode(led, OUTPUT);
}

void loop() {
    // Check if data is available to read from serial
    if (Serial.available() > 0) {
        byte received = Serial.read();

        // Update the LED state based on the received value
        if (received == 1) {
            ledState = HIGH; // Turn the LED on
        } else if (received == 0) {
            ledState = LOW; // Turn the LED off
        }

        Serial.write(ledState); 
    }

    // Update the LED with the current state
    digitalWrite(led, ledState);
}
解决方案

1. 恢复CDC控制传输(核心修复)

Arduino的USB串口基于CDC协议,必须完成设置线编码和设置控制线路状态两个控制传输步骤,否则Serial端口不会正确响应数据。之前注释的controlTransfer是关键步骤,不能省略。

修改openUsbConnection方法,恢复并修正控制传输代码:

if(connection!=null){
    // 发送CDC_SET_CONTROL_LINE_STATE命令(置位DTR/RTS,告知Arduino准备通信)
    int res1 = connection.controlTransfer(0x21, 34, 0x0001, 0, null, 0, 1000);
    // 发送CDC_SET_LINE_CODING命令,匹配Arduino的Serial.begin(115200)参数
    byte[] lineEncoding = getLineEncoding(baudRate);
    int res2 = connection.controlTransfer(0x21, 32, 0, 0, lineEncoding, 7, 1000);
    
    // 只有两个控制传输都成功,才标记连接有效
    if(res1 >=0 && res2 >=0){
        if(getInOutEndPoint(usbDevice)){
            _isConnected = true;
        }
    }

    return _isConnected;
}

确保getLineEncoding生成正确的7字节CDC线编码数据,示例实现:

private byte[] getLineEncoding(int baudRate) {
    byte[] encoding = new byte[7];
    // 波特率(小端字节序)
    encoding[0] = (byte) (baudRate & 0xff);
    encoding[1] = (byte) ((baudRate >> 8) & 0xff);
    encoding[2] = (byte) ((baudRate >> 16) & 0xff);
    encoding[3] = (byte) ((baudRate >> 24) & 0xff);
    encoding[4] = 0; // 停止位:1位
    encoding[5] = 0; // 奇偶校验:无
    encoding[6] = 8; // 数据位:8位
    return encoding;
}

2. 验证端点方向正确性

检查getInOutEndPoint方法是否正确识别端点方向:

  • 输出端点(Android→Arduino)方向必须是UsbEndpoint.DIRECTION_OUT
  • 输入端点(Arduino→Android)方向必须是UsbEndpoint.DIRECTION_IN
    端点方向错误会导致数据发送到无效通道,Arduino无法接收。

3. 优化Arduino端数据读取逻辑

添加缓冲区清空处理,避免残留数据干扰指令识别:

void loop() {
    // 清空缓冲区,确保只处理最新的指令
    while(Serial.available() > 0){
        byte received = Serial.read();
        if (received == 1) {
            ledState = HIGH;
        } else if (received == 0) {
            ledState = LOW;
        }
    }
    digitalWrite(led, ledState);
    // 回传当前状态到Android,用于调试
    Serial.write(ledState);
    delay(10); // 降低轮询频率,减少资源占用
}

4. 调试方法(替代串口监视器)

  • 在Android按钮点击代码中添加详细日志,确认发送和接收结果:
    void BtnOnClick(View view) {
        if(view == startBtn)
        {
            int result = arduinoManager.sendData(new byte[]{1},5000);
            Log.d("USB_DEBUG", "发送1字节结果:" + result);
            byte[] readBuf = new byte[1];
            int result2 = arduinoManager.readData(readBuf,5000);
            if(result2 > 0){
                Log.d("USB_DEBUG", "读取到状态:" + readBuf[0]);
            } else {
                Log.e("USB_DEBUG", "读取失败,返回值:" + result2);
            }
        }
        else if(view == btn)
        {
            int result = arduinoManager.sendData(new byte[]{0},5000);
            Log.d("USB_DEBUG", "发送0字节结果:" + result);
            byte[] readBuf = new byte[1];
            int result2 = arduinoManager.readData(readBuf,5000);
            if(result2 > 0){
                Log.d("USB_DEBUG", "读取到状态:" + readBuf[0]);
            } else {
                Log.e("USB_DEBUG", "读取失败,返回值:" + result2);
            }
        }
    }
    
  • 在Arduino端增加辅助调试LED:比如使用引脚12,收到数据时快速闪烁,直观确认是否接收到指令。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.24 17:15:54