前言
打包负责发送前拼装字节;解包是它的逆操作。我们读传感器、ADC、电源芯片的寄存器时,一个字节里面往往挤着就绪标志、故障码、量程参数,这时候就需要位域解包,把混杂在一起的字段拆分出来。
本文配套上篇打包的逻辑,讲解(val >> n) & mask这套固定解法,给出掩码计算技巧、多字段拆分示例,读懂 datasheet 的寄存器位图全靠它。
一、解包通用范式
field = (packed_val >> offset) & mask;参数说明:
offset:目标字段最低 bit 在打包字节里的位置,和解包对应的打包偏移完全一致;>>右移:把目标字段整体向右拉,对齐到 bit0;mask:掩码,用来保留有效 bit、屏蔽高位无关数据,掩码宽度等于字段 bit 宽度。
核心一句话:先右移对齐低位,再掩码截取。
二、案例 1|解包 I2C 寻址字节(打包篇案例反向)
打包布局:bit7~bit1 是 7bit 地址,bit0 是 R/W
uint8_t rw = (byte >> 0) & 0x01; uint8_t addr7 = (byte >> 1) & 0x7F;0x01:1bit 掩码;0x7F = 0b01111111:7bit 掩码
三、案例 2|解包 SPI 式命令字节(R/W 在 bit7)
布局:bit7=R/W,bit6~bit0=7bit 地址
uint8_t rw = (byte >> 7) & 0x01; uint8_t addr7 = (byte >> 0) & 0x7F;四、拓展:多字段解包(对应打包篇多字段例子)
打包:pack = (cmd << 5) | param
bit7~bit5:cmd(3bit);
bit4~bit0:param(5bit)
uint8_t cmd = (pack >> 5) & 0x07; // 0x07 是3bit掩码 0b111 uint8_t param = (pack >> 0) & 0x1F; // 0x1F 是5bit掩码 0b11111五、掩码快速计算技巧
掩码 =( (1U << bit_width) - 1 )
- 1bit:
(1<<1)-1 = 0x01 - 3bit:
(1<<3)-1 = 0x07 - 5bit:
(1<<5)-1 = 0x1F - 7bit:
(1<<7)-1 = 0x7F
写宏自动生成掩码(工程很常用):
#define MASK(w) ((1U << (w)) - 1U)六、什么时候必须掌握解包
- 读取传感器、ADC、电源芯片的状态寄存器(寄存器里面塞满标志位);
- 写 I2C/SPI 从机:收到主机下发的打包命令,第一件事就是解包;
- 自定义串口 / RS485 通信协议,接收端解析帧;
- 阅读 datasheet 寄存器位图,看懂每一位代表的含义。
补充:只读写 AT24C02 这种纯数据流 EEPROM,解包写得少;但只要碰传感器寄存器,解包是高频代码。
七、打包和解包对照总表
| 操作 | 用途 | 模板 | 方向 | |
|---|---|---|---|---|
| 打包 | 发送前拼装字段 | (field << offset) | ... | 左移就位、按位或 |
| 解包 | 收到后拆分字段 | (val >> offset) & mask | 右移对齐、掩码截取 |
八、解包篇小结
- 解包是打包的逆过程;
- 解包固定两步:右移对齐 bit0,掩码截取有效位;
- 偏移 offset 和打包时的 offset 一一对应;
- 解包只用右移 + 掩码,解包不用左移。
配套阅读:《位域打包:看懂 I2C 地址左移的底层逻辑》