目录
I2C总线简介
主器件与从器件
工作原理
主要特点
数据传输
字节格式
应答响应
时钟同步
I2C 仲裁
传输模式
快速模式
高速模式
I2C协议标准代码
起始信号&停止信号
起始信号代码
停止信号代码
发送一个(8bit)字节
读取一个字节
应答
I2C 总线是由 Philips 公司开发的一种简单、双向二线制同步串行总线。它只需要两根线 SDA 、SCL 即可在连接于总线上的器件之间传送信息,I2C 总线数据传输速率在标准模式下可达 100kbit/s,快速模式下可达 400kbit/s,高速模式下可达 3.4Mbit/s,在超高速模式下可达到 5Mbit/s。
主器件用于启动总线传送数据,并产生时钟以开放传送的器件,此时任何被寻址的器件均被认为是从器件.在总线上主和从、发和收的关系不是恒定的,而取决于此时数据传送方向。如果主机要发送数据给从器件,则主机首先寻址从器件,然后主动发送数据至从器件,最后由主机终止数据传送;如果主机要接收从器件的数据,首先由主器件寻址从器件.然后主机接收从器件发送的数据,最后由主机终止接收过程。在这种情况下.主机负责产生定时时钟和终止数据传送。
SDA(串行数据线)和SCL(串行时钟线)都是双向I/O线,接口电路为开漏输出.需通过上拉电阻接电源VCC.当总线空闲时.两根线都是高电平,连接总线的外同器件都是CMOS器件,输出级也是开漏电路.在总线上消耗的电流很小,因此,总线上扩展的器件数量主要由电容负载来决定,因为每个器件的总线接口都有一定的等效电容.而线路中电容会影响总线传输速度.当电容过大时,有可能造成传输错误.所以,其负载能力为400pF,因此可以估算出总线允许长度和所接器件数量。
主器件用于启动总线传送数据,并产生时钟以开放传送的器件,此时任何被寻址的器件均被认为是从器件.在总线上主和从、发和收的关系不是恒定的,而取决于此时数据传送方向。如果主机要发送数据给从器件,则主机首先寻址从器件,然后主动发送数据至从器件,最后由主机终止数据传送;如果主机要接收从器件的数据,首先由主器件寻址从器件.然后主机接收从器件发送的数据,最后由主机终止接收过程。在这种情况下.主机负责产生定时时钟和终止数据传送。
主设备往从设备中写数据,如下图:
主设备从从设备中读数据,如下图:
发送到SDA 线上的每个字节必须为8 位,每次传输可以发送的字节数量不受限制。每个字节后必须跟一个响应位。首先传输的是数据的最高位(MSB),如果从机要完成一些其他功能后(例如一个内部中断服务程序)才能接收或发送下一个完整的数据字节,可以使时钟线SCL 保持低电平,迫使主机进入等待状态,当从机准备好接收下一个数据字节并释放时钟线SCL 后数据传输继续。
数据传输必须带响应,相关的响应时钟脉冲由主机产生。在响应的时钟脉冲期间发送器释放SDA 线(高)。
在响应的时钟脉冲期间,接收器必须将SDA 线拉低,使它在这个时钟脉冲的高电平期间保持稳定的低电平。
通常被寻址的接收器在接收到的每个字节后,除了用CBUS 地址开头的数据,必须产生一个响应。当从机不能响应从机地址时(例如它正在执行一些实时函数不能接收或发送),从机必须使数据线保持高电平,主机然后产生一个停止条件终止传输或者产生重复起始条件开始新的传输。
如果从机接收器响应了从机地址,但是在传输了一段时间后不能接收更多数据字节,主机必须再一次终止传输。这个情况用从机在第一个字节后没有产生响应来表示。从机使数据线保持高电平,主机产生一个停止或重复起始条件。
如果传输中有主机接收器,它必须通过在从机发出的最后一个字节时产生一个响应,向从机发送器通知数据结束。从机发送器必须释放数据线,允许主机产生一个停止或重复起始条件。
所有主机在SCL线上产生它们自己的时钟来传输I2C总线上的报文。数据只在时钟的高电平周期有效,因此需要一个确定的时钟进行逐位仲裁。
时钟同步通过线与连接I2C 接口到SCL 线来执行。这就是说SCL 线的高到低切换会使器件开始数它们的低电平周期,而且一旦器件的时钟变低电平,它会使SCL 线保持这种状态直到到达时钟的高电平。但是如果另一个时钟仍处于低电平周期,这个时钟的低到高切换不会改变SCL 线的状态。因此SCL 线被有最长低电平周期的器件保持低电平。此时低电平周期短的器件会进入高电平的等待状态。
当所有有关的器件数完了它们的低电平周期后,时钟线被释放并变成高电平。之后,器件时钟和SCL线的状态没有差别,而且所有器件会开始数它们的高电平周期。首先完成高电平周期的器件会再次将SCL线拉低。
这样产生的同步SCL 时钟的低电平周期由低电平时钟周期最长的器件决定,而高电平周期由高电平时钟周期最短的器件决定。
(1)I2C 仲裁:在多节点的 I2C 通信中,为解决两个或两个以上节点同时向一条总线发送数据形成的冲突,需要进行 I2C 总线仲裁。
(2)仲裁机制:根据总线线“与”逻辑原理,当有一个节点发送低电平时,总线上表现为低电平,而发送高电平的节点将会失去仲裁。(如果节点1为低电平0,总线表现也是低电平0,那么节点1与总线线与相同;如果节点2为高电平1,总线为低电平,那么节点2与总线线与结果不相同,那么节点2就会被制裁。)
(3)以下图 两个节点为例,DATA1 和 DATA2 分别是节点向总线所发送的数据信号,SDA 为总线上所呈现的数据信号,SCL 是总线上所呈现的时钟信号
起始:DATA 1 和 DATA 2 发送起始信号,DATA 1 和 DATA 2 为高电平,根据总线线“与”功能,总线为高电平,DATA 1、DATA 2 与 总线电平相同,继续发送数据。
第一个时钟周期:DATA1 和 DATA 2 为高电平,总线为高电平,DATA 1、DATA 2 继续发送数据。
第二个时钟周期:DATA1 和 DATA 2 为低电平,总线为低电平,DATA 1、DATA 2 继续发送数据。
第三个时钟周期:DATA1 为高电平,DATA2 为低电平,SDA 总线为低电平,DATA1 继续发送数据,DATA 2 与 SDA 总线电平不同失去仲裁。
快速模式器件可以在400kbit/s 下接收和发送。最小要求是:它们可以和400kbit/s 传输同步,可以延长SCL 信号的低电平周期来减慢传输。快速模式器件都向下兼容,可以和标准模式器件在0~100kbit/s 的I2C 总线系统通讯。但是,由于标准模式器件不向上兼容,所以不能在快速模式I2C 总线系统中工作。快速模式I2C 总线规范与标准模式相比有以下特征:
1、最大位速率增加到400kbit/s;
2、调整了串行数据(SDA) 和串行时钟(SCL )信号的时序;
3、快速模式器件的输入有抑制毛刺的功能,SDA 和SCL输入有施密特触发器;
4、快速模式器件的输出缓冲器对SDA 和SCL 信号的下降沿有斜率控制功能;
5、如果快速模式器件的电源电压被关断,SDA 和SCL 的I/O 管脚必须悬空,不能阻塞总线;
6、连接到总线的外部上拉器件必须调整以适应快速模式I2C 总线更短的最大允许上升时间。对于负载最大是200pF 的总线,每条总线的上拉器件可以是一个电阻,对于负载在200pF~400pF 之间的总线,上拉器件可以是一个电流源(最大值3mA )或者是一个开关电阻电路。
高速模式(Hs 模式)器件对I2C 总线的传输速度有巨大的突破。Hs 模式器件可以在高达3.4Mbit/s 的位速率下传输信息,而且保持完全向下兼容快速模式或标准模式(F/S 模式)器件,它们可以在一个速度混合的总线系统中双向通讯。
Hs 模式传输除了不执行仲裁和时钟同步外,与F/S 模式系统有相同的串行总线协议和数据格式。
高速模式下I2C 总线规范如下:
1、Hs 模式主机器件有一个SDAH 信号的开漏输出缓冲器和一个在SCLH 输出的开漏极下拉和电流源上拉电路。这个电流源电路缩短了SCLH 信号的上升时间,任何时候在Hs 模式,只有一个主机的电流源有效;
2、在多主机系统的Hs 模式中,不执行仲裁和时钟同步,以加速位处理能力。仲裁过程一般在前面用F/S 模式传输主机码后结束;
3、Hs 模式主机器件以高电平和低电平是1:2 的比率产生一个串行时钟信号。解除了建立和保持时间的时序要求;
4、可以选择Hs 模式器件有内建的电桥。在Hs 模式传输中,Hs 模式器件的高速数据(SDAH)和高速串行时钟(SCLH )线通过这个电桥与F/S 模式器件的SDA 和SCL 线分隔开来。减轻了SDAH 和SCLH 线的电容负载,使上升和下降时间更快;
5、Hs 模式从机器件与F/S 从机器件的唯一差别是它们工作的速度。Hs 模式从机在SCLH 和SDAH输出有开漏输出的缓冲器。SCLH 管脚可选的下拉晶体管可以用于拉长SCLH 信号的低电平,但只允许在Hs 模式传输的响应位后进行;
6、Hs 模式器件的输出可以抑制毛刺,而且SDAH 和SCLH 输出有一个施密特触发器;
7、Hs 模式器件的输出缓冲器对SDAH 和SCLH 信号的下降沿有斜率控制功能。
起始信号:当 SCL 线是高电平时 SDA 线从高电平向低电平切换。
停止信号:当 SCL 线是高电平时 SDA 线由低电平向高电平切换。
void I2C_Start(void)
{
I2C_SDA_High(); //SDA=1,初始状态,SDA线空闲
I2C_SCL_High(); //SCL=1,初始状态,SDA=1,SDA线空闲
I2C_Delay(); //延时
I2C_SDA_Low(); //SDA=0,SDA线有效
I2C_Delay(); //延时
I2C_SCL_Low(); //SDA=0,SCL=0;
I2C_Delay();
}
void I2C_Stop(void)
{
I2C_SDA_Low(); //SDA=0,数据线有效
I2C_SCL_High(); //SCL=1.信号线为高电平,则需要将SDA设置为1;
I2C_Delay(); //延时
I2C_SDA_High(); //SDA=1,数据线失效
I2C_Delay();
}
CPU向I2C总线设备发送一个字节(8bit)数据
u8 I2C_SendByte(uint8_t Byte)
{
uint8_t i;
/* 先发送高位字节 */
for(i = 0 ; i < 8 ; i++)
{
if(Byte & 0x80)
{
I2C_SDA_High();
}
else
{
I2C_SDA_Low();
}
I2C_Delay();
I2C_SCL_High();
I2C_Delay();
I2C_SCL_Low();
I2C_Delay();
if(i == 7)
{
I2C_SDA_High(); /* 释放SDA总线 */
}
Byte <<= 1; /* 左移一位 */
I2C_Delay();
}
}
CPU从I2C总线设备上读取一个字节(8bit数据)
u8 I2C_ReadByte(void)
{
uint8_t i;
uint8_t value;
/* 先读取最高位即bit7 */
value = 0;
for(i = 0 ; i < 8 ; i++)
{
value <<= 1;
I2C_SCL_High();
I2C_Delay();
if(I2C_SDA_READ())
{
value++;
}
I2C_SCL_Low();
I2C_Delay();
}
return value;
}
CPU产生一个ACK信号
void I2C_Ack(void)
{
I2C_SDA_Low();
I2C_Delay();
I2C_SCL_High();
I2C_Delay();
I2C_SCL_Low();
I2C_Delay();
I2C_SDA_High();
}
CPU产生一个非ACK信号
void I2C_NoAck(void)
{
I2C_SDA_High();
I2C_Delay();
I2C_SCL_High();
I2C_Delay();
I2C_SCL_Low();
I2C_Delay();
}
CPU产生一个时钟,并读取器件的ACK应答信号
uint8_t I2C_WaitToAck(void)
{
uint8_t redata;
I2C_SDA_High();
I2C_Delay();
I2C_SCL_High();
I2C_Delay();
if(I2C_SDA_READ())
{
redata = 1;
}
else
{
redata = 0;
}
I2C_SCL_Low();
I2C_Delay();
return redata;
}