寫在前面的話:由于外設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
Android Things提供了外設I/O API,使用行業(yè)標準協(xié)議和接口與傳感器和執(zhí)行器進行通信。
通用輸入/輸出(GPIO)
將此API用于簡單傳感器,例如運動探測器、接近探測器和電平開關,它們將當前狀態(tài)報告為二進制值高或低。
通用輸入/輸出(GPIO)引腳提供了一個可編程接口,用于讀取二進制輸入設備(例如按鈕開關)的狀態(tài)或控制二進制輸出設備(例如LED)的開/關狀態(tài)。
您可以將GPIO引腳配置為具有高或低狀態(tài)的輸入或輸出。 作為輸入時,當外部源狀態(tài)確定,您的應用程序就可以讀取當前值,或者對狀態(tài)更改做出相應反應。 作為輸出時,您的應用程序可以配置引腳的狀態(tài)。
注意:為避免損壞GPIO引腳,請在連線之前檢查硬件的輸入和輸出限制。 請參閱硬件基礎并查閱硬件的文檔。
管理連接
為了打開到GPIO端口的連接,您需要知道唯一的端口名稱。 在開發(fā)的初始階段或?qū)贸绦蛞浦驳叫掠布r,通過getGpioList()從PeripheralManagerService找到所有可用的端口名稱很有幫助:
PeripheralManagerService manager = new PeripheralManagerService();
List<String> portList = manager.getGpioList();
if (portList.isEmpty()) {
Log.i(TAG, "No GPIO port available on this device.");
} else {
Log.i(TAG, "List of available ports: " + portList);
}
知道端口名稱后,就可以使用PeripheralManagerService連接到該端口。 當您完成與GPIO端口的通信后,記得關閉連接以釋放資源。 此外,在現(xiàn)有連接關閉之前,無法打開與同一端口的新連接。 要關閉連接,請使用端口的close()方法。
public class HomeActivity extends Activity {
// GPIO引腳名稱
private static final String GPIO_NAME = ...;
private Gpio mGpio;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// 嘗試訪問GPIO
try {
PeripheralManagerService manager = new PeripheralManagerService();
mGpio = manager.openGpio(GPIO_NAME);
} catch (IOException e) {
Log.w(TAG, "Unable to access GPIO", e);
}
}
@Override
protected void onDestroy() {
super.onDestroy();
if (mGpio != null) {
try {
mGpio.close();
mGpio = null;
} catch (IOException e) {
Log.w(TAG, "Unable to close GPIO", e);
}
}
}
}
從輸入端讀取
要讀取GPIO作為輸入端的端口:
- 使用mode DIRECTION_IN的setDirection()將其配置為輸入。
- 通過使用ACTIVE_HIGH或ACTIVE_LOW調(diào)用setActiveType(),將高電平(接近IOREF)或低電平(接近零)電壓信號配置為真(活動)。
- 使用getValue()方法訪問當前狀態(tài)。
以下代碼顯示如何設置具有與高電壓電平相關聯(lián)的活動狀態(tài)的輸入:
public void configureInput(Gpio gpio) throws IOException {
// 將引腳初始化為輸入
gpio.setDirection(Gpio.DIRECTION_IN);
// 高電平有效
gpio.setActiveType(Gpio.ACTIVE_HIGH);
...
// 讀取有效的高引腳狀態(tài)
if (gpio.getValue()) {
// 引腳為高電平
} else {
// 引腳為低電平
}
}
監(jiān)聽輸入狀態(tài)變化
配置為輸入的GPIO端口可以在其狀態(tài)在高和低之間變化時通知應用程序。 要注冊這些更改事件:
- 將GpioCallback附加到活動端口連接。
- 使用setEdgeTriggerType()方法聲明觸發(fā)中斷事件的狀態(tài)更改。 邊沿觸發(fā)支持以下四種類型:
- EDGE_NONE:無中斷事件。 這是默認值。
- EDGE_RISING:從低到高的轉(zhuǎn)換時中斷
- EDGE_FALLING:從高到低的轉(zhuǎn)換時中斷
- EDGE_BOTH:所有狀態(tài)轉(zhuǎn)換的中斷
- 從onGpioEdge()內(nèi)返回true以指示偵聽器應繼續(xù)接收每個端口狀態(tài)更改的事件。
以下代碼為給定輸入端口上的所有狀態(tài)更改注冊了一個中斷偵聽器:
public void configureInput(Gpio gpio) throws IOException {
// 將引腳初始化為輸入狀態(tài)
gpio.setDirection(Gpio.DIRECTION_IN);
// 設置低電平狀態(tài)有效
gpio.setActiveType(Gpio.ACTIVE_LOW);
// 注冊所有狀態(tài)更改
gpio.setEdgeTriggerType(Gpio.EDGE_BOTH);
gpio.registerGpioCallback(mGpioCallback);
}
private GpioCallback mGpioCallback = new GpioCallback() {
@Override
public boolean onGpioEdge(Gpio gpio) {
// 讀取低電平有效的低電平狀態(tài)
if (mDevice.getValue()) {
// 引腳為低電平
} else {
// 引腳為高電平
}
// 繼續(xù)監(jiān)聽更多中斷
return true;
}
@Override
public void onGpioError(Gpio gpio, int error) {
Log.w(TAG, gpio + ": Error event " + error);
}
};
- 當您的應用程序不再監(jiān)聽傳入事件時,取消注冊所有中斷處理程序:
public class HomeActivity extends Activity {
private Gpio mGpio;
...
@Override
protected void onStart() {
super.onStart();
// 開始監(jiān)聽中斷事件
mGpio.registerGpioCallback(mGpioCallback);
}
@Override
protected void onStop() {
super.onStop();
// 中斷事件不再需要
mGpio.unregisterGpioCallback(mGpioCallback);
}
}
寫入輸出端口
以編程方式控制GPIO端口的狀態(tài):
- 使用setDirection()將其配置為輸出,模式為DIRECTION_OUT_INITIALLY_HIGH或DIRECTION_OUT_INITIALLY_LOW。 這些模式確保端口的初始狀態(tài)也在配置時正確設置。
- 通過使用ACTIVE_HIGH或ACTIVE_LOW調(diào)用setActiveType(),將高電平(接近IOREF)或低電平(接近零)電壓信號配置為真(活動)。
- 使用setValue()方法設置當前狀態(tài)。
以下代碼顯示如何將輸出設置為初始為高,然后使用setValue()方法將其狀態(tài)切換為低:
public void configureOutput(Gpio gpio) throws IOException {
// 將引腳初始化為高電平輸出
gpio.setDirection(Gpio.DIRECTION_OUT_INITIALLY_HIGH);
// 低電平有效
gpio.setActiveType(Gpio.ACTIVE_LOW);
...
// 將值切換為LOW
gpio.setValue(true);
}