Skip to content

LV005-I2C协议简介

了解下 I2C 协议。若笔记中有错误或者不合适的地方,欢迎批评指正 😃。

可以参考这个文档:I2C-bus specification and user manual

一、硬件连接

I2C 在硬件上的接法如下所示,主控芯片引出两条线 SCL,SDA 线,在一条 I2C 总线上可以接很多 I2C 设备,我们还会放一个上拉电阻(放一个上拉电阻的原因以后我们再说)。

image-20210220144722044

i2c 支持一主多从,各设备地址独立,标准模式传输速率为 100kbit/s,快速模式为 400kbit/s。总线通过上拉电阻接到电源。当 I2C 设备空闲时,会输出高阻态,而当所有设备都空 闲,都输出高阻态时,由上拉电阻把总线拉成高电平。2C 物理总线使用两条总线线路,SCL 和 SDA。

  • SCL: 时钟线,数据收发同步
  • SDA: 数据线,传输具体数据

二、怎么传输数据?

1. 发球的例子

怎么通过 I2C 传输数据?我们需要把数据从主设备发送到从设备上去,也需要把数据从从设备传送到主设备上去,数据涉及到双向传输。举个例子,现在我们上体育课,我们的体育老师可以把球发给学生,也可以把球从学生中接过来。

image-20210220145618978
  • 发球:体育老师 → 学生

(1)老师:开始了(start)

(2)老师:A!我要发球给你!(地址/方向)

(3)学生 A:到!(回应)

(4)老师把球发出去(传输)

(5)A 收到球之后,应该告诉老师一声(回应)

(6)老师:结束(停止)

  • 接球:学生 → 体育老师

(1)老师:开始了(start)

(2)老师:B!把球发给我!(地址/方向)

(3)学生 B:到!

(4)B 把球发给老师(传输)

(5)老师收到球之后,给 B 说一声,表示收到球了(回应)

(6)老师:结束(停止)

2. I2C 的信号

我们就使用上面这个简单的例子,来了解一下 IIC 的传输协议:

  • 老师说开始了,表示开始信号(start)
  • 老师提醒某个学生要发球,表示发送地址和方向(address/read/write)
  • 老师发球/接球,表示数据的传输
  • 收到球要回应:回应信号(ACK)
  • 老师说结束,表示 IIC 传输结束(P)

下面我们回到 I2C 中,I2C 协议中数据传输的单位是字节,也就是 8 位。但是要用到 9 个时钟:前面 8 个时钟用来传输 8 数据,第 9 个时钟用来传输回应信号。传输时,先传输最高位(MSB)。I2C 协议信号应该是在每个 I2C 器件的芯片手册中都有,我们找一个看一下:

image-20210220151524099

2.1 起始信号与结束信号

  • 开始信号(S):SCL 为高电平时,SDA 山高电平向低电平跳变,开始传送数据。
  • 结束信号(P):SCL 为高电平时,SDA 由低电平向高电平跳变,结束传送数据。
3|

当 SCL 线为高电平时,SDA 线由高到低的下降沿,为传输开始标志(S)。直到主设备发出结束信号(P), 否则总线状态一直为忙。结束标志(P)为,当 SCL 线为高电平时,SDA 线由低到高的上升沿。

2.2 数据格式与应答信号(ACK/NACK)

  • 应答信号(ACK):接收器在接收到 8 位数据后,在第 9 个时钟周期,拉低 SDA
  • SDA 上传输的数据必须在 SCL 为高电平期间保持稳定,SDA 上的数据只能在 SCL 为低电平期间变化
3|

i2c 的数据字节定义为 8-bits 长度,对每次传送的总字节数量没有限制, 但对每一次传输必须伴有一个应答(ACK)信号, 其时钟由主设备提供,而真正的应答信号由从设备发出,在时钟为高时,通过拉低并保持 SDA 的值来实现。如果从设备忙, 它可以使 SCL 保持在低电平,这会强制使主设备进入等待状态。当从设备空闲后,并且释放时钟线,原来的数据传输才会继续。3

2.3 主机与从机通信

完整的通信过程时序大概如下图:

3|

开始标志(S)发出后,主设备会传送一个 7 位的 Slave 地址,并且后面跟着一个第 8 位,称为 Read/Write 位。 R/W 位表示主设备是在接受从设备的数据还是在向其写数据。然后,主设备释放 SDA 线,等待从设备的应答信号(ACK)。 每个字节的传输都要跟随有一个应答位。应答产生时,从设备将 SDA 线拉低并且在 SCL 为高电平时保持低。 数据传输总是以停止标志(P)结束,然后释放通信线路。 然而,主设备也可以产生重复的开始信号去操作另一台从设备, 而不发出结束标志。综上可知,所有的 SDA 信号变化都要在 SCL 时钟为低电平时进行,除了开始和结束标志

