Android Things 设备输入/输出指南上:GPIO、PWM、I2C

Android Things 具有独特的功能,可通过外设 API 和内置设备支持轻松连接到外部电子组件。在本文中,您将了解可以连接到的不同类型的外围设备,以便使用 Android Things 自定义您的物联网设备。

与不同的接口一起工作

Android Things 允许大多数设备通过使用 Peripheral API 连接到原型板,该 Peripheral API 支持 GPIO、PWM、I2C、SPI 和 UART 接口,每个接口都是用于与外设通信的行业标准接口。在本节中,您将了解这些接口是什么,以及如何使用这些连接与已连接到 Android Things 原型板的设备进行通信。

GPIO

通用输入/输出(GPIO)引脚用于与组件进行数字(二进制​​)通信,例如读取按钮是否被按下,或者打开或关闭 LED。在本教程中将会看到的 I/O 方法中,最简单的方法是使用 GPIO,只需要一个引脚,并将布尔值用于高或低状态。

在连接到 GPIO引脚之前,您需要知道该引脚的唯一名称。您可以通过检索 PeripheralManagerService 并调用 getGpioList()来获取所有可用引脚的名称。在 Raspberry Pi 上,将返回以下列表:

[BCM12,BCM13,BCM16,BCM17,BCM18,BCM19,BCM20,BCM21,BCM22,BCM23,BCM24,BCM25,BCM26,BCM27,BCM4,BCM5,BCM6]

要弄清楚这些代表哪个引脚,可以参考 Raspberry Pi I/O 图。

一旦获得了将要读取或写入的引脚名称,就可以通过调用 PeripheralManagerService 中的 openGpio(String pin_name) 来获取该引脚的 Gpio 对象引用。

try {
    mGpio = service.openGpio(PIN_NAME);
} catch (IOException e){

}

GPIO 引脚可用于输入或输出。如果您将使用该引脚来读取信息,则需要将引脚方向配置为 DIRECTION_IN,并设置该引脚的触发类型,以便知道何时让应用程序知道发生了某些事情。

mGpio.setDirection(Gpio.DIRECTION_IN);
mGpio.setEdgeTriggerType(Gpio.EDGE_BOTH);

触发器类型由 EDGE_NONEEDGE_RISINGEDGE_FALLINGEDGE_BOTH 组成。如果按下按钮,则在按钮电路完成且物理引脚上出现高电压信号时发生上升事件。当按钮被释放时发生下降事件。 您的代码将根据您设置的触发类型被通知更改。

现在您的 GPIO 正在侦听边缘触发器,您将需要创建一个 GpioCallback 来在您的应用程序中,注册 GPIO 组件的值。

private GpioCallback mCallback = new GpioCallback() {
    @Override
    public boolean onGpioEdge(Gpio gpio) {
        try {
            Log.d("Tuts+", "GPIO value:  " + gpio.getValue());
        } catch( IOException e ) {

        }
        return super.onGpioEdge(gpio);
    }

    @Override
    public void onGpioError(Gpio gpio, int error) {
        super.onGpioError(gpio, error);
    }
};

一旦你的回调被创建,注册它与您的 Gpio 对象。

mGpio.registerGpioCallback(mCallback);

如果您的 GPIO 引脚正在写入信息,则需要将方向设置为 DIRECTION_OUT_INITIALLY_LOWDIRECTION_OUT_INITIALLY_HIGH,具体取决于您希望组件是开启还是关闭。输出引脚不需要触发器类型。

mGpio.setDirection(Gpio.DIRECTION_OUT_INITIALLY_LOW);

为了写入设备,您可以调用 Gpio 对象上的 setValue(boolean) 来设置组件的状态。

mGpio.setValue(true);

一旦您的应用程序运行完毕,您将需要取消注册您的输入回调,如果它已被创建和注册,并使用 onDestroy() 中的 close() 方法关闭对外设的访问。

PWM

脉宽调制(PWM)设备,使用称为比例控制信号的数字状态的交替来发生作用。比例控制信号有三个主要部分需要注意:

  • 频率:描述输出脉冲重复的频率。频率的测量单位是赫兹(Hz)。
  • 占空比:表示设定频率内的脉冲宽度。占空比表示为一个频率内高信号的百分比,所以一个半周期的周期将有 50% 的占空比。
  • 周期:这表示每个上/下周期发生所花费的时间。周期与频率成反比。

通过调整信号的占空比,可以控制波形的平均 “开启” 时间。下面你可以看到一个 50% 周期信号的例子。

一些可以使用 PWM 信号的设备,包括使用频率来确定其位置的伺服电机,或者可以使用 PWM 信号来调节亮度的 LED 矩阵。

即使只有电机和 GPIO 设备,也可以创建大量的物联网设备,例如带电动激光的 “智能” 猫树。

