Android Things:外设I/O接口-I2C

一、接口简介


内部集成电路(IIC或者I2C)总线使用小数据负载连接简单的外部设备。传感器和执行器是常见的I2C使用案例,例如包含加速度计,温度计,LCD显示器,和电机驱动。

I2C总线是一种同步的串行接口:这意味着它依赖于共享的时钟信号来同步设备之间的数据传输。控制时钟信号的设备被称为master,其它所有连接的外设被认为是Slaves,每个设备连接到同一组数据信号以形成总线。
I2C设备连接使用3线接口

  • 共享时间信号(SCL);
  • 共享数据线(SDA);
  • 共同的接地参考(GND);

I2C仅支持半双工通信:因为所有的数据都是通过一根线连接。 所有的通信都是由master设备发起的,一旦主master传输完成slave必须响应。
** I2C支持在同一条总线上连接多个slave设备:不像SPI,slave设备使用I2C软件协议寻址。每个设备编程有一个唯一的地址**,并且仅仅响应master发送给地址的信息。每个slave设备必须有一个地址,即时总线仅仅包含一个单一的信号slave。

Android Things:外设I/O接口-I2C_第1张图片
I2C原理图

二、接口使用


1. 管理Slave设备连接

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);
        }
    }
}

2. 与寄存器通信
I2C Slave设备组织内容给可读或者可写的寄存器(单个字节数据由一个地址值引用):

  • 可读寄存器:包含slave想要向master报告的数据,例如传感器值或者状态标识;
  • 可写寄存器:包含master可以控制的配置数据;

一个常见的协议实现被称为System Management Bus(SMBus)存在于I2C顶部,以标准的方式和寄存器通信。SMBus命令由下面的两个I2C事务组成:

寄存器通信数据结构

- 第一个事务标识代表了要访问的寄存器的地址,第二个是在该地址读或者写的数据。
- Slave设备的逻辑数据可能经常占用多个字节,从而包含多个寄存器地址。提供给API的地址始终是第一个寄存器的引用;

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

  • 字节数据:readRegByte()和writeRegByte()来读或者写一个单独的8位寄存器数据。
  • 字数据:readRegWord()和writeRegWord()来读或者写两个连续寄存器的值以一个16位litten-endian字。第
    一个寄存器的地址被翻译为字中的最小有效字节(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;
}

3. 传输原始数据
当和一个I2C外设交互时,定义不同的SMBus寄存器,或许根本不使用寄存器,使用原始的raw()和write()方法对通过导线传递的字节数据完全控制。这些方法将会执行一个如下单独的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.");
}  

4. 关闭连接
当你完成I2C端口通信,关闭这个连接,并释放资源。此外,在现有端口关闭之前,你不能打开一个新的连接。要想关闭连接,使用端口的close()方法;

public class HomeActivity extends Activity {
    ... ... 
    private I2cDevice mDevice;

    @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接口,获取bmp280温度传感器的温度数据来演示该接口的使用。
1. 硬件准备

  • 树莓派开发板 1块
  • 面包板 1块
  • bmp280传感器
  • 杜邦线(公对母)若干

2. 电路搭建

Android Things:外设I/O接口-I2C_第2张图片
电路图

3. 代码编写
I2CDemo\app\src\main\java\com\chengxiang\i2cdemo\MainActivity.java

public class MainActivity extends AppCompatActivity {
    private static final String I2C_ADDRESS = "I2C1";
    private static final int TEMPERATURE_SENSOR_SLAVE = 0x77;
    private static final int REGISTER_TEMPERATURE_CALIBRATION_1 = 0x88;
    private static final int REGISTER_TEMPERATURE_CALIBRATION_2 = 0x8A;
    private static final int REGISTER_TEMPERATURE_CALIBRATION_3 = 0x8C;

    private static final int REGISTER_TEMPERATURE_RAW_VALUE_START = 0xFA;
    private static final int REGISTER_TEMPERATURE_RAW_VALUE_SIZE = 3;

