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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.16 09:33:29