三、I2C 传输数据的格式

1. 写操作

流程如下:

  • 主芯片要发出一个 start 信号
  • 然后发出一个设备地址(用来确定是往哪一个芯片写数据),方向(读/写,0 表示写,1 表示读)
  • 从设备回应(用来确定这个设备是否存在),然后就可以传输数据
  • 主设备发送一个字节数据给从设备,并等待回应
  • 每传输一字节数据,接收方要有一个回应信号(确定数据是否接受完成),然后再传输下一个数据。
  • 数据发送完之后,主芯片就会发送一个停止信号。

下图中白色背景表示 "主→ 从",灰色背景表示 "从→ 主"

image-20210220150757825

2. 读操作

流程如下:

  • 主芯片要发出一个 start 信号

  • 然后发出一个设备地址(用来确定是往哪一个芯片写数据),方向(读/写,0 表示写,1 表示读)

  • 从设备回应(用来确定这个设备是否存在),然后就可以传输数据

  • 从设备发送一个字节数据给主设备,并等待回应

  • 每传输一字节数据,接收方要有一个回应信号(确定数据是否接受完成),然后再传输下一个数据。

  • 数据发送完之后,主芯片就会发送一个停止信号。

下图中白色背景表示 "主→ 从",灰色背景表示 "从→ 主"

image-20210220150954993

3. 读写实例

我们来看一下 i2c 对 mpu6050 进行数据读写的流程。

  • 单字节写入
3|
  • 连续字节写入
3|

对 MPU6050 进行写操作时,主设备发出开始标志(S)和写地址(地址位加一个 R/W 位,0 为写)。 MPU6050 产生应答信号。然后主设备开始传送寄存器地址(RA),接到应答后,开始传送寄存器数据, 然后仍然要有应答信号,连续写入多字节时依次类推。

  • 单字节读出
3|
  • 连续字节读出
3|

对 MPU6050 进行读操作时,主设备发出开始标志(S)和读地址(地址位加一个 R/W 位,1 为读)。 等待 MPU6050 产生应答信号。然后发送寄存器地址,告诉 MPU6050 读哪一个寄存器。 紧接着,收到应答信号后,主设备再发一个开始信号,然后发送从设备读地址。 MPU6050 产生应答信号并开始发送寄存器数据。通信以主设备产生的拒绝应答信号(NACK)和结束标志(P)结束。

4. 协议细节

  • 如何在 SDA 上实现双向传输?

主芯片通过一根 SDA 线既可以把数据发给从设备,也可以从 SDA 上读取数据,连接 SDA 线的引脚里面必然有两个引脚(发送引脚/接受引脚)。

  • 主、从设备都可以通过 SDA 发送数据,肯定不能同时发送数据,怎么错开时间?

在 9 个时钟里,前 8 个时钟由主设备发送数据的话,第 9 个时钟就由从设备发送数据;前 8 个时钟由从设备发送数据的话,第 9 个时钟就由主设备发送数据。

  • 双方设备中,某个设备发送数据时,另一方怎样才能不影响 SDA 上的数据?(为什么 SDA 上要有上拉电阻?)

设备的 SDA 中有一个三极管,使用开极/开漏电路(三极管是开极,CMOS 管是开漏,作用一样),如下图:

image-20210220152057547

真值表如下:

image-20210220152134970

从真值表和电路图我们可以知道:

(1)当某一个芯片不想影响 SDA 线时,那就不驱动这个三极管

(2)想让 SDA 输出高电平,双方都不驱动三极管(SDA 通过上拉电阻变为高电平)

(3)想让 SDA 输出低电平,就驱动三极管

可以看个例子,了解下数据是怎么传的(实现双向传输)。主设备发送(8bit)给从设备

前 8 个 clk:从设备不要影响 SDA,从设备不驱动三极管。主设备决定数据,主设备要发送 1 时不驱动三极管,要发送 0 时驱动三极管

第 9 个 clk:由从设备决定数据,主设备不驱动三极管。从设备决定数据,要发出回应信号的话,就驱动三极管让 SDA 变为 0。从这里也可以知道 ACK 信号是低电平。

从上面的这个例子,就可以知道怎样在一条线上实现双向传输,这就是 SDA 上要使用 上拉电阻的原因

  • 为何 SCL 也要使用上拉电阻?

在第 9 个时钟之后,如果有某一方需要更多的时间来处理数据,它可以一直驱动三极管把 SCL 拉低。当 SCL 为低电平时候,大家都不应该使用 I2C 总线,只有当 SCL 从低电平变为高电平的时候,IIC 总线才能被使用。当它就绪后,就可以不再驱动三极管,这是上拉电阻把 SCL 变为高电平,其他设备就可以继续使用 I2C 总线了。

  • 对于 IIC 协议它只能规定怎么传输数据,数据是什么含义由从设备决定。