I2C的物理接口由两条线组成:SDA和SCL。 SCL(串行时钟)是总线主机的时钟信号,SDA(串行数据)是数据信号。 I2C 驱动器是“漏极开路”,这意味着该器件只能将输出接地,或者将其输出置于高阻抗状态,这意味着它无法将其输出驱动为逻辑 1。高阻抗状态意味着输出不连接任何东西 ,即处于浮动状态。 SDA 和 SCA 线上分别连接了一对外部电阻,以便在器件将其输出置于高阻抗状态时上拉线路。 这种开漏极配置可防止线路短路,因为连接在一起的主设备和所有从设备永远不会向同一线路施加冲突的电压。
I2C 驱动器的时钟输入和数据输入缓冲器用作 I2C 设备的输入,因为它们用于读取线路的状态。 另一方面,当设备在总线上写入时,MOSFET 控制线路上的输出。
I2C总线支持不同的模式,支持不同的数据交换比特率。
模式 | 速度 |
---|---|
标准模式 | 100kbit/s |
快速模式 | 400kbit/s |
快速模式(plus) | 1Mbit/s |
高速模式 | 3.4Mbit/s |
应该注意的是,这些比特率决定了总线上数据传输的速度,而不是设备的处理速度。
I2C 协议以主从(控制器-外设)配置运行,因此总线上的读/写权限仅由主机拥有。 主机决定哪个从机将接收或发送数据给主机。 I2C有专门的数据帧,可以与总线上最多128个设备进行通信。
启动条件
在通信空闲状态下,SDA和SCL线被上拉。 为了启动通信,主设备将 SDA 线拉低,同时 SCL 线仍为高电平,并提醒总线上的从设备准备好进行通信。
寻址从机
在这个启动条件之后,主设备向它想要与之通信的从设备发送一个 7 位地址。 该地址由连接到总线的所有设备读取,并且具有该地址的设备响应主设备的请求。
读/写操作
7 位地址后面跟着一个 R/W 位 - “1”用于读取操作,“0”用于写入操作。 R/W 决定谁将接管 SDA 线进行数据传输,主机还是从机。 读写操作都是从master角度进行的,如下:
需要注意的是,是主机(而不是从机)在 SCL 线上产生时钟信号来采样 SDA 线上的数据。
应答/不应答
为了检查从机是否连接到总线或者是否忙,主机等待从机的确认,即主机等待从机在第 9 个时钟周期将 SDA 线拉低。 如果满足这样的条件,主设备会收到从设备的肯定响应,称为 ACK。 但如果SDA线在第9个时钟周期保持高电平,则称为NACK。 这种机制使主机能够检查具有给定地址的从机是否存在于总线上。 ACK/NACK 的另一个用途是确定从设备是否已接收到传输的比特而没有任何错误。
主机发送或接收的数据是正在执行通信的实际数据。 数据帧的所有其他部分都是协议的支持机制。 正如前面提到的,有两种操作:写和读。
写操作
首先,主机通过发送 7 位地址来对总线上的从机进行寻址。 如果从设备在总线上存在或处于活动状态,它就准备好传输。 之后,主设备发出W位,通知从设备主设备将接管SDA线并向从设备发送数据。 主设备在下一个时钟周期等待从设备的 ACK。 收到从机的 ACK 后,主机在每个时钟周期逐位发送“数据”。 主设备将数据写入总线,因此在 I2C 协议中称为“写”操作。
读操作
如果主机想要接收来自从机的数据,它会在总线上寻址从机并发送一个 R 位,并等待来自从机的 ACK。 收到从机的 ACK 后,主机允许从机接管 SDA 线,向主机传输数据。 这里主机从总线读取数据,因此这在 I2C 协议中称为“读”操作。
与 UART 相比,使用 I2C 的优点之一是通信由主机保持活动状态,并且在所有数据传输完成之前无需重新初始化通信,这意味着可以传输的位数没有限制。 每个数据帧传输。 例如:如果主机要向从机写入32位数据,则无需启动和结束通信4次(一次8位)。 在来自从机的每个 ACK 之后,可以将另一个 8 位块发送到从机。 与 UART 不同,I2C 减少了每个数据帧的起始位和停止位造成的开销。 但是,如果我们想将操作模式从读更改为写,或者反之亦然,则需要结束该帧。
除了减少位开销之外,ACK/NACK 还可以用作 I2C 总线中的错误检查机制。 对于写操作,如果主设备收到从设备的 NACK,则会重新发送数据到从设备。 如果主设备从从设备读取数据时收到 NACK,则主设备会丢弃已接收到的位。
停止条件
传输完成后,主机通过在 SCL 为高电平时将 SDA 线从低电平更改为高电平来发出停止条件。 这完成了事务并使通信回到空闲状态。
至此,我们完成了 I2C 数据帧及其所有部分的解释。 但这还不是全部。 I2C 提供了一些非常酷的功能,对于创建强大的系统非常有帮助。 并非所有 I2C 设备都支持这些功能,但需要注意它们。
前面提到,I2C 通信设备支持的比特率不一定是设备的数据处理速度。 那么,如果主设备向从设备请求一些数据而从设备尚未准备好所请求的数据怎么办? 由于主设备将在下一个时钟周期期待从设备的 ACK,并且如果从设备未能将 SDA 线拉低,则主设备将认为通信失败。 为了克服通信中的这一限制,从设备使用“时钟拉伸”来通知主设备它正忙并且需要更多时间来处理数据。 从机通过将 SCL 线拉低来实现此目的,这会停止通信,因为 I2C 中的数据采样是在 SCL 线的上升沿完成的。 并非所有 I2C 设备都支持时钟拉伸; 因此,需要设备的数据表来验证这一点。 有时这也会引起问题,因为如果设备出现故障,并保持 SCL 线拉低,整个总线就会停止,主设备无法与其他从设备通信。
I2C 总线支持多个主设备,并且可以与连接到总线的所有设备进行通信。 连接在总线上的主设备不断监视 SDA 和 SCL 线路的启动和停止条件,并保持挂起的传输,直到总线再次空闲。 这就是它们在同一总线上并发操作的方式,但可能存在传输由两个主机同时发起的情况。 为了避免这种情况,总线上的主设备不断监视 SDA 线,以检查 SDA 线是否被另一个主设备拉低。 如果其中一个在本应为高电平时检测到 SDA 为低电平,则它会断定另一个主机当前处于活动状态并立即终止自己的传输。 该过程称为总线仲裁。
如上图所示,Master A和Master B同时发起数据传输。 然而,Master B 设法将 SDA 线拉低,而 Master A 希望 SDA 线拉高。 Master A 检测到这种冲突,并失去仲裁权,即不再控制 SDA 线。
更高的比特率对于现代通信系统非常重要。 为了快速处理数据,还需要快速从从站获取数据。 I2C 支持每秒 3.2Mbits 的比特率。 这意味着 I2C 线每秒将在高电平和低电平之间改变状态 320 万次。 由于 PCB 走线或用于通信的电线上的高电容,使得线路的这种快速切换变得困难,并且时钟线路的上升时间增加。 上升时间是线路从逻辑低电平转换到逻辑高电平所需的时间。 下面是线路中每个电容的上升时间差异的示例。 红色波形的电容为 30nF,因此与电容为 1nF 的绿色波形相比,其上升速度要慢得多。
为了解决时钟信号上升时间增加的问题,使用阻值低于4.7 kΩ的上拉电阻。 这允许更多电流在线路中流动,但这会增加 I2C 线路的功耗。 因此,该协议中需要在速度和功耗之间进行权衡,因为随着速度的提高,功耗也会增加。
I2C 广泛用于将传感器分线、存储设备、显示器和其他从设备连接到微控制器 - 因为它需要最少的硬件连接。 由于它在爱好者社区中很受欢迎,因此用于实现和调试该协议的资源非常丰富。 我们希望本文能让您清楚地了解 I2C 的工作原理。