您的位置:首页 > 大数据 > 物联网

Android Things物联网开发--外围I/O接口之I2C(五)

2017-04-06 23:42 447 查看

I2C

I2C总线连接一些简单的设备,这些设备的数据负载较小。传感器和执行器用的就是I2C,还有其他的比如加速度计,温度计,LED显示器和电机驱动器。

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

I2C设备使用3线接口连接,包括:

共享时钟信号(SCL)

共享数据总线(SDA)

地线(GND)



因为所有数据都通过一根线传输,I2C仅仅支持半双工通信。所有的通信都由主设备启动,主设备传输完成后从设备必须响应。

I2C支持同一个总线连接多个从设备。不同于 SPI ,从设备使用 I2C 软件协议来寻址。每一个设备都有一个唯一的地址,并且仅响应主设备发送到的地址。

管理从设备的连接

为了打开一个到普通 I2C 从设备的连接,你必须知道那个总线的唯一的名字。在开发的初始阶段,或者移植一个app到新设备的时候,使用PeripheralManagerService 的getI2CBusList()方法获取所用可用的设备名是很有帮助的。

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 总线,地址代表了总线上的指定从设备。因此,一个 I2cDevice 是一个连接到相应 I2C 总线上的指定从设备 。

与寄存器进行交互

I2C 从设备将他们的内容放到可写或者可读的寄存器中。

可读寄存器–包含了从设备想要传输给主设备的数据,比如传感器的值或者状态位。

可写寄存器–包含了主设备可以控制的配置数据。

在 I2C 之上有一个通用的协议实现叫做 系统管理总线(SMBus),它以标准的方式与寄存器进行交互。SMBus由以下两个 I2C 事物组成:



Register Address标识了要访问的寄存器的地址,Data
是要读取或者写入的数据。从设备上的逻辑数据通常由多位组成,因此可以包含多个寄存器地址。

注意:对于SMBus协议,设备将会在地址(Register Address)和数据(Data
)之间发送一个重复的开始位。

外围I/O接口为访问寄存器数据提供SMBus命令的三种类型。

读写字节数据(Byte Data): readRegByte() 和 writeRegByte() 方法读或者写单字节(8-Bit)的寄存器数据;

读写字节数据(Word Data): readRegWord() 和 writeRegWord() 方法读或者写2个连续的寄存器值作为一个16位的小端存储(little-endian)的字。第一个寄存器地址对应字中的低位字节(LSB),后面的寄存器对应着高位字节(MSB)。

读写块数据(Block Data): 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;
}


传输原始数据

当需要与定义了跟SMBus不同的寄存器的 I2C 外设交互时,或者根本不用寄存器,使用原始的 read() 和 write()方法来完全控制在线缆上传输的字节数据。这些方法将会向下面那样执行一个单个的 I2C 事物:



使用原始传输方法,设备将在传输之前发送开始标志,并在传输完成之后发送停止标志。这使得通过 传输重复的开始标识来结合多个事物变的不再可能。

注意:原始传输方式能处理的数据没有明确的最大长度,但是在你设备上的 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.");
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: