4. I2C 地址与读写操作:7位地址与10位地址、读/写位、多字节传输格式
I2C 总线协议的核心在于其独特的寻址机制与读写控制方式。每个从设备都有一个唯一的地址,主设备通过地址来选择通信对象,并通过读/写位(R/W)决定数据传输方向。本章将深入解析 7 位与 10 位地址结构、读写位的作用以及多字节传输的完整格式,为 GPIO 模拟 I2C 驱动开发奠定协议基础。
4.1 7 位地址结构
标准 I2C 总线使用 7 位地址,最多可挂载 112 个从设备(保留 16 个地址用于特殊用途)。地址在起始条件(START)后由主设备发送,占用第一个字节的高 7 位,最低位为读写控制位(R/W)。
关键点: 7 位地址范围是 0x00 ~ 0x7F,其中 0x00 为通用呼叫地址,0x01 ~ 0x03 为保留地址,0x04 ~ 0x77 为用户可用地址,0x78 ~ 0x7F 为 10 位地址预留。
4.2 10 位地址结构
当系统需要挂载超过 112 个从设备时,I2C 规范定义了 10 位地址模式。10 位地址使用两个字节传输:第一个字节的高 5 位固定为 11110,后跟地址的高 2 位(A9、A8)和 R/W 位;第二个字节为地址的低 8 位(A7 ~ A0)。
| 字节序号 |
位 7 |
位 6 |
位 5 |
位 4 |
位 3 |
位 2 |
位 1 |
位 0 |
说明 |
| 第 1 字节 |
1 |
1 |
1 |
1 |
0 |
A9 |
A8 |
R/W |
10 位地址标识 + 高 2 位地址 |
| 第 2 字节 |
A7 |
A6 |
A5 |
A4 |
A3 |
A2 |
A1 |
A0 |
低 8 位地址 |
驱动开发提示: 在 GPIO 模拟 I2C 驱动中,10 位地址需要发送两个字节的地址帧,且第一个字节的 R/W 位必须为 0(写方向),第二个字节后跟 ACK。如果使用 7 位地址模式,则只需发送一个地址字节。务必在驱动初始化时确认从设备地址类型。
4.3 读/写位(R/W)
R/W 位是地址字节的最低位,用于指示数据传输方向:
- R/W = 0(写操作): 主设备向从设备发送数据。地址字节后,主设备继续发送数据字节,从设备每接收一个字节后回复 ACK。
- R/W = 1(读操作): 主设备从从设备读取数据。地址字节后,从设备发送数据字节,主设备每接收一个字节后回复 ACK(最后一个字节回复 NACK 以结束传输)。
常见误区: 许多初学者误以为 R/W 位是地址的一部分。实际上,R/W 位独立于地址,它决定的是总线上的数据流方向。在驱动代码中,地址左移 1 位后,最低位写入 R/W 值:addr << 1 | rw_flag。
4.4 多字节传输格式
I2C 支持在一个传输事务中连续发送或接收多个字节。多字节传输格式分为 写多字节 和 读多字节 两种场景。
4.4.1 写多字节传输
主设备发送起始条件后,依次发送从设备地址(R/W=0)、寄存器地址(可选)、多个数据字节,最后发送停止条件。每个字节后从设备回复 ACK。
// 写多字节传输时序(伪代码)
START();
send_byte(device_addr << 1 | 0); // 写地址
wait_ack();
send_byte(reg_addr); // 寄存器地址
wait_ack();
send_byte(data[0]); // 数据字节 1
wait_ack();
send_byte(data[1]); // 数据字节 2
wait_ack();
// ... 更多数据字节 ...
send_byte(data[N-1]); // 数据字节 N
wait_ack();
STOP();
4.4.2 读多字节传输
读多字节通常采用组合传输:先写寄存器地址,再重复起始条件切换为读方向,连续读取多个字节。主设备在最后一个字节回复 NACK 以通知从设备停止发送。
// 读多字节传输时序(伪代码)
START();
send_byte(device_addr << 1 | 0); // 写地址(指定寄存器)
wait_ack();
send_byte(reg_addr); // 寄存器地址
wait_ack();
REPEATED_START(); // 重复起始条件
send_byte(device_addr << 1 | 1); // 读地址
wait_ack();
data[0] = read_byte(); // 读取字节 1
send_ack(); // 回复 ACK
data[1] = read_byte(); // 读取字节 2
send_ack(); // 回复 ACK
// ... 更多数据字节 ...
data[N-1] = read_byte(); // 读取字节 N
send_nack(); // 回复 NACK(结束)
STOP();
驱动实现注意事项: 在 GPIO 模拟 I2C 驱动中,多字节传输的时序必须严格遵循 SCL 时钟周期。每个字节的 8 个数据位和 1 个应答位都需要精确的延时控制。特别是重复起始条件(Sr)的时序:在 SCL 低电平时释放 SDA,然后在 SCL 高电平时将 SDA 拉低,与普通起始条件相同。
4.5 地址与读写操作总结
| 特性 |
7 位地址 |
10 位地址 |
| 地址字节数 |
1 字节(高 7 位为地址) |
2 字节(第 1 字节标识 + 高 2 位,第 2 字节低 8 位) |
| 最大设备数 |
112 个 |
1024 个 |
| R/W 位位置 |
地址字节的最低位 |
第 1 字节的最低位 |
| 兼容性 |
所有 I2C 设备均支持 |
仅支持 10 位地址模式的设备 |
| 驱动复杂度 |
低 |
中(需发送两个地址字节) |