标题：iic
I2C总线的硬件结构
I2C串行总线一般有两根信号线，一根是双向的数据线SDA，另一根是时钟线SCL。所有接到I2C总线设备上的串行数据SDA都接到总线的SDA上，各设备的时钟线SCL接到总线的SCL上。
为了避免总线信号的混乱，要求各设备连接到总线的输出端时必须是漏极开路（OD）输出或集电极开路（OC）输出。设备上的串行数据线SDA接口电路应该是双向的，输出电路用于向总线上发送数据，输入电路用于接收总线上的数据。而串行时钟线也应是双向的，作为控制总线数据传送的主机，一方面要通过SCL输出电路发送时钟信号，另一方面还要检测总线上的SCL电平，以决定什么时候发送下一个时钟脉冲电平；作为接受主机命令的从机，要按总线上的SCL信号发出或接收SDA上的信号，也可以向SCL线发出低电平信号以延长总线时钟信号周期。总线空闲时，因各设备都是开漏输出，上拉电阻Rp使SDA和SCL线都保持高电平。任一设备输出的低电平都将使相应的总线信号线变低，也就是说：各设备的SDA是“与”关系，SCL也是“与”关系。 
总线对设备接口电路的制造工艺和电平都没有特殊的要求（NMOS、CMOS都可以兼容）。在I2C总线上的数据传送率可高达每秒十万位，高速方式时在每秒四十万位以上。另外，总线上允许连接的设备数以其电容量不超过400pF为限。 
总线的运行（数据传输）由主机控制。所谓主机是指启动数据的传送（发出启动信号）、发出时钟信号以及传送结束时发出停止信号的设备，通常主机都是微处理器。被主机寻访的设备称为从机。为了进行通讯，每个接到I2C总线的设备都有一个唯一的地址，以便于主机寻访。主机和从机的数据传送，可以由主机发送数据到从机，也可以由从机发到主机。凡是发送数据到总线的设备称为发送器，从总线上接收数据的设备被称为接受器。 
I2C总线上允许连接多个微处理器以及各种外围设备，如存储器、LED及LCD驱动器、A/D及D/A转换器等。为了保证数据可靠地传送，任一时刻总线只能由某一台主机控制，各微处理器应该在总线空闲时发送启动数据，为了妥善解决多台微处理器同时发送启动数据的传送（总线控制权）冲突，以及决定由哪一台微处理器控制总线的问题，I2C总线允许连接不同传送速率的设备。多台设备之间时钟信号的同步过程称为同步化。
I2C数据传输
在I2C总线传输过程中，将两种特定的情况定义为开始和停止条件（见图3）：当SCL保持“高”时，SDA由“高”变为“低”为开始条件；当SCL保持“高”且SDA由“低”变为“高”时为停止条件。开始和停止条件均由主控制器产生。使用硬件接口可以很容易地检测到开始和停止条件，没有这种接口的微机必须以每时钟周期至少两次对SDA取样，以检测这种变化。 
  开始和停止条件图3SDA线上的数据在时钟“高”期间必须是稳定的，只有当SCL线上的时钟信号为低时，数据线上的“高”或“低”状态才可以改变。输出到SDA线上的每个字节必须是8位，每次传输的字节不受限制，但每个字节必须要有一个应答ACK。如果一接收器件在完成其他功能（如一内部中断）前不能接收另一数据的完整字节时，它可以保持时钟线SCL为低，以促使发送器进入等待状态；当接收器准备好接受数据的其它字节并释放时钟SCL后，数据传输继续进行。I2C数据总线传送时序如图4所示。 
数据传送具有应答是必须的。与应答对应的时钟脉冲由主控制器产生，发送器在应答期间必须下拉SDA线。当寻址的被控器件不能应答时，数据保持为高并使主控器产生停止条件而终止传输。在传输的过程中，在用到主控接收器的情况下，主控接收器必须发出一数据结束信号给被控发送器，从而使被控发送器释放数据线，以允许主控器产生停止条件。合法的数据传输格式如下：
I2C总线在开始条件后的首字节决定哪个被控器将被主控器选择，例外的是“通用访问”地址，它可以在所有期间寻址。当主控器输出一地址时，系统中的每一器件都将开始条件后的前7位地址和自己的地址进行比较。如果相同，该器件即认为自己被主控器寻址，而作为被控接收器或被控发送器则取决于R/W位。
I2C总线的应用
I2C总线是各种总线中使用信号线最少，并具有自动寻址、多主机时钟同步和仲裁等功能的总线。因此，使用I2C总线设计计算机系统十分方便灵活，体积也小，因而在各类实际应用中得到广泛应用。下面举二个应用示例。
I2C的运用比如在铁电存储器中，用铁电存储数据就是用的I2C总线协议。
伺服控制系统用I2C扩展LCD显示器图5是一个伺服系统的结构图。它用8XC752单片机的PWM输出经放大后来驱动电机，电机的转速由测速机测取并直接送到8XC752片内的A/D电路。处理后的有关信息经I2C总线送到LCD驱动芯片PCF8577以驱动64段LCD显示板。
通用I/O端口作为I2C总线接口目前，51、96系列的单片机应用很广，但是由于它们都没有I2C总线接口，从而限制了在这些系统中使用具有I2C总线接口的器件。通过对I2C总线时序的分析，可以用51单片机的两根I/O线来实现I2C总线的功能。接I2C总线规定：SCL线和SDA线是各设备对应输出状态相“与”的结果，任一设备都可以用输出低电平的方法来延长SCL的低电平时间，以迫使高速设备进入等待状态，从而实现不同速度设备间的时钟同步。因此，即使时钟脉冲的高、低电平时间长短不一，也能实现数据的可靠传送，可以用软件控制I/O口做I2C接口。下面就是用GMS97C2051的通用I/O口来作为I2C总线接口，并由软件控制实现数据传送的例子，图6为其连线图。 
在单主控器的系统中，时钟线仅由主控器驱动，因此可以用51系列的一根I/O线作为SCL的信号线，将其设备为输出方式，并由软件控制来产生串行时钟信号。在实际系统中使用了P1.3。另一根I/O线P1.2作为I2C总线的串行数据线，可在软件控制下在时钟的低电平期间读取或输出数据。系统传输数据的过程如下：先由单片机发出一个启始数据信号，接着送出要访问器件的7位地址数据，并等待被控器件的应答信号。当收以应答信号后，根据访问要求进行相应的操作。如果是读入数据，则数据线可一直设为输入方式，中间不需要改变SDA线的工作方式，每读入一个字节均应依次检测应答信号；如果是输出数据，则首先将SDA设置为输出方式，当发送完一个字节后，需要改变SDA线为输入方式，此时读入被控器件的应答信号就完成了一个字节的传送。当所有数据传输完毕后，应向SDA发出一个停止信号，以结束该次数据传输。
I2C范例下面给出51系列用汇编语言实现启始、停止、读、写、应答的程序，读者也可以根据I2C总线时序在96系列或其它单片机上实现I2C总线接口。 
a.启动位程序 
ACK：CLR P1.3 
NOP 
NOP 
SETB P1.2 
NOP 
NOP 
NOP 
CPL P1.3 ；P1.3=1 
NOP 
NOP 
NOP 
DENGDAI：JB P1.2，DENGDAI 
RET 
b.读数据程序 
读字节可以在当前地址读（CURRENT 
READ），也可以随机读（RANDOM READ），读出数据的最后一个字节后不用加应答信号。 
READ：PUSH 0EH 
CLR P1.4 
LCALL BSTART ；START 
MOV A，#0A0H ；SEND THE CNOTROL BYTE 
LCALL SENDBYTE 
LCALL ACK 
MOV A，R1 ；SEND THE ADDRESS 
LCALL SENDBYTE 
LCALL ACK 
LCALL BSTART ；START 
MOV A，#0A1H ；SEND THE CNOTROL BYTE 
LCALL SENDBYTE 
LCALL ACK 
LCALL READBYTE 
LCALL BSTOP 
POP 0EH 
RET 
送字节程序： 
SENDBYTE：PUSH 0EH 
PUSH 00H 
MOV R0,#08H 
LOOP1:CLR P1.3 
NOP 
NOP 
RLC A 
MOV P1.2,C 
CPL P1.3 ;P1.3=1 
NOP 
NOP 
DJNZ R0,LOOP1 
POP 00H 
POP 0EH 
RET 
读字节子程序： 
READBYTE：PUSH 0EH 
PUSH 00H 
MOV R0，#08H；READ THE CONTENT 
CLR A 
LOOP4：CLR P1.3 
NOP 
NOP 
NOP 
SETB P1.3 ；P1.3=1 
MOV C,P1.2 
RLC A 
DJNZ R0,LOOP4 
MOV R2,A 
POP 00H 
POP 0EH 
RET 
c.写数据程序： 
WRITE：PUSH 0EH 
CLR P1.4 
LCALL BSTART 
MOV A，#0A0H 
CLALL SENDBYTE ；SEND THE CONTROL BYTE 
LCALL ACK 
MOV A，R1 ；SEND THE ADDRESS 
LCALL SENDBYTE 
LCALL ACK 
MOV A，R2 ；WRITE THE CONTENT 
LCALL SENDBYTE 
LCALL ACK 
LCALL BSTOP 
POP 0EH 
RET 
连续写的两个字节之间最好是有10ms的延时。当然，也可以进行页写（PAGE 
WRITE），即一次性连续写8个字节，但采用页写方式时每个字节后要有一个应答信号。 
d.停止位程序： 
BSTOP：CLR P1.3 
NOP 
NOP 
CLR P1.2 
NOP 
NOP 
NOP 
SETB P1.3 
NOP 
NOP 
NOP 
SETB P1.2 
RET