IIC时序的理解


I2C 总线上的通信通常发生在两个器件之间,其中一个作为主机,另一个为从机。同一总线上可以连接多个地址不同的器件。

I2C 总线由两条线路组成,SDA 线和 SCL 线,SDA 传送数据,SCL 提供时钟,所有数据以 8 位为一组通过 I2C 总线传送。为了在 I2C 总线上传送 1 位数据,须在SCL为低电平时驱动 SDA 线至适当的电平(SDA 为低则表明该位为 0,为高则表明该位为 1)。一旦 SDA 线稳定下来 SCL 线被拉高,然后变低,SCL 线上的脉冲以时钟将SDA位一位一位地移入接收器的移位寄存器中。

I2C 总线是双向的:SDA 线可用来发送和接收数据。当主机从从机中读取数据时,从机驱动数据线,当主机向从机发送数据时,主机驱动数据线,主机总是驱动时钟线。

通信时,总线被激活,只有主机才能发起一次通信,为了开始通信,主机

在总线上形成一个开始条件。通常,只有在时钟线为低电平时,数据线才允许改变状态,如果在时钟线为高电平时,数据线改变了状态,则形成一个开始条件或相反地形成一个停止条件。

总线空闲时:不发生通信时,时钟线数据线为高电平

通常传输数据时:时钟线为低电平时,数据线才允许改变状态。

开始条件时钟线为高电平时,数据线从高到低的跳变

停止条件:时钟线为高电平时,数据线从低到高的跳变。

  

 

主机发送开始条件以后,它还会发送一个字节表明它想与哪一个从机通信,该字节称作地址字节。I2C 总线上的每个器件都有唯一的 7 位地址,以作出响应。主机以地址字节发送一个地址,并且还发出一位以表明是对从机读出还是写入。

  当A2,A1,A0都为1时,写操作时最低位为1,则此时地址为10101110(即0xAE);读操作时最低位为0,则此时地址为10101111(即0xAF); 

I2C 总线上发送的每个字节,无论是地址还是数据,均以一个应答位作为响应,在主机发送完一个字节(即 8 位)数据到从机后,它停止驱动 SDA 线,并等待从机对该字节的应答,从机将SDA 线拉低,以对该字节进行应答。然后主机发送一个时钟脉冲来对该应答位定时,类似地,当主机完成对一个字节的读取时,则将 SDA 线拉低以对从机作出应答,然后发送一个时钟脉冲对该位定时

(记住主机总是驱动时钟线)。在一个应答周期期间不作应答,只是保持 SDA 线为高电平。如果器件不在总线上,并且如果主机试图对其寻址,它不会接收到应答信号,因为该地址处没有器件将 SDA 线拉低。

 

主机完成与从机的通信后,它会发出一个停止条件。在发出停止条件后,总线再次空闲,主机也可发出另一个开始条件。 

代码示例:

产生IIC起始信号

void IIC_Start(void)

{

  SDA_OUT();    

  delay_us(4);

  IIC_SDA=1;      

  IIC_SCL=1;

  delay_us(4);

  IIC_SDA=0; 

  delay_us(4);

  IIC_SCL=0;

}  

 

产生IIC停止信号

void IIC_Stop(void)

{

  SDA_OUT();

  IIC_SDA=0;//STOP:when CLK is high DATA change form low to high

  IIC_SCL=1;

  delay_us(1);

  IIC_SDA=1;

  delay_us(4);    

}

 

等待应带信号。1:接收应答失败;0:接收应答成功

u8 IIC_Wait_Ack(void)

{

  u8 ucErrTime=0;

  SDA_IN();       

  IIC_SDA=1;delay_us(1);    

  IIC_SCL=1;delay_us(1);  

  while(READ_SDA)

  {

    ucErrTime++;

    if(ucErrTime>250)

    {

      IIC_Stop();

      return 1;

    } 

  } 

  IIC_SCL=0;    

  return 0;   

}

 

产生ACK应答 

void IIC_Ack(void) 

{

  IIC_SCL=0;

  SDA_OUT(); 

  IIC_SDA=0; 

  delay_us(2);

  IIC_SCL=1;

  delay_us(2);

  IIC_SCL=0;

}

 

不产生ACK应答      

void IIC_NAck(void) 

{

  IIC_SCL=0;

  SDA_OUT();

  IIC_SDA=1;

  delay_us(2);

  IIC_SCL=1;

  delay_us(2);

  IIC_SCL=0;

}        

 

发送一个字节   

void IIC_Send_Byte(u8 txd)

{                        

  u8 t;   

  SDA_OUT();     

  IIC_SCL=0;

  for(t=0;t<8;t++)

   {              

    if((txd&0x80)>>7)

      IIC_SDA=1;

    else

      IIC_SDA=0;

    txd<<=1;   

    delay_us(2);   

    IIC_SCL=1;

    delay_us(2);

    IIC_SCL=0;

    delay_us(2);

   }  

}     

 

读取一个字节。Ack=1,发送ACK;ack=0,发送nACK

u8 IIC_Read_Byte(unsigned char ack)

  unsigned char i,receive=0;

  SDA_IN();

  for(i=0;i<8;i++ )

  {

          IIC_SCL=0;

          delay_us(2);

    IIC_SCL=1;

         receive<<=1;

    if(READ_SDA)receive++;   

    delay_us(1);

  }  

  if (!ack)

    IIC_NAck();

  else

    IIC_Ack(); 

   return receive;

}

 

 

 

 


免责声明!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系本站邮箱yoyou2525@163.com删除。



 
粤ICP备18138465号  © 2018-2025 CODEPRJ.COM