目录
- 一、概述
- 二、I2C 详解
- 1、I2C 总线简介
- 2、I2C 协议相关知识
- 2.1 起始位
- 2.2 停止位
- 2.3 数据传输
- 2.4 应答信号
- 2.5 I2C 设备地址格式
- 2.5 I2C 时序图
- 2.5.1 I2C 写时序
- 2.5.2 I2C 读时序
- 2.5.3 单个/多个字节的写入/读取
- 3、时钟同步和仲裁
- 3.1 时钟同步
- 3.2 时钟仲裁
一、概述
IIC 协议(Inter-Integrated Circuit,可简写为 I2C),是一种用于各种电子设备之间进行通信和数据交换的串行通信协议。它是由飞利浦(Philips)公司于 1982 年首次提出并推广的一种简单、高效、低成本的通信协议。
I2C
协议采用双线结构传输数据,包括一个数据线和一个时钟线(即 SDA 和 SCL 线),其中 SDA(Serial Data)线用于双向数据传输,而 SCL(Serial Clock)线则用于同步数据传输的时钟信号。通信始终由主设备(Master)控制,从设备(Slave)被动接收和回应。这种简单的线路连接方式使得设备之间的互连变得非常容易。下图即是 I2C
的基本结构:
I2C
协议具有广泛的应用范围,如连接传感器、存储器、显示器等设备,常用于微控制器和嵌入式系统中,因为它使用的引脚较少,可以同时连接多个设备,并且具有简单的硬件和软件实现。
二、I2C 详解
1、I2C 总线简介
I2C
总线是一种多主机总线,连接在 I2C
总线上的器件分为主机和从机。
- 主机有权发起和结束一次通信,从机只能被动呼叫;
- 当总线上有多个主机同时启用总线时,
I2C
也具备冲突检测和仲裁的功能来防止错误产生; - 每个连接到
I2C
总线上的器件都有一个唯一的地址(7 bit),且每个器件都可以作为主机也可以作为从机(但同一时刻只能有一个主机),总线上的器件增加和删除不影响其他器件正常工作; I2C
总线在通信时总线上发送数据的器件为发送器,接收数据的器件为接收器。
I2C
总线可以通过外部连线进行在线检测,便于系统故障诊断和调试,故障可以立即被寻址,软件也有利于标准化和模块化,缩短开发时间。
I2C
总线上可挂接的设备数量受总线的最大电容400pF限制。
串行的 8 位双向数据传输速率在标准模式下可达 100Kbit/s,快速模式下可达 400Kbit/s,高速模式下可达 3.4Mbit/s。
总线具有极低的电流消耗,抗噪声干扰能力强,增加总线驱动器可以使总线电容扩大 10 倍,传输距离达到 15m;兼容不同电压等级的器件,工作温度范围宽。
上图就是 I2C
总线如何同多台设备进行通信,在 I2C
总线上,每个从机都有其唯一的设备地址。所以我们只需要知道器件的地址,根据时序就可以实现微控制器与器件之间的通信。
注意,按照实际设计中经验大概是不超过 8 个器件。
这是由 I2C
地址决定:8 位地址,减去 1 位广播地址,是 7 位地址, 2 7 = 128 2^7=128 27=128,但是地址 0x00 不用,那就是 127 个地址, 所以理论上可以挂 127 个从器件。但是,I2C
协议没有规定总线上设备最大数目,但是规定了总线电容不能超过 400pF。管脚都是有输入电容的,PCB 上也会有寄生电容,所以会有一个限制。实际设计中经验值大概是不超过 8 个器件。
总线之所以规定电容大小是因为,I2C
的 OD 要求外部有电阻上拉,电阻和总线电容产生了一个 RC 延时效应,电容越大信号的边沿就越缓,有可能带来信号质量风险。传输速度越快,信号的窗口就越小,上升沿下降沿时间要求更短更陡峭,所以 RC 乘积必须更小。
2、I2C 协议相关知识
2.1 起始位
如下图,就是 I2C
通信起始标志,通过这个起始位就可以告诉 I2C
从机,主机要开始进行 I2C
通信了。在 SCL 为高电平的时候,SDA 出现下降沿就表示为起始位:
2.2 停止位
如下图,就是停止 I2C
通信的标志位,和起始位的功能相反。在 SCL 位高电平的时候,SDA 出现上升沿就表示为停止位:
2.3 数据传输
如下图,I2C
总线在数据传输的时候要保证在 SCL 高电平期间,SDA 上的数据稳定,即 SDA 上的数据变化只能在 SCL 低电平期间发生:
2.4 应答信号
当 I2C
主机发送完 8 位数据以后会将 SDA 设置为输入状态,等待 I2C
从机应答,也就是等到 I2C
从机告诉主机它接收到数据了。应答信号是由从机发出的,主机需要提供应答信号所需的时钟,主机发送完 8 位数据以后紧跟着的一个时钟信号就是给应答信号使用的。从机通过将 SDA 拉低来表示发出应答信号,表示通信成功,否则表示通信失败。
2.5 I2C 设备地址格式
I2C
设备的地址为 8 位,但是时序操作时最后一位不属于地址,而是 R/W 状态位。所以有用的是前 7 位,使用时地址整体右移一位处理即可。
除此之位,一个设备地址的前四位是固定的,是厂家用来表示设备类型的:
- 比如接口为
I2C
的温度传感器类设备地址前四位一般为 1001 即 9X; - EEPROM 存储器地址前四位一般为 1010 即 AX;
- oled屏地址前四位一般为 0111 即 7X 等。
2.5 I2C 时序图
下面结合图例,将前面所提到的信息整合一下:
- 起始信号
当 SCL 为高电平期间,SDA 由高到低的跳变,起始信号是一种电平跳变时序信号,而不是一个电平信号。该信号由主机发出,在起始信号产生后,总线就处于被占用状态,准备数据传输。
- 停止信号
当 SCL 为高电平期间,SDA 由低到高的跳变;停止信号也是一种电平跳变时序信号,而不是一个电平信号。该信号由主机发出,在停止信号发出后,总线就处于空闲状态。
- 应答信号
发送器每发送一个字节,就在时钟脉冲 9 期间释放数据线,由接收器反馈一个应答信号。应答信号为低电平时,规定为有效应答位(ACK 简称应答位),表示接收器已经成功地接收了该字节;应答信号为高电平时,规定为非应答位(NACK),一般表示接收器接收该字节没有成功。
- 数据有效性
IIC 总线进行数据传送时,时钟信号为高电平期间,数据线上的数据必须保持稳定,只有在时钟线上的信号为低电平期间,数据线上的高电平或低电平状态才允许变化。数据在 SCL 的上升沿到来之前就需准备好。并在下降沿到来之前必须稳定。
- 数据传输
在 IIC
总线上传送的每一位数据都有一个时钟脉冲相对应(或同步控制),即在 SCL 串行时钟的配合下,在 SDA 上逐位地串行传送每一位数据。数据位的传输是边沿触发。
- 空闲状态
IIC
总线的 SDA 和 SCL 两条信号线同时处于高电平时,规定为总线的空闲状态。此时各个器件的输出级场效应管均处在截止状态,即释放总线,由两条信号线各自的上拉电阻把电平拉高。
2.5.1 I2C 写时序
要在 I2C
总线上写入,主机将在总线上发送:一个启动开始标志、从机地址、最后一位(R/W位)设置为 0,这表示写入。
从设备发送 ACK 响应确认后,主设备将发送其希望写入的寄存器的寄存器地址。从设备将再次确认,让主设备知道它已准备就绪。在此之后,主机将开始向从机发送寄存器数据,直到主机发送了它需要的所有数据(有时这只是一个字节),并且主机将以停止条件终止传输。
具体步骤如下:
- 开始信号。
- 发送
I2C
设备地址,每个I2C
器件都有一个设备地址,通过发送具体的设备地址来决定访问哪个I2C
器件。这是一个 8 位的数据,其中高 7 位是设备地址,最后 1 位是读写位(为 1 的话表示这是一个读操作,为 0 的话表示这是一个写操作)。 - 读写控制位,因为是向
I2C
从设备发送数据,因此是写信号 0。 - 从机发送的 ACK 应答信号。
- 重新发送开始信号。
- 发送要写入数据的寄存器地址。
- 从机发送的 ACK 应答信号。
- 发送要写入寄存器的数据。
- 从机发送的 ACK 应答信号。
- 停止信号。
2.5.2 I2C 读时序
主机为了读取从设备的数据,主机必须首先指出希望从从设备的哪个寄存器读取数据。这是由主机写入从设备的“写操作”类似的方式开始传输,通过发送 R/W 位等于 0 的地址(表示写入),然后是它希望从中读取的寄存器地址来完成的。
一旦从设备确认该寄存器地址,主机将再次发送启动条件,然后发送从设备地址,R/W 位设置为 1(表示读取)。这一次,从设备将确认读取请求,主机释放 SDA 总线,但将继续向从设备提供时钟。在这部分事务中,主机将成为主“接收器”,将成为从“发射器”。
主机将继续发送时钟脉冲 SCL,但会释放 SDA,以便从设备可以传输数据。在数据的每个字节结束时,主机将向从设备发送 ACK,让从设备知道它已准备好接收更多数据。一旦主机接收到预期的字节数,它将发送一个 NACK,向从设备发送信号以停止通信并释放总线。之后,主机将设置停止条件。
I2C
单字节读时序比写时序要复杂一点,读时序分为四个步骤,第一步是发送设备地址,第二步是发送要读取的寄存器地址,第三步重新发送设备地址,最后一步就是 I2C
从器件输出要读取的寄存器值,我们具体来看一下这步。
- 主机发送起始信号。
- 主机发送要读取的
I2C
从设备地址。 - 读写控制位,因为是向
I2C
从设备发送数据,因此是写信号 0。 - 从机发送的 ACK 应答信号。
- 重新发送 START 信号。
- 主机发送要读取的寄存器地址。
- 从机发送的 ACK 应答信号。
- 重新发送 START 信号。
- 重新发送要读取的
I2C
从设备地址。 - 读写控制位,这里是读信号 1,表示接下来是从
I2C
从设备里面读取数据。 - 从机发送的 ACK 应答信号。
- 从
I2C
器件里面读取到的数据。 - 主机发出 NACK 信号,表示读取完成,不需要从机再发送 ACK 信号了。
- 主机发出 STOP 信号,停止
I2C
通信。
2.5.3 单个/多个字节的写入/读取
-
写入单个字节
向从机设备的某一个寄存器写一个字节数据:开始信号+设备地址(7位)+读/写(1位)+等待从机应答+寄存器地址(8位)+等待从机应答+要写的数据(8位)+等待从机应答+终止信号
。 -
写入多个字节
向从机设备的某一个寄存器写多个字节数据:开始信号+设备地址(7位)+读/写(1位)+等待从机应答+寄存器地址(8位)+等待从机应答+要写的数据_1(8位)+等待从机应答+要写的数据_2(8位)+等待从机应答+······+要写的数据_N(8位)+等待从机应答+终止信号
。 -
读取一个字节
从机设备的某一个寄存器读取一个字节数据:开始信号+设备地址(7位)+写(1位)+等待从机应答+数据地址(8位)+等待从机应答+开始信号+设备地址(7位)+读(1位)+等待从机应答+从机返回读取数据_1(8位)+主机(接收机)不再应答+终止信号
-
读取多个字节
从从机设备的某一个寄存器读取多个字节数据:开始信号+设备地址(7位)+写(1位)+等待从机应答+数据地址(8位)+等待从机应答+开始信号+设备地址(7位)+读(1位)+等待从机应答+从机返回读取数据_1(8位)+主机(接收机)应答+从机返回读取数据_2(8位)+主机(接收机)应答+......+从机返回读取数据_N(8位)+主机(接收机)不再应答+终止信号
。
3、时钟同步和仲裁
3.1 时钟同步
在 I2C
总线上传送信息时的时钟同步信号是由挂接在 SCL 线上的所有器件的 逻辑“与” 完成的。即如果有多个主机同时产生时钟,那么只有所有主机都发送高电平时,SCL 上才表现为高电平,否则 SCL 都表现为低电平。
SCL 线上由高电平到低电平的跳变将影响到这些器件,一旦某个器件的时钟信号下跳为低电平,将使 SCL 线一直保持低电平,使 SCL 线上的所有器件开始低电平期。此时,低电平周期短的器件的时钟由低至高的跳变并不能影响 SCL 线的状态,于是这些器件将进入高电平等待的状态。当所有器件的时钟信号都上跳为高电平时,低电平期结束,SCL 线被释放返回高电平,即所有的器件都同时开始它们的高电平期。其后,第一个结束高电平期的器件又将 SCL 线拉成低电平。这样就在 SCL 线上产生一个同步时钟。
可见,时钟低电平时间由时钟低电平期最长的器件确定,而时钟高电平时间由时钟高电平期最短的器件确定。
3.2 时钟仲裁
总线仲裁与时钟同步类似,当所有主机在 SDA 上都写 1 时,SDA 的数据才是 1,只要有一个主机写 0,那此时 SDA 上的数据就是 0。
一个主机每发送一个 bit 数据,在 SCL 为高电平时,就检查 SDA 的电平是否和发送的数据一致,如果不一致,这个主机便知道自己输掉了仲裁,然后停止向 SDA 写数据。也就是说,如果主机一致检查到总线上数据和自己发送的数据一致,则继续传输,这样在仲裁过程中就保证了赢得仲裁的主机不会丢失数据。
输掉仲裁的主机在检测到自己输了之后也就不再产生时钟脉冲,并且要在总线空闲时才能重新传输。
仲裁的过程可能要经过多个 bit 的发送和检查,实际上两个主机如果发送的时序和数据完全一样,则两个主机都能正常完成整个数据传输。