文| 谷歌开发人员技术专家, 物联网方向 (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)

watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvd2Zpbmc=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast" alt="这里写图片描写叙述" title="">

单看上面的图,为啥有三个 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 类型进行存放的。

Android Things专题5 I2C-LMLPHP

假设有总线。我们再查找当前的 I2C 总线上相应的 I2C 设备。

Android Things专题5 I2C-LMLPHP

关键的接口是 manager.openI2CDeivce(..),这个函数有两个參数。DEVICE_NAME 是用户定义的一个字符串,表示设备的名称。I2C_ADDRESS,也是之前所说的 I2C 从设备上的地址,这个地址在当前的 I2C 总线上是唯一的。

读写操作

首先得把 I2C 的操作流程搬出来说了。

Android Things专题5 I2C-LMLPHP

这张图翻译成中文就是这样子的:

Android Things专题5 I2C-LMLPHP

这样就完毕了向设备地址为 0x30 的 I2C 的设备。寄存器地址为 0x10 的设备上读或者写入 0x06 这个数据。

那怎么知道往从设备是读数据,还是写数据呢?实际上 I2C 是 7 位的地址位。

可是一个字节是 8 位。那位,当中有一位叫做读写位。假设那一位设为读。就是去做操作。假设设为写。就是写操作。实际上。在示波器上我们还能看到另外的一个 ACK 位,保证硬件上传输正常。

那么,加上 I2C 的读写位之后, I2C 传输数据会是什么样的呢?

watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvd2Zpbmc=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast" alt="这里写图片描写叙述" title="">

我们能够看到。 I2C 传输数据的时序,从硬件上来说 SCL 是按周期发的时钟信号,当 SCL 是高电平时。SDA 产生一个下降沿,这时候開始传输数据。当中传输 I2C 的从设备地址共同拥有 8 位,1-7 位是地址,第 8 位是读写位。0 表示写,1 表示读。然后硬件自己主动产生 ACK 位。接下来就是传输数据的整个过程,最后当数据传完后,SCL 为高电平,SDA 产生上升沿时,产生 STOP 操作。

实示上,在 I2C 做读操作须要往 I2C 的设备写入随机值,再去读,只是这些操作在 I2C 相关的接口中已经为我们封装好了。

Android Things专题5 I2C-LMLPHP

这么大篇幅介绍了 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个连续的寄存器的数值。

那么,我们怎么使用接口进行批量操作呢?

传输原始数据

还是先来张图吧:

Android Things专题5 I2C-LMLPHP

这样的操作方法。不同于上面的读写寄存器。在 I2C 的操作中。属于 burst 操作方法。即一次性的读写多少字节,最后再停止。

跟一个样例:

Android Things专题5 I2C-LMLPHP

这样传输能带来更高的传输效率。攻克了 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 的一部分。

05-21 16:57