3. I2C协议基础:I2C总线物理层、主从通信原理、7位与10位地址、起始/停止条件、数据帧格式
在嵌入式系统中,I2C(Inter-Integrated Circuit)总线是连接微控制器与外围设备(如触摸屏控制器、传感器、EEPROM)最常用的串行通信协议之一。本章将深入剖析I2C协议的物理层特性、主从通信机制、地址编码规则以及完整的数据帧格式,为后续调试I2C触摸屏驱动打下坚实的理论基础。
3.1 I2C总线物理层
I2C总线仅需两根双向信号线即可完成多设备通信:串行数据线(SDA)和串行时钟线(SCL)。所有设备通过开漏输出或集电极开路方式连接到这两条线上,并通过上拉电阻接至电源电压。
- SDA(Serial Data Line):用于传输地址、控制命令和数据。
- SCL(Serial Clock Line):由主设备产生,用于同步数据传输。
- 上拉电阻:典型值为4.7kΩ(标准模式100kHz)或1.5kΩ(快速模式400kHz),确保总线空闲时保持高电平。
- 总线电容:受限于上拉电阻与总线寄生电容形成的RC时间常数,限制了最大通信速率。
3.2 主从通信原理
I2C总线采用主从(Master-Slave)通信模式。主设备负责产生时钟信号、发起通信、发送地址并控制数据传输方向;从设备则被动响应主设备的请求。
| 角色 | 职责 | 典型设备 |
|---|---|---|
| 主设备(Master) | 产生SCL时钟、发起START条件、发送从设备地址、控制读写方向、产生STOP条件 | MCU(如STM32F4、ESP32) |
| 从设备(Slave) | 监听总线、识别自身地址、响应主设备请求、发送或接收数据 | 触摸屏控制器(如FT5x06、GT911) |
3.3 7位地址与10位地址
I2C协议支持两种地址格式:7位地址和10位地址。触摸屏控制器绝大多数使用7位地址,但了解10位地址有助于应对特殊场景。
3.3.1 7位地址
7位地址是最常用的格式,地址范围0x00~0x7F(128个地址),其中0x00为通用呼叫地址,0x01~0x78为可用地址,0x79~0x7F保留。在数据帧中,7位地址左对齐占用一个字节的高7位,最低位(LSB)作为读写标志位(R/W)。
3.3.2 10位地址
10位地址扩展了地址空间,范围0x000~0x3FF(1024个地址)。在数据帧中,第一个字节的高5位为11110,接着是10位地址的高2位,然后读写位;第二个字节为10位地址的低8位。
| 地址类型 | 地址范围 | 可用地址数 | 首字节格式 | 典型应用 |
|---|---|---|---|---|
| 7位地址 | 0x00 ~ 0x7F | 112(可用) | AAAAAAA + R/W | 触摸屏、传感器、EEPROM |
| 10位地址 | 0x000 ~ 0x3FF | 1024 | 11110AA + R/W + AAAAAAAA | 复杂系统、多设备场景 |
reg属性指定7位地址。例如,FT5x06触摸屏的I2C地址通常为0x38,在设备树中表示为reg = <0x38>;。
3.4 起始条件与停止条件
I2C总线的数据传输由起始条件(START)和停止条件(STOP)界定。这两个条件是总线上的特殊信号序列,由主设备产生。
- 起始条件(S):SCL为高电平时,SDA从高电平切换到低电平。表示一次I2C通信的开始。
- 停止条件(P):SCL为高电平时,SDA从低电平切换到高电平。表示一次I2C通信的结束。
- 重复起始条件(Sr):在未产生停止条件的情况下,再次产生起始条件。用于改变数据传输方向(如从写切换到读)或切换从设备。
3.5 数据帧格式
I2C数据帧以字节为单位进行传输,每个字节8位,高位在前(MSB first)。每传输一个字节后,接收方必须产生一个应答位(ACK)或非应答位(NACK)。
3.5.1 完整数据帧结构
一次完整的I2C数据传输包含以下阶段:
- 起始条件(S)
- 从设备地址 + 读写位(7位或10位)
- 从设备应答位(ACK)
- 数据字节(一个或多个,每个字节后跟ACK/NACK)
- 停止条件(P)
3.5.2 写操作帧格式
主设备向从设备写入数据:
| S | 从设备地址 | W(0) | ACK | 寄存器地址 | ACK | 数据字节1 | ACK | ... | 数据字节N | ACK | P |
3.5.3 读操作帧格式
主设备从从设备读取数据(通常先写寄存器地址,再重复起始条件后读取):
| S | 从设备地址 | W(0) | ACK | 寄存器地址 | ACK | Sr | 从设备地址 | R(1) | ACK | 数据字节1 | ACK | ... | 数据字节N | NACK | P |
i2c_write_read()函数自动处理写寄存器地址、重复起始条件和读数据的完整流程,开发者只需提供从设备地址、寄存器地址、读写缓冲区即可。