android - 通过蓝牙将数据从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接收字节,转换为字符串并发送到主活动,以便它尽快免费接收下一个活动是否是一种好习惯?然后在主要活动中,我会重建数据包吗?或者这对主要活动来说也太多了?
在此先感谢您的帮助。
解决方案
推荐阅读
- python - 使用 discord.py 创建服务器并获得邀请
- powershell - 签署所有即将到期的 PS 脚本
- sas - 使用另一个 SQL 语句中的 SQL 语句填充 SAS 宏变量?
- firebase - Flutter - Provider - 来自多个流的 Firestore 数据
- python - 如何使用 tkinter 中的按钮调用单独的 python 程序?
- c++ - 无法使用 C++ 连接到 MySQL
- python - Python 抽象属性()“无法用抽象方法实例化抽象类 []”,但我做到了
- python - 在 django 后端应用程序中使用参数进行重定向并响应前端应用程序
- python - 将 3 列数据框转换为由范围定义的列的矩阵
- python - 从 MATLAB 到 Python 的循环转换有问题