硬件工程师口中的取低八位,中八位,高八位是什么意思?

0 阅读4分钟

阿硬:协议定好了,你按协议上的解析就可以了。
小卡拉米:高八位,中八位低八位什么意思。
阿硬:

image.png

在我们和硬件通讯的协议当中,可能要一个字节一个字节的解析。但是我们有时候需要传输的数据有时候用一个字节是不够的。 比如一个CAN协议,要接收一个数据

我们接收到数据段有三个字节,第一个字节代表数据的高八位,第二个字节代表数据的中八位,第三个字节代表数据的低八位。我们怎么解析这个数据呢?

1、复习byte ,short,int 和 long

在Kotlin中

类型位数字节数取值范围
Byte81-128 到 127
Short162-32768 到 32767
Int324-2³¹ 到 2³¹-1
Long648-2⁶³ 到 2⁶³-1

2、传输数据时,byte个数的选择

当传输状态信息(例如设备启动状态、水温、空调温度设定值)时,一个 Byte(8位)通常足以表示,因为其取值范围(-128 至 127)能够涵盖这类离散或有限范围的状态值。

若传输的数据值超出 Byte 的表示范围,则需要使用两个 Byte 组合表示一个数值:其中一个 Byte 表示高八位,另一个 Byte 表示低八位

对于小数类型的数据传输,需在通信协议中明确规定小数精度(例如保留三位小数)。实际传输时,一般做法是将原始数值乘以缩放因子(如 1000)转换为整数,然后发送该整数值。接收方解析后,再除以相同的缩放因子(如 1000) ,即可还原原始数值。

3、两个byte 转成一个数

核心原理:二进制位拼接与数值重构

当使用两个字节表示一个数值时(Byte1 为高八位,Byte2 为低八位),本质是通过二进制位的拼接重构原始数值。其数学原理是:

最终数值 = (高八位值 × 256) + 低八位值

具体的操作步骤:

3.1、字节到整数的无符号转换

Kotlin/Java中,Byte 是有符号类型,需要转为无符号整数

val highBits = byte1.toInt() and 0xFF  // 高八位无符号值 (0~255)
val lowBits = byte2.toInt() and 0xFF   // 低八位无符号值 (0~255)

and 0xFF 确保只保留后八位

3.2、高八位左移

通过位左移(<<)  将高八位移动到正确位置:

val shiftedHigh = highBits shl 8  // 等价于 highBits × 2⁸

00001011(十进制11)左移8位 → 00001011_00000000(十进制2816)

3.3、位或(OR)运算合并

将移位后的高八位与低八位进行按位或运算

val finalValue = shiftedHigh or lowBits  // 位拼接

00001011_00000000(高八位)
OR 00101100(低八位)
00001011_00101100

原理解析图

高八位字节 (byte1)     低八位字节 (byte2)
┌───────┐             ┌───────┐
│ 00001011 │           │ 00101100 │
└───────┘             └───────┘
      │                     │
      ▼ 左移8位             ▼
┌───────────────┐       ┌───────┐
│ 0000101100000000 │ OR  │ 00101100 │
└───────────────┘       └───────┘
             │         │
             └─────┬─────┘
                   ▼
         ┌───────────────────┐
         │ 0000101100101100 │ → 十进制2860
         └───────────────────┘

高中低 同理,三个的时候,高八位要左移十六, 中八位左移八位

4、一个数转成两个byte

graph LR
    A[原始整数 value] --> B[取低八位]
    A --> C[取高八位]
    B --> D[byte2 = value & 0xFF]
    C --> E[byte1 = value >> 8]

4.1. 提取低八位(byte2) :

    val byte2 = (value and 0xFF).toByte()  // 直接取最后8位    
  • and 0xFF操作:屏蔽高24位,保留最低8位
  • 示例:2860(0x0B2C)→ 0x2C → 44

4.2. 提取高八位(byte1)

 val byte1 = (value shr 8).toByte()  // 右移8位后取低8位
  • shr 8操作:将原始值右移8位(相当于除以256)
  • 示例:2860(0x0B2C)→ 右移8位 → 0x0B → 11

4.3 如果需要提取中八位,需要注意一下

graph LR
    A[原始32位整数] --> B[屏蔽低八位]
    A --> C[屏蔽高八位]
    B --> D[右移8位]
    C --> E[位掩码操作]
    D --> F[获取中八位]
    E --> F

详细步骤(以 0x12345678 为例)

  1. 屏蔽低八位(清除0-7位)

    val withoutLow = value and 0xFFFFFF00 // 清除低8位
    
    • 位掩码 0xFFFFFF00 = 11111111_11111111_11111111_00000000
    • 示例:0x12345678 and 0xFFFFFF00 = 0x12345600
    • 效果:保留24-8位,清除0-7位
  2. 屏蔽高八位(清除24-31位)

    val middle8 = (value shr 8) and 0xFF // 右移后取低8位
    
    • 步骤分解:
      a. value shr 8:将值右移8位

      • 0x12345678 shr 8 = 0x00123456
        b. and 0xFF:取结果的最低8位
      • 0x00123456 and 0xFF = 0x56

完整代码实现

fun extractMiddle8Bits(value: Int): Int {
   :直接右移+掩码(推荐)
    return (value shr 8) and 0xFF

// 方法2:分步屏蔽
    // val withoutLow = value and 0xFFFFFF00
    // return (withoutLow ushr 8) and 0xFF

}

OK,这样就可以和阿硬愉快的沟通啦