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
相关产品推荐
相关产品推荐

