在硬件上,I2C總線是由時鐘總線SCL和數據總線SDA兩條線構成,連接到總線上的所有器件的SCL都連到一起,所有SDA都連到一起。I2C總線是開漏引腳并聯的結構,因此我們外部要添加上拉電阻。對于開漏電路外部加上拉電阻,就組成了線“與”的關系。總線上線“與”的關系就是說,所有接入的器件保持高電平,這條線才是高電平,而任何一個器件輸出一個低電平,那這條線就會保持低電平,因此可以做到任何一個器件都可以拉低電平,也就是任何一個器件都可以作為主機,如圖14-1所示,我們添加了 R63 和 R64 兩個上拉電阻。
圖14-1 I2C 總線的上拉電阻
雖然說任何一個設備都可以作為主機,但絕大多數情況下我們都是用單片機來做主機,而總線上掛的多個器件,每一個都像電話機一樣有自己唯一的地址,在信息傳輸的過程中,通過這唯一的地址就可以正常識別到屬于自己的信息,在 KST-51 開發板上,就掛接了2個 I2C 設備,一個是 24C02,一個是 PCF8591。
我們在學習 UART 串行通信的時候,知道了通信流程分為起始位、數據位、停止位這三部分,同理在 I2C 中也有起始信號、數據傳輸和停止信號,如圖14-2所示。
圖14-2 I2C 時序流程圖
從圖上可以看出來,I2C 和 UART 時序流程有相似性,也有一定的區別。UART 每個字節中,都有一個起始位、8個數據位、1位停止位。而 I2C 分為起始信號、數據傳輸部分、停止信號。其中數據傳輸部分,可以一次通信過程傳輸很多個字節,字節數是不受限制的,而每個字節的數據最后也跟了一位,這一位叫做應答位,通常用 ACK 表示,有點類似于 UART 的停止位。
下面我們一部分一部分的把 I2C 通信時序進行剖析。之前我們已經學過了 UART,所以學習 I2C 的過程我盡量拿 UART 來作為對比,這樣有助于更好的理解。但是有一點大家要理解清楚,就是 UART 通信雖然用了 TXD 和 RXD 兩根線,但是實際一次通信中,1條線就可以完成,2條線是把發送和接收分開而已,而 I2C 每次通信,不管是發送還是接收,必須2條線都參與工作才能完成,為了更方便的看出來每一位的傳輸流程,我們把圖14-2改進成圖14-3。
圖14-3 I2C 通信流程解析
起始信號:UART 通信是從一直持續的高電平出現一個低電平標志起始位;而 I2C 通信的起始信號的定義是 SCL 為高電平期間,SDA 由高電平向低電平變化產生一個下降沿,表示起始信號,如圖14-3中的 Start 部分所示。
數據傳輸:首先,UART 是低位在前,高位在后;而 I2C 通信是高位在前,低位在后。其次,UART 通信數據位是固定長度,波特率分之一,一位一位固定時間發送完畢就可以了。而 I2C 沒有固定波特率,但是有時序的要求,要求當 SCL 在低電平的時候,SDA 允許變化,也就是說,發送方必須先保持 SCL 是低電平,才可以改變數據線 SDA,輸出要發送的當前數據的一位;而當 SCL 在高電平的時候,SDA 絕對不可以變化,因為這個時候,接收方要來讀取當前 SDA 的電平信號是0還是1,因此要保證 SDA 的穩定,如圖14-3中的每一位數據的變化,都是在 SCL 的低電平位置。8位數據位后邊跟著的是一位應答位,應答位我們后邊還要具體介紹。
停止信號:UART 通信的停止位是一位固定的高電平信號;而 I2C 通信停止信號的定義是 SCL 為高電平期間,SDA 由低電平向高電平變化產生一個上升沿,表示結束信號,如圖14-3中的 Stop 部分所示。