首页 > 解决方案 > 通过蓝牙将数据从STM32发送到Android时未收到完整数据包

问题描述

我正在将加速度计数据从 STM32 微控制器发送到 HC-06 蓝牙模块,并且我开发了一个 Android 应用程序来接收数据。

在 STM32 上,我制作了一个 3 字节的数据包(uartBuffer),其结构如下:[0] 计数器、[1] xdata、[2] ydata。然后我通过 UART 将此数据发送到 HC-06 模块。 HAL_UART_Transmit(&uartHand, uartBuffer, 3, 10); // {uartHandle, data, dataSize, timeout}

在Android上,我与设备等连接没有问题。但是,当我收到数据包时,它并没有一起到达。它总是最终到达(也以正确的顺序),但我可能会得到一个只有第一个字节的数据包,然后是一个包含最后 2 个字节的数据包,有时还有其他组合,如下面的 logcat 图片所示。始终以 1 递增的值(即 20、21、22 等)是 STM32 发送的数据包的第一个字节。

安卓日志猫

我已经用高达 100Hz 的不同采样率和更大的数据包(最多 5 个字节)对此进行了测试。我从不丢失任何字节,但数据包排列在更高的采样率和数据大小下被进一步划分。

这是在 run 方法中读取数据的 ConnectedThread 类。

`
private class ConnectedThread extends Thread {

    private final BluetoothSocket mmBTSocket;
    private final InputStream mInStream;
    private final OutputStream mOutStream;

    public ConnectedThread(BluetoothSocket mSocket) {
        Log.d(TAG, "ConnectedThread: Starting");

        mmBTSocket = mSocket;
        InputStream mTempIn = null;
        OutputStream mTempOut = null;

        try {
            mTempIn = mmBTSocket.getInputStream();
            mTempOut = mmBTSocket.getOutputStream();
        } catch (IOException e) {
            Log.e(TAG, "Failed to get I/O Stream", e);
        }
        mInStream = mTempIn;
        mOutStream = mTempOut;
    }


    public void run(){
        byte[] mBuffer = new byte[3]
        int mBytes = 0; // bytes returned from read
        String mIncomingMessage = new String();
        mIncomingStringBuilder = new StringBuilder();

        while (true) {
            try {
                mIncomingStringBuilder.setLength(0);
                mBytes = mInStream.read(mBuffer, 0, 3);
                for (int i=0; i<mBytes; i++) {
                    mIncomingMessage = String.valueOf(mBuffer[i]);
                    mIncomingStringBuilder.append(mIncomingMessage + ",");
                }
                Log.d(TAG, "run: ConnectedThread - InputStream: " + mIncomingStringBuilder);
                Intent incomingMessageIntent = new Intent("incomingMessage");
                incomingMessageIntent.putExtra("theMessage", mIncomingStringBuilder.toString());
                LocalBroadcastManager.getInstance(mContext).sendBroadcast(incomingMessageIntent);
            } catch (IOException e) {
                Log.e(TAG, "error reading from inputStream, e);
                break;
            }
        }
}
`

所以我的问题是:

1) 为什么我没有收到与从 STM32 发送的相同结构的完整数据包?一位评论员在这里提到

蓝牙连接是基于流的,而不是基于数据包的。不保证或尝试保留分包。因此,任意数量的写入都可能导致任意数量的读取,只是保证字节流是正确的。如果需要检测数据包,则需要提供自己的数据包结构来包装数据。

这是真的?蓝牙真的不能保留完整的数据包结构吗?任何人都可以验证这一点吗?

2)如果这是真的,那么构造一个易于Android检测开始和结束的包的最佳方法是什么?我假设我需要一个同步/开始字节。如何确保我的加速度计数据中不会出现此同步字节?我应该使用 2 个连续的同步字节吗?数据包末尾的校验和是否足以检测数据包是否有错误?

3)最后,仅在Android上使用connectedThread接收字节,转换为字符串并发送到主活动,以便它尽快免费接收下一个活动是否是一种好习惯?然后在主要活动中,我会重建数据包吗?或者这对主要活动来说也太多了?

在此先感谢您的帮助。

标签: androidcbluetoothstm32spi

解决方案


推荐阅读