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位地址的传输,分两个阶段:
- 第一个字节:高5位固定为11110,接着是10位地址的高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位地址、读写操作、多主机仲裁的关系画清楚了。你可以对照着看,理解整个流程。
3.6 实战要点总结
这一节的内容,我总结成几个关键点,方便你快速回顾:
| 知识点 | 核心要点 | 常见错误 |
|---|---|---|
| 7位地址 | 左移1位+读写位组成1字节 | 忘记左移,直接发7位地址 |
| 10位地址 | 第一字节11110+高2位+R/W,第二字节低8位 | 应答时序处理错误 |
| 读写操作 | 读操作需要先写寄存器地址,再重新开始读 | 读操作最后没发NACK |
| 多主机仲裁 | 低电平优先,输的释放总线 | 没有检测总线空闲就发起传输 |
调试建议:遇到I2C通信问题,先用逻辑分析仪抓波形。看起始条件、地址、读写位、应答位,一眼就能发现问题。我调试时,逻辑分析仪是必备工具,比示波器好用多了。