在Android Studio中正确合并BLE传输的4字节为32位无符号时间戳
STM32WB55 BLE 32位时间戳Android端正确解析方案
端侧原始实现逻辑
- STM32WB55端:将本地微秒级32位计时值
time_micro32拆分为4个独立字节,按低字节在前的顺序绑定到BLE通知数据包的固定位置:- 数据包下标8:存储
time_micro32的最低有效字节(LSB,值为time_micro32 & 0xFF) - 数据包下标9:存储
time_micro32的次低字节(值为(time_micro32 >> 8) & 0xFF) - 数据包下标10:存储
time_micro32的次高字节(值为(time_micro32 >> 16) & 0xFF) - 数据包下标11:存储
time_micro32的最高有效字节(MSB,值为(time_micro32 >> 24) & 0xFF)
MCU端串口打印验证该拆分逻辑输出完全正确,无发送侧错误。
- 数据包下标8:存储
最初实现的核心问题
- 字节顺序不匹配:最初的合并逻辑将数据包下标8的最低字节左移24位放到32位整数的最高位,下标11的最高字节直接放在最低位,与MCU端的拆分顺序完全反向,拼接出的数值与实际时间戳偏差极大。
- 符号扩展错误:Java/Kotlin中定义的
byte为有符号8位类型,取值范围为-128~127。直接将接收到的byte值参与位运算时,若字节值大于127,系统会自动对其做符号扩展,转为32位int类型的负值,这是最终显示结果频繁出现负数的核心诱因。 - 存储类型适配不足:32位无符号整数的最大取值为4294967295,超出Java
int类型的最大正值(2147483647),即便拼接逻辑完全正确,使用int存储该值时,只要最高位为1就会触发符号位标识,显示为负数,无法满足无符号值的展示需求。
修正后的正确实现
处理步骤
- 逐字节做无符号转换:每个从BLE数据包中取出的byte值,先与
0xFF做按位与运算,将有符号字节转换为0~255范围的无符号int值,从根源避免符号扩展带来的数值错误。 - 匹配字节拼接顺序:按照MCU端的高低位对应关系拼接数值,将下标11的最高字节放在32位值的最高偏移位,依次向前移位,下标8的最低字节放在32位值的最低偏移位。
- 适配存储类型:使用
long类型存储最终的32位无符号时间戳,完整覆盖无符号值的全部取值范围,避免int类型的符号位干扰显示结果。
参考代码
// BLE通知回调中获取的数据包数组 byte[] notificationValue = bluetoothGattCharacteristic.getValue(); // 逐字节做无符号转换 int byteLsb = notificationValue[8] & 0xFF; // 最低有效字节 int byteMid1 = notificationValue[9] & 0xFF; int byteMid2 = notificationValue[10] & 0xFF; int byteMsb = notificationValue[11] & 0xFF; // 最高有效字节 // 按对应位偏移拼接为无符号32位值 long timestamp = ((long)byteMsb << 24) | ((long)byteMid2 << 16) | ((long)byteMid1 << 8) | (long)byteLsb; // 显示到TextView findViewById<TextView>(R.id.Time_TextView).text = "Timestamp = " + timestamp;
踩坑注意事项
- 不要跳过
& 0xFF的无符号转换步骤:直接对byte做移位运算时,系统会自动将8位有符号byte扩展为32位int,例如0x80的byte值会被扩展为0xFFFFFF80,移位后得到完全错误的结果。 - 通信两侧必须提前约定统一的字节序规则:本次问题中MCU采用低字节在前的小端传输,Android端必须对应调整拼接顺序,不能默认按高字节在前的大端规则拼接。
- 无符号32位值不要用int类型存储:如果业务需要和MCU的32位无符号计数器保持完全一致的数值范围,long类型是更稳妥的选择,避免最高位为1时出现负数显示。
内容的提问来源于stack exchange,提问作者AnBa
相关产品推荐
相关产品推荐

