LV005-I2C协议简介
了解下 I2C 协议。若笔记中有错误或者不合适的地方,欢迎批评指正 😃。
一、硬件连接
I2C 在硬件上的接法如下所示,主控芯片引出两条线 SCL,SDA 线,在一条 I2C 总线上可以接很多 I2C 设备,我们还会放一个上拉电阻(放一个上拉电阻的原因以后我们再说)。

i2c 支持一主多从,各设备地址独立,标准模式传输速率为 100kbit/s,快速模式为 400kbit/s。总线通过上拉电阻接到电源。当 I2C 设备空闲时,会输出高阻态,而当所有设备都空 闲,都输出高阻态时,由上拉电阻把总线拉成高电平。2C 物理总线使用两条总线线路,SCL 和 SDA。
- SCL: 时钟线,数据收发同步
- SDA: 数据线,传输具体数据
二、怎么传输数据?
1. 发球的例子
怎么通过 I2C 传输数据?我们需要把数据从主设备发送到从设备上去,也需要把数据从从设备传送到主设备上去,数据涉及到双向传输。举个例子,现在我们上体育课,我们的体育老师可以把球发给学生,也可以把球从学生中接过来。

- 发球:体育老师 → 学生
(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 器件的芯片手册中都有,我们找一个看一下:

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

当 SCL 线为高电平时,SDA 线由高到低的下降沿,为传输开始标志(S)。直到主设备发出结束信号(P), 否则总线状态一直为忙。结束标志(P)为,当 SCL 线为高电平时,SDA 线由低到高的上升沿。
2.2 数据格式与应答信号(ACK/NACK)
- 应答信号(ACK):接收器在接收到 8 位数据后,在第 9 个时钟周期,拉低 SDA
- SDA 上传输的数据必须在 SCL 为高电平期间保持稳定,SDA 上的数据只能在 SCL 为低电平期间变化

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

开始标志(S)发出后,主设备会传送一个 7 位的 Slave 地址,并且后面跟着一个第 8 位,称为 Read/Write 位。 R/W 位表示主设备是在接受从设备的数据还是在向其写数据。然后,主设备释放 SDA 线,等待从设备的应答信号(ACK)。 每个字节的传输都要跟随有一个应答位。应答产生时,从设备将 SDA 线拉低并且在 SCL 为高电平时保持低。 数据传输总是以停止标志(P)结束,然后释放通信线路。 然而,主设备也可以产生重复的开始信号去操作另一台从设备, 而不发出结束标志。综上可知,所有的 SDA 信号变化都要在 SCL 时钟为低电平时进行,除了开始和结束标志
三、I2C 传输数据的格式
1. 写操作
流程如下:
- 主芯片要发出一个 start 信号
- 然后发出一个设备地址(用来确定是往哪一个芯片写数据),方向(读/写,0 表示写,1 表示读)
- 从设备回应(用来确定这个设备是否存在),然后就可以传输数据
- 主设备发送一个字节数据给从设备,并等待回应
- 每传输一字节数据,接收方要有一个回应信号(确定数据是否接受完成),然后再传输下一个数据。
- 数据发送完之后,主芯片就会发送一个停止信号。
下图中白色背景表示 "主→ 从",灰色背景表示 "从→ 主"

2. 读操作
流程如下:
主芯片要发出一个 start 信号
然后发出一个设备地址(用来确定是往哪一个芯片写数据),方向(读/写,0 表示写,1 表示读)
从设备回应(用来确定这个设备是否存在),然后就可以传输数据
从设备发送一个字节数据给主设备,并等待回应
每传输一字节数据,接收方要有一个回应信号(确定数据是否接受完成),然后再传输下一个数据。
数据发送完之后,主芯片就会发送一个停止信号。
下图中白色背景表示 "主→ 从",灰色背景表示 "从→ 主"

3. 读写实例
我们来看一下 i2c 对 mpu6050 进行数据读写的流程。
- 单字节写入

- 连续字节写入

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

- 连续字节读出

对 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 管是开漏,作用一样),如下图:

真值表如下:
从真值表和电路图我们可以知道:
(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 协议它只能规定怎么传输数据,数据是什么含义由从设备决定。