Android Things 外設(shè)I/O-I2C(IIC)

寫在前面的話:由于外設(shè)I/O涉及到GPIO、PWM、和串行通信三部分,而串行通信有講了I2C(IIC)、SPI、UART,這樣導(dǎo)致本文的篇幅過長不便于閱讀,特此將本文分成幾部分來方便閱讀

  1. Android Things 外設(shè)I/O-GPIO
  2. Android Things 外設(shè)I/O-PWM
  3. Android Things 外設(shè)I/O-I2C(IIC)
  4. Android Things 外設(shè)I/O-SPI
  5. Android Things 外設(shè)I/O-UART

串行通信

使用這些API在連接在同一本地總線上的兩個或多個智能設(shè)備之間傳輸更大的數(shù)據(jù)有效負載。 下表概述了每個支持的串行協(xié)議的基本屬性:

協(xié)議 傳輸類型 電線數(shù)量 外圍設(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ù)有效載荷的簡單外圍設(shè)備。 傳感器和執(zhí)行器是I2C的常見用例。 示例包括加速度計,溫度計,LCD顯示器和電機驅(qū)動器。

I2C是同步串行接口,這意味著它依賴于共享時鐘信號來同步設(shè)備之間的數(shù)據(jù)傳輸。 觸發(fā)時鐘信號的控制裝置稱為主機。 所有其他連接的外圍設(shè)備稱為從設(shè)備。 每個設(shè)備連接到同一組數(shù)據(jù)信號以形成總線。

I2C器件使用3-Wire接口連接,包括:

  • 共享時鐘信號(SCL)
  • 共享數(shù)據(jù)線(SDA)
  • 公共接地參考(GND)
I<sup>2</sup>C連接

由于所有數(shù)據(jù)都通過一條線傳輸,I2C僅支持半雙工通信。 所有通信由主設(shè)備發(fā)起,并且從設(shè)備必須在主設(shè)備的傳輸完成后進行響應(yīng)。
??I2C支持沿同一總線連接的多個從器件。 與SPI不同,從器件使用I2C軟件協(xié)議尋址。 每個設(shè)備都用唯一的地址編程,并且只響應(yīng)主設(shè)備發(fā)送到該地址的傳輸。 每個從設(shè)備必須有一個地址,即使總線只包含一個從設(shè)備。

管理從設(shè)備連接

為了打開到特定I2C從器件的連接,您需要知道總線的唯一名稱。 在開發(fā)的初始階段或?qū)?yīng)用程序移植到新硬件時,可以通過getI2CBusList()方法從PeripheralManagerService中找到所有可用的設(shè)備名稱:

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

一旦知道目標設(shè)備名稱,就可以使用PeripheralManagerService連接到該設(shè)備。 與外圍設(shè)備通信后,記得關(guān)閉連接以釋放資源。 此外,在現(xiàn)有連接關(guān)閉之前,無法打開與設(shè)備的新連接。 要關(guān)閉連接,請使用設(shè)備的close()方法。

public class HomeActivity extends Activity {
    // IIC 設(shè)備名稱
    private static final String I2C_DEVICE_NAME = ...;
    // IIC 從設(shè)備地址
    private static final int I2C_ADDRESS = ...;

    private I2cDevice mDevice;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        // 嘗試訪問I2C設(shè)備
        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是到相應(yīng)I2C總線上的特定從器件的連接。

與寄存器交互

I2C從器件將其內(nèi)容組織為可讀或可寫寄存器(由地址值引用的數(shù)據(jù)的單個字節(jié)):

  • 可讀寄存器 - 包含從機要向主機報告的數(shù)據(jù),例如傳感器值或狀態(tài)標志。
  • 可寫寄存器 - 包含主控可以控制的配置數(shù)據(jù)。

稱為系統(tǒng)管理總線(SMBus)的通用協(xié)議實現(xiàn)存在于I2C之上,以標準方式與寄存器數(shù)據(jù)交互。 SMBus命令由兩個I2C事務(wù)組成,如下所示:

I<sup>2</sup>C-SMBus

第一個事務(wù)標識要訪問的寄存器地址,第二個事務(wù)在該地址讀取或?qū)懭霐?shù)據(jù)。 從設(shè)備上的邏輯數(shù)據(jù)通??梢哉加枚鄠€字節(jié),并且因此包含多個寄存器地址。 提供給API的寄存器地址始終是要引用的第一個寄存器。

注:根據(jù)SMBus協(xié)議,設(shè)備將在地址和數(shù)據(jù)事務(wù)之間發(fā)送“重復(fù)啟動”條件。

外設(shè)I/O提供三種類型的SMBus命令來訪問寄存器數(shù)據(jù):

  • 字節(jié)數(shù)據(jù) - readRegByte()和writeRegByte()讀取或?qū)懭胍粋€8位寄存器值。
  • 字數(shù)據(jù) - readRegWord()和writeRegWord()讀取或?qū)懭雰蓚€連續(xù)的寄存器值作為16位小端字。 第一個寄存器地址被解釋為字中的最低有效字節(jié)(LSB),后跟最高有效字節(jié)(MSB)。
  • 塊數(shù)據(jù) - readRegBuffer()和writeRegBuffer()讀取或?qū)懭攵噙_32個連續(xù)的寄存器值作為數(shù)組。
// 修改單個寄存器的內(nèi)容
public void setRegisterFlag(I2cDevice device, int address) throws IOException {
    // 從從器件讀取一個寄存器
    byte value = device.readRegByte(address);
    // 設(shè)置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外設(shè)交互時,或者根本不使用寄存器時,使用原始 read()和write()方法來完全控制通過線傳輸?shù)臄?shù)據(jù)字節(jié)。 這些方法將執(zhí)行單個I2C事務(wù),如下所示:

I<sup>2</sup>C-raw

使用原始傳輸時,器件將在傳輸之前發(fā)送單個啟動條件,并在之后發(fā)送單個停止條件。 不可能將多個事務(wù)與“重復(fù)開始”條件組合。

注意:原始事務(wù)沒有明確的最大長度,但是設(shè)備上的I2C控制器硬件可能對其可以處理的字節(jié)數(shù)有限制。 如果您的外設(shè)需要大量數(shù)據(jù)傳輸,請查閱您的設(shè)備硬件文檔。

以下代碼示例說明如何構(gòu)造原始字節(jié)緩沖區(qū)并將其寫入I2C從設(shè)備:

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

參考文獻 https://developer.android.google.cn/things/sdk

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容