寫在前面的話:由于外設I/O涉及到GPIO纠吴、PWM硬鞍、和串行通信三部分,而串行通信有講了I2C(IIC)戴已、SPI固该、UART,這樣導致本文的篇幅過長不便于閱讀糖儡,特此將本文分成幾部分來方便閱讀
- Android Things 外設I/O-GPIO
- Android Things 外設I/O-PWM
- Android Things 外設I/O-I2C(IIC)
- Android Things 外設I/O-SPI
- Android Things 外設I/O-UART
串行通信
使用這些API在連接在同一本地總線上的兩個或多個智能設備之間傳輸更大的數(shù)據(jù)有效負載伐坏。 下表概述了每個支持的串行協(xié)議的基本屬性:
協(xié)議 | 傳輸類型 | 電線數(shù)量 | 外圍設備數(shù)量 | 傳輸速度 |
---|---|---|---|---|
I2C | 同步 | 2 | Up to 127 | Low |
SPI | 同步 | 4+ | Unlimited | High |
UART | 異步 | 2 or 4 | 1 | Medium |
I2C
內(nèi)部集成電路(IIC或I2C)總線連接具有小數(shù)據(jù)有效載荷的簡單外圍設備。 傳感器和執(zhí)行器是I2C的常見用例握联。 示例包括加速度計桦沉,溫度計每瞒,LCD顯示器和電機驅動器。
I2C是同步串行接口纯露,這意味著它依賴于共享時鐘信號來同步設備之間的數(shù)據(jù)傳輸剿骨。 觸發(fā)時鐘信號的控制裝置稱為主機。 所有其他連接的外圍設備稱為從設備埠褪。 每個設備連接到同一組數(shù)據(jù)信號以形成總線浓利。
I2C器件使用3-Wire接口連接,包括:
- 共享時鐘信號(SCL)
- 共享數(shù)據(jù)線(SDA)
- 公共接地參考(GND)
由于所有數(shù)據(jù)都通過一條線傳輸组橄,I2C僅支持半雙工通信荞膘。 所有通信由主設備發(fā)起罚随,并且從設備必須在主設備的傳輸完成后進行響應玉工。
??I2C支持沿同一總線連接的多個從器件。 與SPI不同淘菩,從器件使用I2C軟件協(xié)議尋址遵班。 每個設備都用唯一的地址編程,并且只響應主設備發(fā)送到該地址的傳輸潮改。 每個從設備必須有一個地址狭郑,即使總線只包含一個從設備。
管理從設備連接
為了打開到特定I2C從器件的連接汇在,您需要知道總線的唯一名稱翰萨。 在開發(fā)的初始階段或將應用程序移植到新硬件時,可以通過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連接到該設備亩鬼。 與外圍設備通信后,記得關閉連接以釋放資源阿蝶。 此外雳锋,在現(xiàn)有連接關閉之前,無法打開與設備的新連接羡洁。 要關閉連接玷过,請使用設備的close()方法。
public class HomeActivity extends Activity {
// IIC 設備名稱
private static final String I2C_DEVICE_NAME = ...;
// IIC 從設備地址
private static final int I2C_ADDRESS = ...;
private I2cDevice mDevice;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// 嘗試訪問I2C設備
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從器件將其內(nèi)容組織為可讀或可寫寄存器(由地址值引用的數(shù)據(jù)的單個字節(jié)):
- 可讀寄存器 - 包含從機要向主機報告的數(shù)據(jù)袋马,例如傳感器值或狀態(tài)標志。
- 可寫寄存器 - 包含主控可以控制的配置數(shù)據(jù)袒餐。
稱為系統(tǒng)管理總線(SMBus)的通用協(xié)議實現(xiàn)存在于I2C之上飞蛹,以標準方式與寄存器數(shù)據(jù)交互谤狡。 SMBus命令由兩個I2C事務組成,如下所示:
第一個事務標識要訪問的寄存器地址卧檐,第二個事務在該地址讀取或寫入數(shù)據(jù)墓懂。 從設備上的邏輯數(shù)據(jù)通常可以占用多個字節(jié)霉囚,并且因此包含多個寄存器地址捕仔。 提供給API的寄存器地址始終是要引用的第一個寄存器。
注:根據(jù)SMBus協(xié)議盈罐,設備將在地址和數(shù)據(jù)事務之間發(fā)送“重復啟動”條件榜跌。
外設I/O提供三種類型的SMBus命令來訪問寄存器數(shù)據(jù):
- 字節(jié)數(shù)據(jù) - readRegByte()和writeRegByte()讀取或寫入一個8位寄存器值。
- 字數(shù)據(jù) - readRegWord()和writeRegWord()讀取或寫入兩個連續(xù)的寄存器值作為16位小端字盅粪。 第一個寄存器地址被解釋為字中的最低有效字節(jié)(LSB)钓葫,后跟最高有效字節(jié)(MSB)。
- 塊數(shù)據(jù) - readRegBuffer()和writeRegBuffer()讀取或寫入多達32個連續(xù)的寄存器值作為數(shù)組票顾。
// 修改單個寄存器的內(nèi)容
public void setRegisterFlag(I2cDevice device, int address) throws IOException {
// 從從器件讀取一個寄存器
byte value = device.readRegByte(address);
// 設置bit 6
value |= 0x40;
// 將更新的值寫回從器件
device.writeRegByte(address, value);
}
// 讀取寄存器塊
public byte[] readCalibration(I2cDevice device, int startAddress) throws IOException {
// 讀取三個連續(xù)的寄存器值
byte[] data = new byte[3];
device.readRegBuffer(startAddress, data, data.length);
return data;
}
傳輸原始數(shù)據(jù)
當與不同于SMBus定義其寄存器的I2C外設交互時础浮,或者根本不使用寄存器時,使用原始 read()和write()方法來完全控制通過線傳輸?shù)臄?shù)據(jù)字節(jié)奠骄。 這些方法將執(zhí)行單個I2C事務豆同,如下所示:
使用原始傳輸時,器件將在傳輸之前發(fā)送單個啟動條件含鳞,并在之后發(fā)送單個停止條件影锈。 不可能將多個事務與“重復開始”條件組合。
注意:原始事務沒有明確的最大長度蝉绷,但是設備上的I2C控制器硬件可能對其可以處理的字節(jié)數(shù)有限制鸭廷。 如果您的外設需要大量數(shù)據(jù)傳輸,請查閱您的設備硬件文檔潜必。
以下代碼示例說明如何構造原始字節(jié)緩沖區(qū)并將其寫入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.");
}