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