I2C

集成电路(IIC或I2C)总线将简单的外围设备与小数据有效载荷连接起来。传感器和执行器是I2C的常见用例。示例包括加速度计,温度计,LCD显示器和电机驱动器。

I2C是同步 串行接口,这意味着它依赖于共享时钟信号来同步器件之间的数据传输。控制触发时钟信号的器件称为主器件。所有其他连接的外围设备都称为从站。每个设备连接到同一组数据信号以形成总线

I2C器件使用3线接口连接,包括:

  • 共享时钟信号(SCL)
  • 共享数据线(SDA)
  • 公共接地参考(GND)

alt_text

由于所有数据都通过一条线传输,所以I2C只支持半双工 通信。所有通信由主设备启动,并且从站必须在主站传输完成后响应。

I2C支持沿同一总线连接的多个从站器件。与 SPI 不同,从站器件使用 I2C软件协议进行寻址。每个设备都使用唯一的地址编程,只响应主机发送到该地址的传输。每个从站设备必须具有地址,即使总线只有单个从站。

管理从站设备连接

为了打开与特定 I2C从站的连接,您需要知道总线的唯一名称。在开发初始阶段,或将应用程序移植到新硬件时,使用 getI2CBusList()PeripheralManagerService 发现所有可用的设备名称:

PeripheralManagerService manager = new PeripheralManagerService();
List<String> deviceList = manager.getI2cBusList();
if (deviceList.isEmpty()) {
    Log.i(TAG, "No I2C bus available on this device.");
} else {
    Log.i(TAG, "List of available devices: " + deviceList);
}

知道目标设备名称后,使用 PeripheralManagerService 连接到该设备。完成与外围设备通信后,关闭连接以释放资源。此外,在现有连接关闭之前,您无法打开与设备的新连接。要关闭连接,请使用设备的 close() 方法。

public class HomeActivity extends Activity {
    // I2C Device Name
    private static final String I2C_DEVICE_NAME = ...;
    // I2C Slave Address
    private static final int I2C_ADDRESS = ...;

    private I2cDevice mDevice;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        // Attempt to access the I2C device
        try {
            PeripheralManagerService manager = new PeripheralManagerService();
            mDevice = manager.openI2cDevice(I2C_DEVICE_NAME, I2C_ADDRESS);
        } catch (IOException e) {
            Log.w(TAG, "Unable to access I2C device", e);
        }
    }

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

        if (mDevice != null) {
            try {
                mDevice.close();
                mDevice = null;
            } catch (IOException e) {
                Log.w(TAG, "Unable to close I2C device", e);
            }
        }
    }
}
>

与寄存器进行交互

I2C 从器件将其内容组织成可读或可写寄存器(由地址值引用的数据的单个字节):

  • 可读寄存器 - 包含从站想要向主站报告的数据,如传感器值或状态标志。
  • 可写入寄存器 - 包含主机可以控制的配置数据。

被称为 系统管理总线(SMBus)的通用协议实现存在于 I2C 之上,以标准方式与寄存器数据进行交互。 SMBus命令由两个 I2C 事务组成,如下所示:

""

第一个事务标识要访问的寄存器地址,第二个事务在地址处读取或写入数据。从设备上的逻辑数据可能经常占用多个字节,因此包含多个寄存器地址。提供给API的寄存器地址始终是第一个引用寄存器。

>

外设I / O提供访问寄存器数据的三种类型的SMBus命令:

  • 字节数据 - readRegByte()writeRegByte() 读取或写入单个8位寄存器值。

  • 字数据 - readRegWord()writeRegWord() 读取或写入两个连续的寄存器值作为16位小端字。第一个寄存器地址对应于字中的最低有效字节(LSB),后跟最高有效字节(MSB)。

  • 块数据 - readRegBuffer()writeRegBuffer() 读取或写入最多32个连续的寄存器值作为数组。

// Modify the contents of a single register
public void setRegisterFlag(I2cDevice device, int address) throws IOException {
    // Read one register from slave
    byte value = device.readRegByte(address);
    // Set bit 6
    value |= 0x40;
    // Write the updated value back to slave
    device.writeRegByte(address, value);
}

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

转移原始数据

当与 I2C 外设进行交互时,它不同于SMBus定义其寄存器 - 或者根本不使用寄存器 - 使用原始的 read()write() 方法来完全控制通过线传输的数据字节。这些方法将执行单个 I2C 事务,如下所示:

""

使用原始传输,设备将在传输之前发送单个启动条件,并在之后单个停止条件。不可能将多个事务与“重复启动”条件组合。

以下代码示例说明如何构造原始字节缓冲区并将其写入 I2C 从站器件:

public void writeBuffer(I2cDevice device, byte[] buffer) throws IOException {
    int count = device.write(buffer, buffer.length);
    Log.d(TAG, "Wrote " + count + " bytes over I2C.");
}

results matching ""

    No results matching ""