如何实现Android通过蓝牙向Arduino正确连续发送消息并解决乱码问题
问题排查与解决方案
核心根因
- Arduino接收逻辑存在致命性能缺陷:每次读取1个字符就执行
delay(5),相当于单字符处理耗时5ms,每秒最多只能处理200个字符。单条指令长度约20字节,每秒发送超过10条指令就会导致Arduino串口接收缓冲区溢出,出现丢字、串包。另外else分支会直接将未接收完整的半截指令清空打印,是看到乱码、分段指令的直接原因。 - 安卓端发送逻辑未做限流+输出流未强制刷新:
ACTION_MOVE事件触发频率可达60~120次/秒,每触发一次就发送一次指令,发送速率远超Arduino的处理能力;且sendData方法写完字节数组后没有调用flush(),可能出现缓冲区攒了多包数据一起发送的情况,进一步加剧接收端压力。部分蓝牙透传模块本身速率有限,高频小数据包发送也可能出现粘包。
具体修复步骤
第一步:优先修复Arduino接收代码
- 直接删除
delay(5)代码行,串口接收为硬件缓冲,不需要加延迟等待,该延迟是问题的最大诱因 - 删除else分支里未完整接收就打印、清空
serialMessage的逻辑,指令必须读到结束符/才算完整,未读到结束符前不要清空缓冲区 - 可选:改用固定长度数组存储接收内容,避免String频繁拼接产生内存碎片
修复后参考代码:
if (Serial.available() > 0) { char c = Serial.read(); serialMessage += c; // 只有读到结束符才处理指令 if (c == '/') { lcd.setCursor(0,0); lcd.print(serialMessage); command = serialMessage; serialMessage = ""; } } // 完全删除else分支里的半截指令处理逻辑
第二步:优化安卓端发送逻辑
- 给
sendData方法添加flush调用,确保每次调用都立即把数据发出去,避免缓冲区攒包
protected void sendData(String message) { byte[] msgBuffer = message.getBytes(); try { outStream.write(msgBuffer); outStream.flush(); // 新增该行 } catch (IOException e) { // 原有异常处理逻辑 } }
- 给
ACTION_MOVE的发送逻辑加限流,比如设置最短200ms才发一次,人眼感知不到200ms的延迟,同时把发送速率降到5次/秒,完全在Arduino的处理能力范围内
参考实现:
// 新增全局变量 private long lastSendTime = 0; private static final long SEND_INTERVAL = 200; // ACTION_MOVE分支修改为如下逻辑 case MotionEvent.ACTION_MOVE: // 原有数值计算逻辑不变 String command = "[code]command(" + value + ")/"; long now = System.currentTimeMillis(); // 仅间隔超过阈值时发送 if (now - lastSendTime > SEND_INTERVAL) { Log.d("command", command); sendData(command); lastSendTime = now; } break;
第三步:极端场景兼容优化
如果上述修改后依然偶现异常,可做如下兼容:
- 给指令增加起始符校验,只有收到
[code]才开始存储后续内容,避免乱码字符混入有效指令 - 用
\r\n替代单字符/作为结束符,降低结束符误判概率
内容的提问来源于stack exchange,提问作者sunx35
相关产品推荐
相关产品推荐

