Android Things中的I2C
上一講中,我們說(shuō)到 Android Things 的 API,以及 Peripheral I/O 設(shè)備包含的 API 的類(lèi)型。但是作為程序員的我們,怎么理解這些 API 呢?
我們就拿 I2C 的 API 來(lái)說(shuō)吧??纯次覀?cè)鯓釉?Android Things 中添加一個(gè) I2C 的設(shè)備?首先得知道,I2C 是做什么的?怎么用?
實(shí)際上,I2C 是同步的串行通信總線,一般用于控制信號(hào),比如控制 LCD, Camera 等設(shè)備。另外,大部分傳感器有 I2C 的接口。I2C 是依靠時(shí)鐘信號(hào)來(lái)傳遞數(shù)據(jù)的,所以有主設(shè)備(產(chǎn)生時(shí)鐘的信號(hào))和從設(shè)備(接收時(shí)鐘的信號(hào))之分。I2C 的通信每一次操作都是由主設(shè)備的發(fā)起的。
既然 I2C 是依靠時(shí)鐘傳遞的信號(hào),那么在連線上就有時(shí)鐘錢(qián) (SCL) 和數(shù)據(jù)線 (SDA),然后為了電勢(shì)與大地相同,自然少不了地線 (GND)。為了方便沒(méi)有接觸過(guò) I2C 總線的同學(xué)們理解這三個(gè)名詞,貼上名詞的全稱(chēng):
- Shared clock signal (SCL)
- Shared data line (SDA)
- Common ground reference (GND)
單看上面的圖,為啥有三個(gè) I2C 設(shè)備連接在一起呢?這三者之間又是什么關(guān)系?
其中,寫(xiě)有 Master Device 的 I2C 設(shè)備,稱(chēng)為主設(shè)備,另外兩個(gè)為從設(shè)備。從主設(shè)備引出的 SDA 和 SCL 線構(gòu)成 I2C 的總線。一個(gè) I2C 的主設(shè)備可以提供一條 I2C 的總線,一條總線上***可以連接 127 個(gè) I2C 的從設(shè)備。
等等,為啥是 127 個(gè)呢?主要是 I2C 的地址有 7 位和 10 位兩種地址。也就意味著,對(duì)于 7 位的地址表達(dá)的數(shù)據(jù)***可以到 2^7=128,減去一個(gè)主設(shè)備,就是 127 個(gè)從設(shè)備了。這里的 I2C 設(shè)備地址,就是上圖的 Address: 0x3c 和 0x4c,I2C 的主設(shè)備是通過(guò)從設(shè)備的地址,來(lái)找到從設(shè)備的。請(qǐng)注意,I2C 的主設(shè)備,是沒(méi)有設(shè)備地址這一說(shuō)法的。
我們還需要了解 I2C 的一些硬件信息:
I2C 是半雙工,可以有主 -> 從方向的數(shù)據(jù),也可以有從 -> 主方向的數(shù)據(jù),但是同一時(shí)刻,只能有一種傳輸方式。這點(diǎn)和 SPI 是有差別的,SPI 總線支持全雙工模式。但它同時(shí)只能訪問(wèn)一個(gè)從設(shè)備,由片選信號(hào) (CS) 來(lái)決定。這就很明顯了,I2C 通常用于控制命令的傳輸。而 SPI 通常用數(shù)據(jù)的批量傳輸。
了解完 I2C 的基本硬件信息。我們來(lái)了解一下 I2C 的從設(shè)備操作方式。不多不多,就是三大步。
- 連接從設(shè)備
- 對(duì)從設(shè)備進(jìn)行讀操作
- 對(duì)從設(shè)備進(jìn)行寫(xiě)操作
設(shè)備連接
先要檢查我們的物聯(lián)網(wǎng)設(shè)備上有沒(méi)有 I2C 總線。這時(shí)需要補(bǔ)充一下,有可能你的開(kāi)發(fā)板上有多個(gè) I2C 的總線。這時(shí)候, I2C 的總線地址 (此處非 I2C 的設(shè)備地址) 是有多個(gè)的,要明確你的 I2C 設(shè)備是接在哪個(gè) I2C 的總線上。這也可以理解,為什么得到的 I2C 總線的數(shù)據(jù)是用 List 類(lèi)型進(jìn)行存放的。
如果有總線,我們?cè)俨檎耶?dāng)前的 I2C 總線上對(duì)應(yīng)的 I2C 設(shè)備。
關(guān)鍵的接口是 manager.openI2CDeivce(..),這個(gè)函數(shù)有兩個(gè)參數(shù),DEVICE_NAME 是用戶(hù)定義的一個(gè)字符串,表示設(shè)備的名稱(chēng)。I2C_ADDRESS,也是之前所說(shuō)的 I2C 從設(shè)備上的地址,這個(gè)地址在當(dāng)前的 I2C 總線上是唯一的。
讀寫(xiě)操作
首先得把 I2C 的操作流程搬出來(lái)說(shuō)了。
這張圖翻譯成中文就是這樣子的:
這樣就完成了向設(shè)備地址為 0x30、寄存器地址為 0x10 的設(shè)備上讀或者寫(xiě)入 0x06 這個(gè)數(shù)據(jù)。
那怎么知道是讀數(shù)據(jù),還是寫(xiě)數(shù)據(jù)呢?實(shí)際上 I2C 是 7 位的地址位。但是一個(gè)字節(jié)是 8 位,其中有一位叫做讀寫(xiě)位。如果那一位設(shè)為讀,就是去讀操作,如果設(shè)為寫(xiě),就是寫(xiě)操作。實(shí)際上,在示波器上我們還能看到另外的一個(gè) ACK 位,保證硬件上傳輸正常,ACK 位在軟件上不需要處理。
那么,加上 I2C 的讀寫(xiě)位之后, I2C 數(shù)據(jù)傳輸會(huì)是什么樣的呢?
我們可以看到, I2C 數(shù)據(jù)傳輸?shù)臅r(shí)序,從硬件上來(lái)說(shuō) SCL 是按周期發(fā)的時(shí)鐘信號(hào),當(dāng) SCL 是高電平時(shí),SDA 產(chǎn)生一個(gè)下降沿,這時(shí)候開(kāi)始數(shù)據(jù)傳輸。其中傳輸 I2C 的從設(shè)備地址共有 8 位,1-7 位是地址,第 8 位是讀寫(xiě)位,0 表示寫(xiě),1 表示讀。然后硬件自動(dòng)產(chǎn)生 ACK 位。接下來(lái)就是數(shù)據(jù)傳輸?shù)恼麄€(gè)過(guò)程,***當(dāng)數(shù)據(jù)傳完后,SCL 為高電平,SDA 產(chǎn)生上升沿時(shí),產(chǎn)生 STOP 操作。事實(shí)上,在 I2C 做讀操作需要往 I2C 的設(shè)備寫(xiě)入隨機(jī)值,再去讀,不過(guò)這些操作在 I2C 相關(guān)的接口中已經(jīng)為我們封裝好了。
這么大篇幅介紹了 I2C 的原理,還有 I2C 的時(shí)序,操作流程。實(shí)際上,Android Things 已經(jīng)幫我們把讀寫(xiě)接口封裝好了,我們只需要在理解的基礎(chǔ)上,調(diào)用接口就行了。
可以看出,Android Things 已經(jīng)給我們封裝好了 I2C 的讀寫(xiě)操作 ,我們直接用就可以了。
這里面還有個(gè)細(xì)節(jié)比較繞。之前提到, I2C 的設(shè)備地址可以是 7 位,也可以是 10 位,但是 I2C 設(shè)備的寄存器可以是 8 位,也可以是 16 位。這里面就涉及到 8 位的設(shè)備,以及 16 位設(shè)備的讀寫(xiě)問(wèn)題。
六大函數(shù)出場(chǎng):
- 8 位地址讀寫(xiě)操作- readRegByte() 和 writeRegByte()
- 16 位地址讀寫(xiě)操作 - readRegWord() 和 writeRegWord()
- 批量讀寫(xiě)操作- readRegBuffer() and writeRegBuffer()
其中 Byte 是針對(duì) 8 位的 I2C 設(shè)備,Word 是針對(duì) 16 位的設(shè)備。
- 讀操作:用寄存器的地址做為參數(shù)。
- 寫(xiě)操作:兩個(gè)參數(shù),寄存器地址,和你要寫(xiě)入的值。
上面的代碼中,把寄存器的第 6 位置 1。所以操作流程是
- 讀出寄存器的值
- 將這個(gè)值的第6位置1 (value |= 0x40;)
- 然后把新的值寫(xiě)回寄存器
不過(guò)對(duì)于 16 位的地址操作還有一個(gè)大小端的問(wèn)題。(什么是大小端?去 Google 吧 )現(xiàn)在的 API 是依照小端模式來(lái)讀寫(xiě)的 16 位設(shè)備地址。
直接批量數(shù)據(jù)操作,可以***讀到 32 個(gè)連續(xù)的寄存器的數(shù)值。
那么,我們?cè)趺词褂媒涌谶M(jìn)行批量操作呢?
傳輸原始數(shù)據(jù)
還是先來(lái)張圖吧:
這種操作方法,不同于上面的讀寫(xiě)寄存器。在 I2C 的操作中,屬于 burst 操作方法。即一次性的讀寫(xiě)多少字節(jié),***再停止。
跟一個(gè)例子:
這樣傳輸能帶來(lái)更高的傳輸效率,解決了 I2C 傳輸?shù)暮诵膯?wèn)題,我們也解決了支持 I2C 的任何外設(shè)的讀寫(xiě)問(wèn)題。
后記
Android Things 的 SDK 中,Peripheral I/O 部分是包括三種總線的,UART, I2C, SPI。對(duì)于軟件開(kāi)發(fā)人員來(lái)說(shuō),有下面幾點(diǎn)需要注意:
- UART 開(kāi)發(fā),需要了解 UART 的波特率、流控等概念。
- SPI 開(kāi)發(fā),需要了解 MISO, MOSI,CLK, GND, CS 這些連線的作用,還有 SPI 的操作模式等,SDK 中的接口,與上文的 I2C 的開(kāi)發(fā)流程相似。
- I2C開(kāi)發(fā),就不用接著說(shuō)了吧
【本文是51CTO專(zhuān)欄機(jī)構(gòu)“谷歌開(kāi)發(fā)者”的原創(chuàng)稿件,轉(zhuǎn)載請(qǐng)聯(lián)系原作者(微信公眾號(hào):Google_Developers)】