第一篇:位域打包:看懂 I2C 地址左移的底层逻辑

前言

写 I2C 驱动时,几乎所有人都会碰到一行代码:7bit地址 << 1。很多人只记住这是 I2C 的固定写法,却不知道这是一套通用的位域打包思想,I2C 寻址字节只是其中一个特例。

位域打包,就是把多个短小的二进制字段,拼装到同一个字节里,用来组成总线命令、寻址帧。

本文从 I2C 寻址字节切入,讲清楚 (field << n) | flag 的通用范式,顺带对比 SPI 那种读写位在最高位的布局,避开移位方向的坑。

一、打包通用范式

复制代码
packed_val = (field_1 << offset_1) | (field_2 << offset_2);

规则:

  1. offset = 该字段最低位在最终打包结果中的 bit 编号(bit0 是最低位);
  2. 所有字段统一使用左移 <<,把字段抬到目标 bit 区间;
  3. 要求各个字段的 bit 范围互不重叠,才能安全按位或 |;
  4. 打包的目标:组装成总线要求的一个字节 / 字,发给外设。

核心一句话:哪一块字段要放在更高 bit,就给这块字段更大的左移偏移。

二、案例 1|标准 I2C 寻址字节:R/W 在 bit0

协议规定单字节布局(MSB 先行):

bit7 bit6 bit5 bit4 bit3 bit2 bit1 bit0
A6 A5 A4 A3 A2 A1 A0 R/W
  • 7bit 地址 A6~A0,目标区间 bit7~bit1,最低位偏移 = 1 → addr7 << 1

  • R/W 标记,目标区间 bit0,最低位偏移 = 0 → rw << 0

    uint8_t i2c_addr_byte = (addr7 << 1) | rw;

示例:addr7 = 0x50 (0b1010000)

  • 写:(0x50 << 1) | 0 = 0xA0
  • 读:(0x50 << 1) | 1 = 0xA1

三、案例 2|SPI 风格命令字节:R/W 在 bit7

大量 SPI ADC、Flash 命令格式:

bit7 bit6 bit5 bit4 bit3 bit2 bit1 bit0
R/W A6 A5 A4 A3 A2 A1 A0
  • 7bit 地址放在低 7 位,偏移 = 0,不需要移位;

  • R/W 标记放在 bit7,偏移 = 7 → rw << 7

    uint8_t spi_cmd_byte = addr7 | (rw << 7);

示例:addr7 = 0x50

  • 写:0x50 | (0 << 7) = 0x50
  • 读:0x50 | (1 << 7) = 0xD0

高频误区:RW 在高位,不需要把地址右移。打包永远是把字段左移就位,不是右移。

四、拓展:多字段打包示例

单字节内分配:bit7~bit5(3bit 命令 cmd),bit4~bit0(5bit 参数 param)

复制代码
uint8_t pack = (cmd << 5) | (param << 0);

五、工程避坑:STM32 HAL I2C 不对称地址

  1. HAL_I2C_Mem_Read(..., DevAddr,...):主机发送寻址字节,需要你手动打包,7bit 地址 <<1 | rw
  2. hi2c1.Init.OwnAddress1:STM32 作为 I2C 从机的匹配地址,寄存器内部右对齐存放,直接填原始 7bit 地址,HAL 内部自动打包

很多 I2C 驱动 bug,根源就是混淆两处的打包责任。

六、打包篇小结

  • 打包 = 拼积木,为发送做准备;
  • 统一公式:(字段 << 偏移) | (另一个字段 << 偏移);
  • I2C 左移 1 只是范式的一个特例,不是独立规则;
  • 打包只用左移,打包不用右移。

配套阅读:《位域解包:寄存器标志位拆分方法》

相关推荐
Zw-awa3 小时前
工程师的词典:缺省值、鲁棒性,和那些名不副实的怪词
stm32
youcans_3 小时前
【嵌入式软件AI编程】21. 整理通用提示词模板
stm32·单片机·嵌入式·ai编程
zhangzhangkeji4 小时前
stm32, HAL 库,定时器
stm32
新晨单片机设计4 小时前
S025F-STM32蓝牙智能手环(心率、血氧、体温、计步)【Proteus仿真+Keil程序+原理图】
stm32·嵌入式硬件·proteus·蓝牙智能手环
番茄灭世神6 小时前
PN学堂GD32课程第15篇——HardFault异常
c语言·单片机·嵌入式
创界工坊工作室6 小时前
49-基于单片机的火警报警器设计
stm32·单片机·嵌入式硬件·51单片机·proteus
笨笨饿6 小时前
144_Codex变慢的解决办法
stm32·单片机·嵌入式硬件·mcu·物联网·51单片机·proteus
雨田言炎6 小时前
STM32之ADC--电压采集
stm32·单片机·嵌入式硬件
inrichtt8 小时前
第十课时:中断优先级揭秘:抢占与嵌套的底层逻辑:
c语言·stm32·单片机·嵌入式硬件·github