Android Thing 專題 5 I2C

weixin_34357887發表於2017-03-27

文| 谷歌開發者技術專家, 物聯網方向 (IOT GDE) 王玉成(York Wang)

上一講中,我們說到 Android Things 的 API,以及 Peripheral I/O 裝置包含的 API 的型別。但是作為程式設計師的我們,怎麼理解這些 API 呢?

我們就拿 I2C 的 API 來說吧。看看我們怎樣在 Android Things 中新增一個 I2C 的裝置?首先得知道,I2C 是做什麼的?怎麼用?

實際上,I2C 是同步的序列通訊匯流排,一般用於控制訊號,比如控制 LCD, Camera等裝置。另外,大部分感測器有 I2C 的介面。I2C 是依靠時鐘訊號來傳遞資料的。所以有主裝置(產生時鐘的訊號)和從裝置(接收時鐘的訊號)之分。I2C 的通訊每一次操作都是由主裝置的發起的。

既然 I2C 是依靠時鐘傳遞的訊號,那麼在連線上就有時鐘錢 (SCL) 和資料線 (SDA),然後為了電勢與大地相同,自然少不了地線 (GND)。為了方便沒有接觸過 I2C 匯流排的同學們理解這三個名詞,貼上名詞的全稱:
Shared clock signal (SCL)
Shared data line (SDA)
Common ground reference (GND)

這裡寫圖片描述

單看上面的圖,為啥有三個 I2C 裝置連線在一起呢?這三者之間又是什麼關係?

其中,寫有 Master Device 的 I2C 裝置,稱為主裝置,另外兩個為從裝置。從主裝置引出的 SDA 和 SCL 線,構成 I2C 的匯流排。一個 I2C 的主裝置可以提供一條 I2C 的匯流排。一條匯流排上,最後可以連線 127 個 I2C 的從裝置。

等等,為啥是 127 個呢?主要是 I2C 的地址有 7 位和 10 位兩種地址。也就意味著,對於 7 位的地址表達的資料最大可以到 2^7=128,減去一個主裝置,就是 127 個從裝置了。這裡的 I2C 裝置地址,就是上圖的 Address: 0x3c 和 0x4c,I2C 的主裝置是通過從裝置的地址,來找到從裝置的。請注意,I2C 的主裝置,是沒有裝置地址這一說法的。

我們還需要了解 I2C 的一些硬體資訊:
I2C 是半雙工,可以有主 -> 從方向的資料,也可以有從 -> 主方向的資料,但是同一時刻,只能有一種傳輸方式。這點和 SPI 是有差別的,SPI 匯流排支援全雙工模式。但它同時只能訪問一個從裝置,由片選訊號 (CS) 來決定。這就很明顯了,I2C 通常用於控制命令的傳輸。而 SPI 通常用資料的批量傳輸。

瞭解完 I2C 的基本硬體資訊。我們來了解一下 I2C 的從裝置操作方式。不多不多,就是三大步。
連線從裝置
對從裝置進行讀操作
對從裝置進行寫操作

裝置連線

先要檢查我們的物聯網裝置上有沒有 I2C 匯流排。這時需要補充一下,有可能你的開發板上有多個 I2C 的匯流排。這時候, I2C 的匯流排地址 (此處非 I2C 的裝置地址) 是有多個的,要明確你的 I2C 裝置是接在哪個 I2C 的匯流排上。這也可以理解,為什麼得到的 I2C 匯流排的資料是用 List 型別進行存放的。

這裡寫圖片描述

如果有匯流排,我們再查詢當前的 I2C 匯流排上對應的 I2C 裝置。

這裡寫圖片描述

關鍵的介面是 manager.openI2CDeivce(..),這個函式有兩個引數,DEVICE_NAME 是使用者定義的一個字串,表示裝置的名稱。I2C_ADDRESS,也是之前所說的 I2C 從裝置上的地址,這個地址在當前的 I2C 匯流排上是唯一的。

讀寫操作

首先得把 I2C 的操作流程搬出來說了。

這裡寫圖片描述

這張圖翻譯成中文就是這樣子的:

這裡寫圖片描述

