關於I2C總線的詳解和實現


I2C總線是兩條線,一條串行數據(SDA),一條串行時鐘(SCL),兩根線能與總線上的設備實現通信,每個器件都有唯一的地址,而且都可以作為一個發送器一個接收器(根據器件功能決定)。

I2C特點:

1、 只需要兩根線就可以實現數據傳輸:一條串行數據(SDA),一條串行時鐘(SCL)。

2、 每個連接到總線上的器件都有一個唯一的地址。

3、 I2C是8位的雙向數據傳輸,通信是高位在前,地位在後。

4、 傳輸速率標準模式下100Kbit/s,快速模式下 400Kbit/s, 高速模式下可達3.4Mbit/s

5、 I2C發送從機地址,地址有7位,緊跟著的第8位,是代表方向為。0表示寫,1表示讀。

I2C採用的是主從通信方式,所以在通信之前,由主設備發送一個起始信號,開始數據的傳送,並且在結束通信時,也必須由主設備發送一個結束信號,表示通信結束。

I2C的起始信號和結束信號

起始信號: (SCL)時鐘線為高電平時,(SDA)數據線由高電平向低電平跳變,表示起始信號。

結束信號:(SCL)時鐘線為高電平時,(SDA)數據線由低電平向高電平跳變,表示結束信號

關於I2C總線的詳解和實現

下面是51單片機對應的代碼部分

起始信號代碼

Void I2C_Start(void)

{

<strong>I2C_SDA=1;

<strong>I2C_SCL=1;

<strong>I2C_Delay();

I2C_SDA=0;

I2C_Delay();

I2C_SCL=0;

}

結束信號代碼

void I2C_Stop(void)

{

I2C_SDA=0;

I2C_SCL=0;

I2C_Delay();

I2C_SCL=1;

I2C_Delay();

I2C_SDA=1;

}

I2C應答信號

主設備每次發送完一個8bit數據,後面會在第9位等待從機一個應答信號,這時候我們會釋放SDA數據線,拉高電平,當從機應答SDA會被拉低,若從機沒有應答,SDA還是高電平,這樣會引起主機(stop)結束本次流程。

關於I2C總線的詳解和實現

主機發送數據給從機,主機等待從機應答,收到從機應答代表數據傳輸完成,下面是等待從機應答的代碼

Unsigned char I2C_WaitSlave_Ack()

{

unsigned char cnt=0;

I2C_SDA=1;

I2C_Delay();

I2C_SCL=1;

While(I2C_SDA)//等待從機應答

{

cnt++;

if(cnt>=200)//如果等待從機應答計數200次還沒應答終止本次數據傳輸

{

I2C_Stop();

return 1;

}

}

I2C_SCL=0;

Return 0;

}

當我們發送數據給從機需要等待從機應答,同樣的從機把我們需要的數據發給我們的時候主機也需要給從機一個應答,代表我們收到它傳給我們的數據了,如果不應答代表我們結束了本次數據的傳輸。

下面用代碼來實現這個過程

主機不應答代碼

Void I2C_Master_NAck()

{

I2C_SDA=1;

I2C_Delay();

I2C_SCL=1;

I2C_Delay();

I2C_SCL=0;

}

主機應答代碼

void I2C_Master_Ack()

{

I2C_SDA=0;

I2C_Delay();

I2C_SCL=1;

I2C_Delay();

I2C_SCL=0;

}

I2C位數據傳輸

I2C數據傳輸: 若SCL是高電平時,SDA保持當前穩定狀態,那麼SDA上傳輸一個Bit數據。

I2C數據改變:SCL是為低電平時,SDA才可以改變傳輸的bit數據,當SCL由低電平變為高電平時,SDA上的Bit數據就不能改變了,當SCL再變為低電平時,SDA就是一個有效的Bit數據了。

如果SCL高電平時,SDA電平發生了跳變,就有可能產生一個起始信號或者是結束信號。

關於I2C總線的詳解和實現

發送數據給從機

Void I2C_Send_Data(unsigned char dat)

{

Unsigned char i=0;

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

{

I2C_SDA=(dat&0x80)>>7;

dat<<=1;

<strong> I2C_Delay();

I2C_SCL=1;

I2C_Delay();

I2C_SCL=0;

}

}

讀取從機的數據,當從機把數據發給我們時,如果我們還想從 從機哪裡讀取數據就要給從機一個應答,如果不應答代表這次數據傳輸結束,下面代碼最後加了一個條件語句就是實現這個功能的。

Void I2C_Read_Data(bit ack)

{

unsigned char dat=0;

Unsigned char i=0;

I2C_SDA=1;

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

{

I2C_Delay();

I2C_SCL=1;

if(I2C_SDA)

dat=((dat<<1)|0x01);

else

dat<<=1;

<strong> I2C_Delay();

I2C_SCL=0;

}

If(ack)

I2C_Master_Ack();//應答

Else

I2C_Master_NAck();//不應答

Return dat;

}


分享到:


相關文章: