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;
}