    private TextView temperatureTextView;

    private I2cDevice i2cDevice;

    private final short[] calibrationData = new short[3];

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        temperatureTextView = (TextView) findViewById(R.id.temperature);

        PeripheralManagerService peripheralManagerService = new PeripheralManagerService();
        try {
            i2cDevice = peripheralManagerService.openI2cDevice(I2C_ADDRESS, TEMPERATURE_SENSOR_SLAVE);
            calibrationData[0] = i2cDevice.readRegWord(REGISTER_TEMPERATURE_CALIBRATION_1);
            calibrationData[1] = i2cDevice.readRegWord(REGISTER_TEMPERATURE_CALIBRATION_2);
            calibrationData[2] = i2cDevice.readRegWord(REGISTER_TEMPERATURE_CALIBRATION_3);

            byte[] data = new byte[REGISTER_TEMPERATURE_RAW_VALUE_SIZE];
            i2cDevice.readRegBuffer(REGISTER_TEMPERATURE_RAW_VALUE_START, data, REGISTER_TEMPERATURE_RAW_VALUE_SIZE);
            if (data.length != 0) {
                float temperature = compensateTemperature(readSample(data));
                temperatureTextView.setText("temperature:" + temperature);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        if (i2cDevice != null) {
            try {
                i2cDevice.close();
                i2cDevice = null;
            } catch (IOException e) {
                Log.w(TAG, "Unable to close I2C device", e);
            }
        }

    }

    private int readSample(byte[] data) {
        // msb[7:0] lsb[7:0] xlsb[7:4]
        int msb = data[0] & 0xff;
        int lsb = data[1] & 0xff;
        int xlsb = data[2] & 0xf0;
        // Convert to 20bit integer
        return (msb << 16 | lsb << 8 | xlsb) >> 4;
    }

    private float compensateTemperature(int rawTemp) {
        float digT1 = calibrationData[0];
        float digT2 = calibrationData[1];
        float digT3 = calibrationData[2];
        float adcT = (float) rawTemp;

        float varX1 = adcT / 16384f - digT1 / 1024f;
        float varX2 = varX1 * digT2;

        float varY1 = adcT / 131072f - digT1 / 8192f;
        float varY2 = varY1 * varY1;
        float varY3 = varY2 * digT3;

        return (varX2 + varY3) / 5120f;
    }
}

4. 运行结果
按照上面的电路图,搭建电路如下:

Android Things:外设I/O接口-I2C_第3张图片
电路搭建

运行程序,通过传感器检测的温度显示在屏幕上:
Android Things:外设I/O接口-I2C_第4张图片
运行结果


1.抛弃各种找元器件的烦恼,来“1024工场”旗舰店,一次性买到你所想要的:树莓派套装—专为Android Things打造。

Android Things:外设I/O接口-I2C_第5张图片
树莓派套装

电脑用户,点击如下链接进入淘宝宝贝页面:
https://item.taobao.com/item.htm?spm=686.1000925.0.0.3f11c9ed68fPu7&id=549263158263
手机用户,打开淘宝客户端扫描二维码:
Android Things:外设I/O接口-I2C_第6张图片
宝贝二维码

2.完整和持续更新的《使用Android打开物联网开发大门——Andoid Thigns开发》文档,欢迎大家阅读!
https://www.kancloud.cn/workshop1024/android_things_develop/360773
Android Things:外设I/O接口-I2C_第7张图片
这里写图片描述

3.新技术,新未来!欢迎大家关注“1024工场”微信服务号,时刻关注我们的最新的技术讯息。(甭客气!尽情的扫描或者长按!)
Android Things:外设I/O接口-I2C_第8张图片
服务号

4.加入“Android Things开发”QQ讨论群,一起学习一起Hi。(甭客气!尽情的扫描或者长按!)
Android Things:外设I/O接口-I2C_第9张图片
qq群

你可能感兴趣的:(Android Things:外设I/O接口-I2C)