3. I2C从机地址与读写操作:7位地址与10位地址、读写位组合、多主机仲裁

地址,是I2C通信的第一步。地址错了,后面全是白搭。我见过不少工程师,调了两天I2C,最后发现是地址配错了——这种坑,我自己也踩过。

这一节,咱们把地址和读写操作彻底讲透。7位地址怎么用?10位地址什么时候需要?读写位到底怎么组合?多主机抢总线怎么办?嗯,一个一个来。

3.1 7位地址:最常用的地址格式

I2C总线上的每个从机,都有一个唯一地址。7位地址,就是最常见的格式。你想想看,7位能表示0~127,但实际可用的是0x08~0x77。为什么?因为0x00是通用呼叫地址,0x01~0x07保留,0x78~0x7F也是保留地址。

地址范围 用途 说明
0x00 通用呼叫地址 广播给所有从机
0x01 ~ 0x07 保留 特殊总线功能
0x08 ~ 0x77 普通从机地址 实际可用范围
0x78 ~ 0x7F 保留 10位地址扩展等

7位地址的传输格式,是这样的:主机先发一个起始条件,然后发7位地址 + 1位读写位。读写位为0表示写,为1表示读。从机收到后,如果地址匹配,会在第9个SCL时钟周期拉低SDA,作为应答。

关键点:7位地址左移1位,最低位填读写位,组成一个字节。比如地址0x50,写操作就是0xA0,读操作就是0xA1。很多数据手册直接给7位地址,你得自己算。

3.2 10位地址:什么时候用?怎么用?

7位地址最多支持112个设备。对于简单的传感器、EEPROM,够用了。但有些复杂芯片,比如视频处理器、多通道ADC,地址不够用怎么办?这时候就需要10位地址。

10位地址的传输,分两个阶段:

  1. 第一个字节:高5位固定为11110,接着是10位地址的高2位,最后是读写位。
  2. 第二个字节:10位地址的低8位。

举个例子,10位地址0x2B4:

  • 高2位是10,低8位是0xB4
  • 第一个字节:1111 0 10 R/W = 0xF4(写)或0xF5(读)
  • 第二个字节:0xB4

注意:10位地址的从机,在第一个字节后要应答一次,第二个字节后也要应答一次。我曾经调试一个10位地址的音频编解码芯片,第一次应答没处理好,总线直接卡死。后来用逻辑分析仪一看,才发现是应答时序不对。

3.3 读写位组合:写操作与读操作的完整流程

读写位,就是地址字节的最低位。0是写,1是读。但实际传输中,读操作往往需要先写再读。为什么?因为你要告诉从机,读哪个寄存器。

写操作流程:

START + 7位地址 + 0(W) + ACK + 寄存器地址 + ACK + 数据 + ACK + ... + STOP

读操作流程(先写后读):

START + 7位地址 + 0(W) + ACK + 寄存器地址 + ACK + 
RESTART + 7位地址 + 1(R) + ACK + 数据 + NACK + STOP

这里有个细节:读操作的最后,主机要发NACK,表示不再接收数据,然后发STOP。如果发了ACK,从机会继续发数据,总线就乱了。

个人经验:我习惯在驱动里把读写操作封装成两个函数:i2c_write_reg()和i2c_read_reg()。读函数内部自动处理先写后读的流程。这样上层调用时,不用关心底层细节,代码也干净。

3.4 多主机仲裁:谁抢到总线谁说话

I2C允许多个主机挂在同一条总线上。但同一时刻,只能有一个主机控制总线。如果两个主机同时发数据,怎么办?仲裁机制来解决。

仲裁的原理很简单:谁先拉低SDA,谁就赢。因为SDA是开漏输出,低电平会覆盖高电平。主机在发送数据时,会监测SDA电平。如果自己发的是高电平,但SDA是低电平,说明有其他主机在拉低总线,自己就输了。

仲裁的规则:

  • 仲裁在SDA上进行,SCL由主机共同驱动
  • 仲裁可以发生在地址位,也可以发生在数据位
  • 输掉仲裁的主机,必须释放总线,转为从机模式
  • 仲裁不会丢失数据,因为赢的主机继续传输

避坑指南:我曾经在一个多主机项目中,两个主机同时访问同一个从机。结果从机应答混乱,数据错位。后来加了总线占用检测,每个主机在发起传输前,先检测总线是否空闲。空闲时间大于4.7μs才能开始传输。

3.5 知识结构图:地址与仲裁核心逻辑

下面这张图,把7位地址、10位地址、读写操作、多主机仲裁的关系画清楚了。你可以对照着看,理解整个流程。

I2C地址与仲裁核心逻辑 I2C地址与仲裁核心逻辑 I2C地址 7位地址 (0x08~0x77) 10位地址 (0~1023) 读写位 (0=写, 1=读) 两阶段传输 读写操作 (先写后读) 多主机仲裁 (低电平优先) 7位地址左移1位+读写位组成1字节;10位地址分两阶段传输;多主机仲裁由SDA低电平决定

3.6 实战要点总结

这一节的内容,我总结成几个关键点,方便你快速回顾:

知识点 核心要点 常见错误
7位地址 左移1位+读写位组成1字节 忘记左移,直接发7位地址
10位地址 第一字节11110+高2位+R/W,第二字节低8位 应答时序处理错误
读写操作 读操作需要先写寄存器地址,再重新开始读 读操作最后没发NACK
多主机仲裁 低电平优先,输的释放总线 没有检测总线空闲就发起传输

调试建议:遇到I2C通信问题,先用逻辑分析仪抓波形。看起始条件、地址、读写位、应答位,一眼就能发现问题。我调试时,逻辑分析仪是必备工具,比示波器好用多了。