I2C通信協議
項目要求是,通過通信線,是實現單片機讀寫外掛模塊寄存器的功能,至少實現,在指定位置寫寄存器和在指定位置讀寄存器,實現了讀寫寄存器,就實現對模塊的控制。
MPU6050,OLED,AT24C02(存儲器模塊),DS3231(實時時鐘模塊)
一主多從指單片機作為主機主導I2C總線的運行,掛載在I2C總線上的所有設備都是從機,只有主機允許才可以控制I2C總線;多主多從是指多個主機,任何一個模塊都可以作為主機,當沖突時對其進行仲裁,誰勝利誰成為主機。
作為一個通信協議,I2C必須在硬件和軟件上作出規定。硬件上的規定包括電路的連接方式、端口的輸入輸出模式等;軟件上的規定包括時序的定義、字節的傳輸方式、高位先行還是低位先行等。這些硬件和軟件的規定結合起來構成了一個完整的通信協議。
硬件電路
主機永遠擁有SCL時鐘線的控制權,在空閑時可以主動操控SDA線,也可以將SDA線的控制權交給從機;從機權力較小,永遠只能被動的讀取SCL線,不允許控制,從機不允許主動發起對SDA的控制,只有在主機發送從機讀取的命令后或者從機應答的時候從機才能短暫的取得SDA的控制權。這就是一主多從模型中協議的規定。
如果總線時序沒有協調好,就極有可能發生兩個引腳同時處于輸出的狀態。如果此時一個引腳輸出高電平,一個引腳輸出低電平,就會造成電源短路的情況,這是要極力避免的。
為了避免這種情況,I2C的設計規定所有設備不輸出強上拉的高電平,而是采用外置弱上拉電阻加開漏輸出的電路結構。這兩點規定對應于前面提到的“設備的SCL和SDA均要配置成開漏輸出模式”以及“SCL和SDA各添加一個上拉電阻,阻值一般為4.7KΩ左右”。對應上面這個圖。
引腳內部結構圖
圖左側展示的是SCL的結構,其中SClk代表SCL;右側則是SDA的結構,其中DATA代表SDA。
引腳的信號輸入都可以通過一個數據緩沖器或施密特觸發器進行,因為輸入對電路無影響,所以任何設備在任何時刻都可以輸入。然而,在輸出部分,采用的是開漏輸出的配置。
輸出低電平,這個開關管導通,引腳直接接地,是強下拉,輸出高電平,這個開關管斷開,引腳什么都不接,處于浮空狀態,這樣的話,所有的設備都只能輸出低電平而不能輸出高電平,為了避免高電平造成的引腳浮空,這時就需要在總線外面,SCL和SDA各外置一個上拉電阻,這是通過一個電阻拉到高電平的,所以這是一個弱上拉。
- 第一,完全杜絕了電源短路現象,保證電路的安全。
第二,避免了引腳模式的頻繁切換。開漏加弱上拉的模式,同時兼具了輸入和輸出的功能。因為開漏模式下,輸出高電平就相當于斷開引腳,所以在輸入之前,可以直接輸出高電平,不需要再切換成輸入模式了。
第三,就是這個模式會有一個“線與”的現象。就是只要有任意一個或多個設備輸出了低電平,總線就處于低電平,只有所有設備都輸出高電平,總線才處于高電平。
I2C可以利用這個電路特性執行多主機模式下的時鐘同步和總線仲裁,所以這里SCL雖然在一主多從模式下可以用推挽輸出,但是它仍然采用了開漏加上拉輸出的模式,因為在多主機模式下會利用到這個特征。
I2C時序基本單元
起始條件是指SCL高電平期間,SDA從高電平切換到低電平。在I2C總線處于空閑狀態時,SCL和SDA都處于高電平狀態,由外掛的上拉電阻保持。當主機需要數據收發時,會首先產生一個起始條件。這個起始條件是,SCL保持高電平,然后把SDA拉低,產生一個下降沿。當從機捕獲到這個SCL高電平,SDA下降沿信號時,就會進行自身的復位,等待主機的召喚。之后,主機需要將SCL拉低。這樣做一方面是占用這個總線,另一方面也是為了方便這些基本單元的拼接。這樣,除了起始和終止條件,每個時序單元的SCL都是以低電平開始,低電平結束。
**終止條件是,SCL高電平期間,**SDA從低電平切換到高電平。SCL先放開并回彈到高電平,SDA再放開并回彈高電平,產生一個上升沿。這個上升沿觸發終止條件,同時終止條件之后,SCL和SDA都是高電平,回歸到最初的平靜狀態。這個起始條件和終止條件就類似串口時序里的起始位和停止位。一個完整的數據幀總是以起始條件開始、終止條件結束。另外,起始和終止都是由主機產生的。因此,從機必須始終保持雙手放開,不允許主動跳出來去碰總線。如果允許從機這樣做,那么就會變成多主機模型,不在本節的討論范圍之內。這就是起始條件和終止條件的含義。
發送一個字節
主機拉低SCL,把數據放在SDA上,主機松開SCL,從機讀取SDA的數據。
在SCL的同步下,依次進行主機發送和從機接收,循環8次,就發送了8位數據,也就是一個字節,另外注意,這里是高位先行,所以第一位是一個字節的最高位B7,然后依次是次高位B6…最后是B0。(串口時序是低位先行,I2C是高位先行)
另外,由于這里有時鐘線進行同步,所以如果主機一個字節發送一半,突然進中斷,不操作SDA,SCL,那時序就會在中斷不斷拉長,SDA,SCL電平都暫停變化,傳輸也暫停,等中斷結束后,主機繼續回來操作,傳輸仍然不會出問題,這就是同步時序的好處。
接收一個字節
發送應答和接收應答
I2C的完整時序
主要有指定地址寫,當前地址讀和指定地址讀這3種。
I2C總線上每個從機都確定一個唯一的設備地址,主機在起始條件之后會先發送一個字節確認相應的設備地址,相應的設備響應之后的讀寫操作,MPU6050地址為1101000
首先,SCL高電平期間,拉低SDA,產生起始條件(start,s),在起始條件后,緊跟著時序,必須是發送一個字節的時序,字節的內容,必須是從機地址+讀寫位,正好從機地址是7位,讀寫位是1位,加起來是1個字節,8位,發送從機地址,就是確定從機的對象。發送讀寫位,就是確認接下來要寫入還是讀出。在這里低電平期間,SDA變換數據,高電平期間,從機讀取SDA。綠色的線,標明從機得到的數據。然后就是1101000,0表示之后的時序主機要進行寫操作,1表示之后的時序主機要進行讀出操作,這里是0說明之后要進行寫操作。
那這里,目前主機是發送一個字節,字節的內容轉換為16進制,高位先行,就是0xD0,然后根據協議規定,緊跟著單元是,就是接收從機的應答位,在這個時刻,主機要釋放SDA,釋放SDA后,引腳電平回彈到高電平,但是根據協議規定,從機要在這個位拉低SDA,所以從機的波形是這樣的,該應答的時候,從機立刻拽住SDA,然后應答結束后,從機在放開SDA,現在綜合兩者的波形,結合線與的特性,在主機釋放SDA后,由于SDA被從機拽住了,SDA沒有回彈高電平,這個過程代表從機產生了應答。
首先,SCL高電平期間,拉低SDA,產生起始條件(start,s),起始條件開始后,主機必須首先調用發送一個字節,來進行從機的尋址和指定讀寫標志位。圖示的波形,表示本次尋址的目標是1101 000的設備,同時最后一位,讀寫標志為1,表示主機接下來想要讀取數據,緊跟著,發送一個字節后,接收一下從機的應答位。從機應答0,代表從機收到一個字節。
在從機應答后,從這里開始,數據的傳輸方向就要反過來了,因為主機發出了讀的命令,所以之后,主機就不能繼續發送了,要把SDA控制權交給從機,主機調用接收一個字節的操作,進行接收操作。
指定地址讀=指定地址寫+當前地址讀
該時序下從中間紅線分割,前半部分為指定地址寫在寫之前的時序,后半部分為當前地址讀的時序,因為在前半部分中指定了地址,所以可以讀出指定地址的數據。