Android蓝牙SPP无法读取单片机UART数据,接收乱码求助
问题排查与解决方案
核心问题分析
你遇到的本质问题有两个:一是蓝牙输入流读取到异常字节(-1、0、0...,-1代表流已关闭,正常连接状态下不应出现);二是错误地将原始二进制字节直接转字符串(非可打印字符转任何编码都会产生乱码),而你的需求是将字节转换为十六进制格式的可读字符串。
以下是分步骤的排查与解决方法:
1. 先确认数据链路连通性
用第三方蓝牙串口工具(如Serial Bluetooth Terminal)连接单片机的蓝牙模块,测试收发数据:
- 如果第三方工具也收不到正确数据:问题出在单片机侧,要么是单片机UART到蓝牙模块的数据传输故障,要么是蓝牙模块的串口参数配置错误。
- 如果第三方工具能收到正确数据:问题完全在Android代码逻辑中。
2. 修复Android侧的字节处理逻辑
(1)替换错误的字符串转换方式
你需要将原始字节数组转换为十六进制格式的字符串,而不是直接用编码转字符串(FE、01这类非可打印字符转UTF-8/ASCII必然是乱码)。添加工具方法:
private String bytesToHexString(byte[] bytes, int length) { StringBuilder sb = new StringBuilder(); for (int i = 0; i < length; i++) { // 格式化每个字节为0xXX的格式 String hex = String.format("0x%02X", bytes[i]); sb.append(hex); if (i < length - 1) { sb.append(" "); } } return sb.toString(); }
然后在Handler中替换原字符串构造代码:
case Constants.MESSAGE_READ: byte[] readBuf = (byte[]) msg.obj; String readMessage = bytesToHexString(readBuf, msg.arg1); mConversationArrayAdapter.add(mConnectedDeviceName + ": " + readMessage); break;
(2)排查流读取异常问题
在ConnectedThread.run()中添加日志,确认每次读取的字节数:
bytes = mmInStream.read(buffer); Log.d(TAG, "读取到" + bytes + "个字节");
- 如果频繁出现
bytes=-1:说明蓝牙连接已隐性断开,需检查单片机蓝牙模块的稳定性,或Android侧的连接保活逻辑。 - 如果
bytes=0:代表流中暂时无数据,属于正常情况,无需处理。
3. 确认蓝牙模块的串口参数匹配
Android蓝牙SPP(RFCOMM)无需在Android侧设置波特率等参数,这些参数是单片机侧蓝牙模块的UART输入配置,必须与单片机的UART输出参数完全一致(波特率115200、数据位8、停止位1、无校验):
- 如果有单片机侧蓝牙模块的配置代码,检查是否将蓝牙模块的UART参数设置为目标值。
- 如果没有配置代码,可通过蓝牙模块的AT指令查询/修改(多数经典蓝牙模块支持):
- 发送
AT+UART?查询当前参数 - 发送
AT+UART=115200,8,1,0,0设置为目标参数(具体指令需参考对应蓝牙模块的数据手册)
- 发送
4. 排查单片机侧的数据发送链路
- 将单片机的UART输出端直接连接电脑的USB转串口模块,用串口助手查看是否能收到
FE 01 02的十六进制数据:- 如果电脑收不到:问题在单片机的串口发送逻辑,需检查单片机代码。
- 如果电脑能收到:问题在蓝牙模块的UART接收或蓝牙发送环节,需排查蓝牙模块的硬件连接或配置。
5. 优化Android侧的帧处理逻辑(可选)
如果需要处理固定格式的帧(如以FE开头的3字节帧),可添加缓存逻辑避免分包/粘包问题:
private ByteArrayOutputStream frameBuffer = new ByteArrayOutputStream(); public void run() { Log.i(TAG, "BEGIN mConnectedThread"); byte[] buffer = new byte[1024]; int bytes; while (mState == STATE_CONNECTED) { try { bytes = mmInStream.read(buffer); if (bytes > 0) { frameBuffer.write(buffer, 0, bytes); byte[] currentData = frameBuffer.toByteArray(); // 处理以FE开头的3字节完整帧 while (currentData.length >= 3 && currentData[0] == (byte)0xFE) { byte[] fullFrame = Arrays.copyOf(currentData, 3); mHandler.obtainMessage(Constants.MESSAGE_READ, 3, -1, fullFrame) .sendToTarget(); // 移除已处理的字节,缓存剩余数据 frameBuffer.reset(); if (currentData.length > 3) { frameBuffer.write(currentData, 3, currentData.length - 3); currentData = frameBuffer.toByteArray(); } else { break; } } } else if (bytes == -1) { Log.w(TAG, "输入流意外关闭"); connectionLost(); break; } } catch (IOException e) { Log.e(TAG, "连接断开 ~ " + e.toString()); connectionLost(); break; } } }
内容的提问来源于stack exchange,提问作者PETRER
相关产品推荐
相关产品推荐