与GPIO类似,您可以通过创建 PeripheralManagerService 并调用 getPwmList() 来检索可用的PWM端口列表。在 Raspberry Pi 上,这个列表将如下所示:

[PWM0, PWM1]

一旦知道了要使用的 PWM 引脚的名称,就可以使用 openPwm(String) 方法打开与该外设的连接。它需要包装在 try/catch 块中,以处理抛出 IOException 的可能性。

try {
    mPwm = service.openPwm(PIN_NAME);
} catch( IOException e ) {

}

一旦打开了与 PWM 引脚的连接,就可以控制其上的设置,例如频率和占空比。

mPwm.setPwmFrequencyHz(120);
mPwm.setPwmDutyCycle(25);
mPwm.setEnabled(true);

在完成应用程序并销毁 Activity 之前,您需要关闭连接并释放 PWM 设备的引用。

@Override
protected void onDestroy() {
    super.onDestroy();
    if( mPwm != null ) {
        try {
            mPwm.close();
            mPwm = null;
        } catch( IOException e ) {

        }
    }
}

I2C

内部集成电路(I2C)总线,允许您的项目通过一个物理连接与多个设备进行通信,并允许您仅通过 Raspberry Pi 或其他嵌入式设备的几个引脚发送复杂的数据。I2C 使用设备之间的同步通信,并依靠时钟信号确保设备在适当的时间响应。

发出时钟信号的设备(通常是您的 Android Things 设备)被称为主设备,所有接收该信号的外设都称为从设备。

与仅需要单个引脚的 PWM 和 GPIO 不同,I2C 器件需要三个连接:

  • 共享时钟信号(简称 SCL),它将主器件的时钟信号发送给从器件。
  • 共享数据线(简称 SDA),这是用于实际数据传输的连接。由于 I2C 是一种同步(半双工)通信标准,含义数据一次只能向一个方向移动,所以只有一个设备可以在任何特定的时间点使用此连接。
  • 电气接地。

值得注意的是,每个 I2C 从设备都使用设置的地址进行编程,并且只有当主设备对该特定地址发出数据请求时才会响应。

一些可以使用这种连接方法的外围设备,包括分段式 LED 矩阵显示器和各种先进的传感器。

每个 Android Things 设备将有一组用于 I2C 的引脚,您可以通过查看特定原型板的文档来找到这些引脚。对于 Raspberry Pi,可以参考本文顶部的引脚分配图,其中指出 SDA 和 SDL 是引脚 3 和 5。要查找 I2C 的名称,可以运行以下代码:

PeripheralManagerService manager = new PeripheralManagerService();
List<String> deviceList = manager.getI2cBusList();

if( !deviceList.isEmpty() ) {
   Log.d( "Tuts+", deviceList.toString() );
}

上面的代码片段将在 Raspberry Pi 上输出以下内容:

[I2C1]

一旦知道了 I2C 总线的名称,就可以使用其软件地址连接到该总线上的设备。您可以在外围设备组件的 “数据表” 中,找到软件地址和其他低级连接详细信息 - 如果要为嵌入式项目使用外设,则需要阅读!

private I2cDevice mDevice;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    try {
        PeripheralManagerService manager = new PeripheralManagerService();
        mDevice = manager.openI2cDevice(I2C_DEVICE_NAME, I2C_ADDRESS);
    } catch (IOException e) {}
}

通过I2C与设备进行通信时,可以使用系统管理总线(SMBus)协议将数据放入寄存器中,或者检索已保存在每个外围设备寄存器中的数据。 这是使用设备地址和寄存器地址完成的,Android Things 允许您使用以下方法从寄存器读取或写入多个寄存器中的字节组:

  • readRegByte()writeRegByte():从特定的寄存器读取或写入一个字节。
  • readRegWord()writeRegWord():以小尾数格式从外设上的两个连续寄存器读取或写入字节。
  • readRegBuffer()writeRegBuffer():读取或写入多达 32 个连续寄存器的字节。 值被写入或检索为一个字节数组(byte array)。
public void singleByte(I2cDevice device, int address) throws IOException {
    // Read one register from slave
    byte value = device.readRegByte(address);

    // Write the value back to slave
    device.writeRegByte(address, value);
}

public byte[] multipleBytes(I2cDevice device, int startAddress) throws IOException {
    // Read three consecutive register values
    byte[] data = new byte[3];
    device.readRegBuffer(startAddress, data, data.length);
    return data;
}

当您的应用准备关闭 Android Things 设备时,请务必注销您的 I2C 总线。

@Override
protected void onDestroy() {
    super.onDestroy();

    if (mDevice != null) {
        try {
            mDevice.close();
            mDevice = null;
        } catch (IOException e) {}
    }
}

原文链接:https://code.tutsplus.com/tutorials/android-things-peripheral-inputoutput--cms-27891