這樣就完成了向裝置地址為 0x30 的 I2C 的裝置,暫存器地址為 0x10 的裝置上讀或者寫入 0x06 這個資料。

那怎麼知道往從裝置是讀資料,還是寫資料呢?實際上 I2C 是 7 位的地址位。但是一個位元組是 8 位,那位,其中有一位叫做讀寫位。如果那一位設為讀,就是去做操作,如果設為寫,就是寫操作。實際上,在示波器上我們還能看到另外的一個 ACK 位,保證硬體上傳輸正常。

那麼,加上 I2C 的讀寫位之後, I2C 資料傳輸會是什麼樣的呢?

這裡寫圖片描述

我們可以看到, I2C 資料傳輸的時序,從硬體上來說 SCL 是按週期發的時鐘訊號,當 SCL 是高電平時,SDA 產生一個下降沿,這時候開始資料傳輸。其中傳輸 I2C 的從裝置地址共有 8 位,1-7 位是地址,第 8 位是讀寫位,0 表示寫,1 表示讀。然後硬體自動產生 ACK 位。接下來就是資料傳輸的整個過程,最後當資料傳完後,SCL 為高電平,SDA 產生上升沿時,產生 STOP 操作。實示上,在 I2C 做讀操作需要往 I2C 的裝置寫入隨機值,再去讀,不過這些操作在 I2C 相關的介面中已經為我們封裝好了。

這裡寫圖片描述

這麼大篇幅介紹了 I2C 的原理,還有 I2C 的時序,操作流程。實際上,Android Things 已經幫我們把讀寫介面封裝好了,我們只需要在理解的基礎上,呼叫介面就行了。

可以看出, I2C 的讀寫操作 Android Things 已經給我們封裝好了,我們直接用就可以了。

這裡面還有個細節比較繞。之前提到, I2C 的裝置地址可以是 7 位,也可以是 10 位,但是 I2C 裝置的暫存器可以是 8 位,也可以是 16 位。這裡面就涉及到 8 位的裝置,以及 16 位裝置的讀寫問題。

六大函式出場:
8 位地址讀寫操作- readRegByte() 和 writeRegByte()
16 位地址讀寫操作 - readRegWord() 和 writeRegWord()
批量讀寫操作- readRegBuffer() and writeRegBuffer()

其中 Byte 是針對 8 位的 I2C 裝置,Word 是針對 16 位的裝置。
讀操作:用暫存器的地址做為引數。
寫操作:兩個引數,暫存器地址,和你要寫入的值。

上面的程式碼中,把暫存器的第 6 位置 1。所以操作流程是
讀出暫存器的值
將這個值的第6位置1 (value |= 0x40;)
然後把新的值寫回暫存器

不過對於 16 位的地址操作還有一個大小端的問題。(什麼是大小端?去 Google 吧 )現在的 API 是依照小端模式來讀寫的 16 位裝置地址。

直接批量資料操作,可以最大讀到32個連續的暫存器的數值。

那麼,我們怎麼使用介面進行批量操作呢?

傳輸原始資料

還是先來張圖吧:

這裡寫圖片描述

這種操作方法,不同於上面的讀寫暫存器。在 I2C 的操作中,屬於 burst 操作方法。即一次性的讀寫多少位元組,最後再停止。

跟一個例子:

這裡寫圖片描述

這樣傳輸能帶來更高的傳輸效率。解決了 I2C 傳輸的核心問題,我們也解決了支援 I2C 的任何外設的讀寫問題。

後記

Android Things 的 SDK 中,Peripheral I/O 部分是包括三種匯流排的,UART, I2C, SPI。對於軟體開發人員來說,有下面幾點需要注意:
UART 開發,需要了解 UART 的波特率、流控等概念。
SPI 開發,需要了解 MISO, MOSI,CLK, GND, CS 這些連線的作用,還有 SPI 的操作模式等,SDK 中的介面,與上文的 I2C 的開發流程相似。
I2C開發,就不用接著說了吧

下一講我們會展示一個完整的 Android Things 應用。

您如果有任何涉及到 Android Things 方面的想法,都歡迎大家在下方留言,我們會把好的建議轉交給 Android Things 的產品部門。也許在某一天,你的建議就是 Andorid Things 的一部分。

相關文章