在上一篇文章里,我们介绍了《Android Things 教程:Android Things 设置输入/输出指南上:GPIO、PWM、I2C》,在这篇文章里,我们将介绍剩下的 SPI、UART 以及其他高级接口。
除了支持全双工通信外,串行外设接口(SPI)连接与 I2C 连接类似。这意味着数据可以同时读写外设,而不需要主设备从从外设请求信息。仍然需要一个时钟信号,来控制来自 SPI 信号总线上多个器件的数据流。SPI 需要至少四个连接才能工作:
另外,如果多个 SPI 设备连接到 SPI 总线,则需要第五个连接。这是片选(CS),用于发信号给外设的硬件地址,以便您的主器件可以与特定的从器件通信。
使用 SPI 的外设的一些例子,包括 LED 点阵板和 SD 卡读卡器,值得注意的是许多支持 I2C 的外设也将支持 SPI。
就像前面的例子一样,您需要知道 Android Things 板上 SPI 连接的名称。你可以通过创建一个 PeripheralManagerService
并在该对象上调用 getSpiBusList()
来找到它。在一个树莓派,你将有以下可用:
[SPI0.0, SPI0.1]
一旦知道了将要使用的 SPI 总线的名称,就可以打开它的连接。
private SpiDevice mDevice;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
try {
PeripheralManagerService manager = new PeripheralManagerService();
mDevice = manager.openSpiDevice(SPI_DEVICE_NAME);
} catch (IOException e) {
}
}
为了使设备通过 SPI 总线进行通信,它们都必须 “说同一种语言”,也就是说,它们必须配置为相同的时钟频率和数据格式。虽然有些外设可以调整数据格式和时钟频率,但其他的则不行。由于 SPI 总线上的所有器件必须以相同配置运行,所以在尝试将其包含在 SPI 总线上之前,了解外设的功能非常重要。有四个设置/参数需要为您的 SPI 总线设置:
big-endian
,首先把最重要的大(MSB)。在您的 Android Things java 代码中,您可以在 SPI 总线上设置以下四个值:
// Low clock, leading edge transfer
device.setMode(SpiDevice.MODE0);
device.setFrequency(16000000);
device.setBitsPerWord(8);
device.setBitJustification(false);
如何在 SPI 总线上与您的设备进行交互,取决于您是在全双工还是半双工模式下工作。如果您的设备配置为半双工模式,那么您将需要使用 SpiDevice
对象上的 read()
和 write()
方法在从设备和主设备之间交换数据。如果以全双工模式运行,则需要使用带有两个字节数组缓冲区的 transfer()
方法:一个用于发送数据,另一个用于存储响应数据的空缓冲区。
//Half-duplex mode
public void sendCommand(SpiDevice device, byte[] buffer) throws IOException {
// Shift data out to slave
device.write(buffer, buffer.length);
// Read the response
byte[] response = new byte[32];
device.read(response, response.length);
}
// Full-duplex mode
public void sendCommand(SpiDevice device, byte[] buffer) throws IOException {
byte[] response = new byte[buffer.length];
device.transfer(buffer, response, buffer.length);
}
当您的应用准备关闭 Android Things 设备时,请务必注销您的 SPI 设备。
@Override
protected void onDestroy() {
super.onDestroy();
if (mDevice != null) {
try {
mDevice.close();
mDevice = null;
} catch (IOException e) {}
}
}
当与主设备通信时,更复杂的外设(如LCD显示器,SD卡读卡器和GPS模块)通常会通过 UART 端口使用串行通信。 UART允许设备将原始数据异步发送到其他设备上的缓冲区。然后以先进先出的顺序读取这个缓冲区。它还允许在两个连接的设备上配置数据格式和传输速度。由于 UART 不支持时钟信号,所以两个器件必须达到传输速度,但传输速度往往比 I2C 更快,数据可以在器件之间以全双工模式传输。与 I2C 和 SPI 不同,每个 UART 连接只允许连接一个外设。
UART 外设有三根芯线:
在外设组件上,这些引脚通常会被标记为:
另外,一些 UART 设备可能还包括两个用于控制数据流的连接:
类似于前面的所有例子,您需要知道您的 Android Things 设备的 UART 连接的名称。 你可以用下面的代码找到:
PeripheralManagerService manager = new PeripheralManagerService();
List<string> deviceList = manager.getUartDeviceList();
if (!deviceList.isEmpty()) {
Log.d("Tuts+", deviceList.toString());
}
在 Raspberry Pi 上,日志输出如下所示:
[UART0]
一旦知道了 UART 连接的名称,就可以像打开其他设备连接一样创建 Android Things UART 设备。
PeripheralManagerService manager = new PeripheralManagerService();
mDevice = manager.openUartDevice(UART_DEVICE_NAME);
一旦你有了你的设备,你将需要配置将在设备之间发送的数据帧的格式。有四个属性需要注意:
这些设置中的每一个都可以在 UART 设备上进行配置,如下所示:
uart.setBaudrate(9600);
uart.setDataSize(6);
uart.setParity(UartDevice.PARITY_NONE);
uart.setStopBits(2);
之前您了解到,UART 设备有两个接线设置,那些设备有附加的控制信号,没有的设备。 您可以使用 setHardwareFlowControl()
方法在代码中配置 UART 设备。
uartDevice.setHardwareFlowControl(UartDevice.HW_FLOW_CONTROL_AUTO_RTSCTS);
//or
uartDevice.setHardwareFlowControl(UartDevice.HW_FLOW_CONTROL_NONE);
完成设备配置后,就可以读取、写入 Android Things 开发板与 UART 外设的数据了。写入是通过调用具有字节数组缓冲区的 write()
方法,以及该数组的长度来处理的。
uartDevice.write(buffer, buffer.length);
虽然,可以不断轮询设备读缓冲区中的数据,但最好还是创建一个 UartDeviceCallback
对象,该对象提供了一个名为 onUartDeviceDataAvailable()
的方法,当数据可用时将会触发该方法。如果是这样,您可以从设备的数据缓冲区中读取数据。您将能够使用 registerUartDeviceCallback
将此回调与您的 UART 设备相关联,不过您将需要记住在完成回调时,调用 unregisterUartDeviceCallback
。当数据可用时,可以使用 UART 的 read()
方法检索数据。
private UartDeviceCallback mUartCallback = new UartDeviceCallback() {
@Override
public boolean onUartDeviceDataAvailable(UartDevice uart) {
byte[] buffer = new byte[MAX_BUFFER_SIZE];
try {
uartDevice.read(buffer, buffer.length)
//do something with the data in the buffer byte array
} catch (IOException e) {}
//Returning true keeps the callback active. If you return false,
//the callback will automatically unregister.
return true;
}
@Override
public void onUartDeviceError(UartDevice uart, int error) {}
};
@Override
protected void onStart() {
super.onStart();
mDevice.registerUartDeviceCallback(mUartCallback);
}
@Override
protected void onStop() {
super.onStop();
mDevice.unregisterUartDeviceCallback(mUartCallback);
}
当 Activity
结束(finish)后,请务必关闭并取消对 UART
设备的引用。
@Override
protected void onDestroy() {
super.onDestroy();
if (uartDevice != null) {
try {
uartDevice.close();
uartDevice = null;
} catch (IOException e) {}
}
}
虽然 Peripheral API
允许您与几乎所有可连接到 Android Things 开发板的设备进行通信,但 Google 还提供了一些额外的支持,使构建您的物联网设备变得更加容易。本节将介绍 Android Things 提供的一些附加外设支持。
虽然 Android Things 为 Android 开发人员提供了一种,使用 Android SDK 和 Java 进入物联网开发的简单方法,但许多物联网应用程序已经存在于 C 和 C++ 中,而其他开发人员由于各种原因,会更愿意使用这些语言。为了支持它,Google 补充了支持本地应用程序和 NDK 的外设 API。关于这个话题,我不会深入探讨,但是建立和使用的连接方式与上面讨论的非常类似。
没有办法连接到互联网,物联网设备就只是物(Things)。借助内置的无线支持,您的 Android Things 设备可以连接到互联网,并使用各种在线资源,例如 Firebase 和其他 Google 服务,或任何其他后端服务。另外,使用 Google Play Services 和 Nearby Connections API 等工具,可以让用户通过 WLAN 网络直接与您的设备进行通信。
尽管 Android Things 的开发人员预览版本目前尚未启用,但蓝牙连接也是一项重要的物联网功能。使用蓝牙,您可以创建多个物联网设备或附件,并让它们在短距离内通信。这允许每个设备具有关于其环境的附加上下文信息,诸如用户的家庭或工作空间,以便为用户提供最好的服务。
有些设备可以使用原型板的 USB 端口,尽管在 Android Things 开发者预览的当前版本中并没有完全启用。在第二个开发者预览版中,Google 已经将 USB 音频文件添加到语音支持,开发者已经确认其他设备能工作,比如 USB 麦克风。随着 USB API 在 Android Things 的更高版本中的测试和认可,将会有大量的设备可以作为附件,简单地插入到您的物联网设备中。
某些设备(如Raspberry Pi)附带内置的附加 I/O 连接,如 HDMI,显示器和相机。幸运的是,所有这些都在 Android Things 上工作,可以让您连接一个 15 厘米的带状电缆相机...
...或者,通过带状电缆或 HDMI 连接显示:
恭喜!你已经了解了,但已经学习了使用 Android Things 开发连接、控制外围设备的非常有价值的信息。使用这些知识,您应该能够连接并与各种硬件组件进行通信。
在本系列的下一篇文章中,我们将使用我们的 Peripherals API 知识为 GPIO 运动传感器组件创建一个软件驱动程序,然后将其用于更大的 Android Things 项目。
观光\评论区