GDE專欄 | Android Things中的I2C

谷歌開發者_發表於2017-03-15

640?wx_fmt=gif


文| 谷歌開發技術專家 王玉成 (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)


640?wx_fmt=png


單看上面的圖,為啥有三個 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 型別進行存放的。

640?wx_fmt=png


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

640?wx_fmt=png


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



讀寫操作

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

640?wx_fmt=png


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

640?wx_fmt=png


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


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


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

640?wx_fmt=png


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


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

640?wx_fmt=png


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


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


六大函式出場:

  • 8 位地址讀寫操作- readRegByte() 和 writeRegByte()

  • 16 位地址讀寫操作 - readRegWord() 和 writeRegWord()

  • 批量讀寫操作- readRegBuffer() and writeRegBuffer()


其中 Byte 是針對 8 位的 I2C 裝置,Word 是針對 16 位的裝置。

讀操作:用暫存器的地址做為引數。

寫操作:兩個引數,暫存器地址,和你要寫入的值。


上面的程式碼中,把暫存器的第 6 位置 1。所以操作流程是

  1. 讀出暫存器的值

  2. 將這個值的第6位置1 (value |= 0x40;)

  3. 然後把新的值寫回暫存器


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


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


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



傳輸原始資料

還是先來張圖吧:

640?wx_fmt=png


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


跟一個例子:

640?wx_fmt=png


這樣傳輸能帶來更高的傳輸效率,解決了 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 的一部分。


推薦閱讀:

GDE專欄 | 物聯網到底是什麼?

GDE專欄 | 完美支援Android Things的開發板都在這裡了

GDE專欄 | Android Things開發環境搭建

GDE專欄 | Android與Android Things,父子還是兄弟?

Android Things Developer Preview 2 釋出




640?wx_fmt=gif

相關文章