什么是I2C
I2C(Inter-Integrated Circuit),也可以叫IIC、I2C,译作集成电路总线,是两线式串行通信总线,用于设备间的通讯等,标准情况下最高传送速率达100Kbps。顾名思义,I2C通讯只需要两根线,一根是数据线SDA(Serial Data Line),一根是时钟线SCL(Serial Clock Line)。主设备控制时钟线决定I2C的波特率,配合数据线进行数据的传输,这两根线分别通过上拉电阻连接到电源
特点
- 一种相对简单的通信协议,适合短距离(比如小于1m)通信
- 总线通信速率 100kHz 或 400kHz,相比其他协议,通信速率较低
- 只需要四个引脚(VCC,GND,SDA,SCL)
- 半双工
- 没有严格的波特率要求
- 最大主设备数:无限制;
- 最大从机数:理论上是127;
和SPI通信类似,I2C通信的两个数据线分别为SCL时钟线和SDA数据线。所有的数据操作都是在这两个数据线的输出的共同作用下产生的,类似于SPI的CS/SS、SCLK、MOSI之间的相互作用。
I2C的高阻态
漏极开路(Open Drain)即高阻状态,适用于输入/输出,其可独立输入/输出低电平和高阻状态,若需要产生高电平,则需使用外部上拉电阻高阻状态:高阻状态是三态门电路的一种状态。逻辑门的输出除有高、低电平两种状态外,还有第三种状态——高阻状态的门电路。电路分析时高阻态可做开路理解。我们知道IIC的所有设备是接在一根总线上的,那么我们进行通信的时候往往只是几个设备进行通信,那么这时候其余的空闲设备可能会受到总线干扰,或者干扰到总线,怎么办呢?为了避免总线信号的混乱,IIC的空闲状态只能有外部上拉, 而此时空闲设备被拉到了高阻态,也就是相当于断路, 整个IIC总线只有开启了的设备才会正常进行通信,而不会干扰到其他设备
数据传输协议
主设备和从设备进行数据传输时遵循以下协议格式。数据通过一条SDA数据线在主设备和从设备之间传输0和1的串行数据。串行数据序列的结构可以分为:
- 总线空闲状态:SCL和SDA都处在高电平。
- 起始信号:SCL高电平时SDA从高到低。
- 终止信号:SCL高电平时SDA从低到高。
- 数据传输:按字节发送、SDA在时钟低电平切换、高电平保持。
- 回应(应答位):I2C最大的一个特点就是有完善的应答机制,从机接收到主机的数据时,会回复一个应答信号来通知主机表示“我收到了”。应答信号: 出现在1个字节传输完成之后,即第9个SCL时钟周期内,此时主机需要释放SDA总线,把总线控制权交给从机,由于上拉电阻的作用,此时总线为高电平,如果从机正确的收到了主机发来的数据,会把SDA拉低,表示应答响应
- 停止位:当主设备决定结束通讯时,需要发送结束信号, 先将SDA线从低电平切换到高电平;再将SCL线从高电平拉到低电平;
标准流程总结为:
- Master发起STARTMaster发送I2C addr(7bit)和w操作0(1bit)
- 等待ACK
- Slave发送ACKMaster发送reg addr(8bit)
- 等待ACK
- Slave发送ACKMaster发送data(8bit),即要写入寄存器中的数据,
- 等待ACK
- Slave发送ACK
- 第6步和第7步可以重复多次,即顺序写多个寄存器
- Master发起STOP
仲裁机制
如果有两个或两个以上的节点都向总线上发送启动信号并开始传送数据,这样就形成了冲突。要解决这种冲突,就要进行仲裁的判决,这就是I2C总线上的仲裁。I2C总线上的仲裁分两部分:SCL线的同步和SDA线的仲裁。
- SCL同步: SCL同步是由于总线具有线 “与”
的逻辑功能(开漏输出),即只要有一个节点发送低电平时,总线上就表现为低电平。当所有的节点都发送高电平时,总线才能表现为高电平。正是由于线“与”逻辑功能的原理,当多个节点同时发送时钟信号时,在总线上表现的是统一的时钟信号,这就是SCL的同步原理。 - SDA线的仲裁:
总线仲裁是为了解决多设备同时竞争中线控制权的问题,通过一定的裸机来决定哪个设备能够获得最终的总线控制权。SDA线的仲裁也是建立在总线具有线“与”逻辑功能的原理上的。节点在发送1位数据后,比较总线上所呈现的数据与自己发送的是否一致,低电平优先(类似于CAN总线的回读机制)。是,继续发送;否则,退出竞争;
I2C总线的控制逻辑:低电平优先SDA线的仲裁可以保证I2C总线系统在多个主节点同时企图控制总线时通信正常进行并且数据不丢失,总线系统通过仲裁只允许一个主节点可以继续占据总线。
I2C死锁
在实际使用过程中,I2C比较容易出现的一个问题就是死锁 ,死锁在I2C中主要表现为:I2C死锁时表现为SCL为高,SDA一直为低。在I2C主设备进行读写操作的过程中,主设备在开始信号后控制SCL产生8个时钟脉冲,然后拉低SCL信号为低电平,在这个时候,从设备输出应答信号,将SDA信号拉为低电平。如果这个时候主设备异常复位,SCL就会被释放为高电平。此时,如果从设备没有复位,就会继续I2C的应答,将SDA一直拉为低电平,直到SCL变为低电平,才会结束应答信号。而对于I2C主设备来说,复位后检测SCL和SDA信号,如果发现SDA信号为低电平,则会认为I2C总线被占用,会一直等待SCL和SDA信号变为高电平。这样,I2C主设备等待从设备释放SDA信号,而同时I2C从设备又在等待主设备将SCL信号拉低以释放应答信号,两者相互等待,I2C总线进人一种死锁状态。同样,当I2C进行读操作,I2C从设备应答后输出数据,如果在这个时刻I2C主设备异常复位而此时I2C从设备输出的数据位正好为0,也会导致I2C总线进入死锁状态。