1. 程式人生 > >i2c匯流排篇一

i2c匯流排篇一

1.what is I2C?

簡單講就是用來傳輸資料的兩根線:一根資料線(SDA)一根時鐘線(SCL)

2.I2C怎麼傳輸的?

(1)基本過程:

     1.主機發出開始訊號

     2.主機接著發出一位元組的從機地址資訊,其中最低位為讀寫控制碼(1為讀、0為寫)

 高七位為從機器件地址

     3.從機發出認可訊號

     4.主機開始傳送訊號,每發完一位元組後,從機發出認可訊號給主機

     5.主機發出停止訊號

 

(2)對以上訊號的具體說明:

     開始訊號:在時鐘線為高電平期間,資料線由高變低,將產生一個開始訊號

     停止訊號:在時鐘線為高電平期間,資料線由低變高,將產生一個停止訊號

     應答訊號:即認可訊號,主機寫從機時,每寫完一個位元組,如果正確從機將在下一個時鐘週期將資料線拉低,以告訴主機操作有效。在主機讀從機的時候,正確讀完一個位元組後,主機在下一個時鐘週期同樣也要將資料線拉低,發出認可訊號,告訴從機所發資料已經收妥(注:讀從機時主機在最後一個位元組資料接收完後,不發應答,直接發停止訊號)

注意:任何在時鐘線為高電平期間的資料線上的電平改變都被認為是起始和停止訊號,所以資料改變必須要在時鐘為低電平時改變。

(3)資料格式:

     

I2C支援兩種資料格式:

7bit/10bit定址資料格式

7bit/10bit定址和重複開始訊號的格式

從裝置地址:

總線上每個裝置都有自己的一個addr,共7個bit,廣播地址全0.
系統中可能有多個同種晶片,為此addr分為固定部分和可程式設計部份,細節視晶片而定,看datasheet。

 

硬體結構:

每一個I2C匯流排器件內部的SDA、SCL引腳電路結構都是一樣的,引腳的輸出驅動與輸入緩衝連在一起。其中輸出為漏極開路的場效電晶體、輸入緩衝為一隻高輸入阻抗的同相器。這種電路具有兩個特點:

(1)由於 SDA、SCL 為漏極開路結構,藉助於外部的上拉電阻實現了訊號的“線與”邏輯; 
(2)引腳在輸出訊號的同時還將引腳上的電平進行檢測,檢測是否與剛才輸出一致。為 “時鐘同步”和“匯流排仲裁”提供硬體基礎。

3.幾個I2C的疑問

(1)模擬I2C與硬體I2C有什麼區別

     原理上:硬體I2C(提供專門的SDA,SCL口)的時鐘是系統產生的,一般由晶振分頻產生。模擬I2C通過程式設計模擬時鐘線和資料線。

     控制上:硬體I2C通過硬體中斷實現各種操作。模擬I2C沒有中斷的概念,通過IO口電平置高置低來實現寫入和讀取。

     效能上:硬體模式更高效更穩定。

(2)MPU6050和MPU9250的I2C

     之前對於這兩個晶片的通過I2C的操作地址有點亂,如要獲取到加速度計的原始值,首先要傳送開始訊號,然後是傳送從機地址(I2C的裝置地址),然後傳送暫存器的地址(這裡很多人會搞亂了,因為要發兩次地址,第一次是I2C裝置地址,第二次是加速度計的地址),接下來才能獲取到原始資料。

4.怎麼實現I2C?

 之前的所有鋪墊都是為了實現I2C通訊,所以怎麼用程式碼實現也是尤為關鍵的一個問題。

下面是是I2C的讀寫流程:

寫暫存器的標準流程為:
1.    Master發起START
2.    Master傳送I2C addr(7bit)和w操作0(1bit),等待ACK
3.    Slave傳送ACK
4.    Master傳送reg addr(8bit),等待ACK
5.    Slave傳送ACK
6.    Master傳送data(8bit),即要寫入暫存器中的資料,等待ACK
7.    Slave傳送ACK
8.    第6步和第7步可以重複多次,即順序寫多個暫存器
9.    Master發起STOP

讀暫存器的標準流程為:
1.    Master傳送I2C addr(7bit)和w操作1(1bit),等待ACK
2.    Slave傳送ACK
3.    Master傳送reg addr(8bit),等待ACK
4.    Slave傳送ACK
5.    Master發起START
6.    Master傳送I2C addr(7bit)和r操作1(1bit),等待ACK
7.    Slave傳送ACK
8.    Slave傳送data(8bit),即暫存器裡的值
9.    Master傳送ACK
10.    第8步和第9步可以重複多次,即順序讀多個暫存器

以上通訊流程模擬I2C跟硬體I2C都類似,不同的地方是讀寫:

如MSP430的程式:

模擬I2C傳送資料

void LCD_WrCmd(unsigned char cmd)

{

    unsigned char i=8, temp=0;

    //LCD_DC=0;

    for(i=0;i<8;i++) //傳送一個八位資料

    {

        LCD_SCL_L;

       

        temp = cmd&0x80;

        if (temp == 0)

        {

            LCD_SDA_L;

        }

        else

        {

            LCD_SDA_H;

        }

        LCD_SCL_H;

        cmd<<=1;;        

    }     

}

通過時鐘線SCL和資料線SDA的高低電平來傳入資料

而硬體I2C:

//寫入資料// Load TX buffer

void USCI_B1_I2C_WriteByte(unsigned char byte)

{

  while(!(UCB1IFG & UCTXIFG));

  UCB1TXBUF = byte;

}

直接通過UCB1TXBUF 來發送