Android Things:外設I/O接口-UART

一、接口簡介
UART(Universal Asynchronous Receiver Transmitter)是用來和外圍設備交互數據的通用接口,如GPS模塊,LCD顯示器,XBee收音機等複雜的外圍設備,通常使用UART端口(通常簡稱爲串行端口)來通信。
  它是通用的:因爲數據傳輸速率和數據字節格式是可配置的。
  它是異步的:因爲沒有時鐘信號來同步兩個設備之間的數據傳輸,設備的硬件在一個先進先出的緩衝中收集所有的輸入數據,直到你的app讀取它。
  它是全雙工:意味着可以同時發送和接口數據。
  它比I2C更快:但是缺少共享時鐘,意味着所有的設備必須同意一個相同的數據傳輸速率,每個設備可以堅持獨立最小定時誤差。
  它僅支持點對點通信:不像API和I2C,它僅支持兩個設備之間的點對點通信。

UART外圍設備通常有兩種類型:
  3線端口包含數據接收(RX),數據發送(TX),和接地引用(GUD)信號;
  5線端口添加了請求發送(RTS)和清除發送(CTS)信號,用於硬件流量控制。流量控制允許接收設備標識它的緩衝已滿,發送設備應該在發送更多數據之前等待。
二、使用步驟
1.打開連接:創建PeripheralManagerService對象,使用你想打開端口的名稱,調用open()方法打開連接。
@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    try {
        PeripheralManagerService manager = new PeripheralManagerService();
        mDevice = manager.openUartDevice(UART_DEVICE_NAME);
    } catch (IOException e) {
        Log.w(TAG, "Unable to access UART device", e);
    }
}
2.配置參數:調用setBaudrate()、setDataSize、setParity()和setStopBits等方法設置波特率、數據大小、錯誤校驗和結束位等。
每個通過UART發送的字符都被包裝在數據幀中,它包含以下組件:

  起始位:在發送數據之前,這行保持固定1位持續時間間隔的時間,來指示新的字符的開始。
  數據位:標識數據字符的單個的位。UART可能配置發送5-9數據位來代表字符。更少的比特減少數據的範圍,但是可以提高數據傳輸效率。
  校驗位:可選的錯誤檢查值。如果UART被配置爲奇偶校驗,一個額外的幀將會添加到這個位,預示着數據內容是否匹配奇偶校驗。設置爲none則從幀移除這位。
  結束位:在所有數據傳輸後,該行被重置爲可配置的時間間隔,指示字符的結尾。它能配置爲1或者2位閒置時間。
通過UART傳輸數據的速率被稱爲波特率,它代表了接受和發送的速度,比特每秒。
通過UART連接的連個設備沒有共享時鐘,都需要使用相同的波特率提前配置來保證數據的正確解碼。
public void configureUartFrame(UartDevice uart) throws IOException {
    uart.setBaudrate(115200);
    uart.setDataSize(8);
    uart.setParity(UartDevice.PARITY_NONE);
    uart.setStopBits(1);
}
如果你的設備支持5線UART端口,啓動硬件流控制可以提交數據傳輸的可靠性。通常這也意味着你可以安全地使用更快的波特率,而丟失傳入數據的機率要低得多。
硬件流控制啓動之後,當設備的接收緩衝區已滿不能接受任何數據的時候,UART發出發送請求(RTS)信號。一旦緩衝區被耗盡這個信號將被清除。相似的,UART監視清除發送(CTS)信號,如果它發現外部設備這行生效,將會增加數據傳輸。

public void setFlowControlEnabled(UartDevice uart, boolean enable) throws IOException {
    if (enable) {
        // Enable hardware flow control
        uart.setHardwareFlowControl(UartDevice.HW_FLOW_CONTROL_AUTO_RTSCTS);
    } else {
        // Disable flow control
        uart.setHardwareFlowControl(UartDevice.HW_FLOW_CONTROL_NONE);
    }
}
3.發送數據:使用UART向外設發送緩衝數據,使用write()方法。
public void writeUartData(UartDevice uart) throws IOException {
    byte[] buffer = {...};
    int count = uart.write(buffer, buffer.length);
    Log.d(TAG, "Wrote " + count + " bytes to peripheral");
}
4.監聽輸入數據:使用read()方法從UART FIFO緩衝中向你的應用讀取數據。這個方法接受一個空緩衝來填充輸入數據,要讀取的最大字節數。
UART讀取是非阻塞的,如果在FIFO中沒有有效數據它將會立即返回。UartDevice將會返回在讀取時候FIFO有效字節的數目,達到要求的數量。爲了確保所有的數據都被讀取,UART循環讀取直到它報告沒有數據存在了。
當緩衝爲空的時候,爲了避免不必要的輪詢,使用UartDevice註冊一個UartDeviceCallback。當還有數據可讀的時候,這個回調調用onUartDeviceDataAvailable()方法。當你的應用程序不再監聽輸入數據的時候,你應該註銷這個回調。
onUartDeviceDataAvailable()回調返回一個布爾值,指示回調是否自動註銷獲取將來的中斷事件。這裏返回true在UART FIFO每次數據出現時繼續獲取事件。
@Override
protected void onStart() {
    super.onStart();
    // Begin listening for interrupt events
    mDevice.registerUartDeviceCallback(mUartCallback);
}
public void readUartBuffer(UartDevice uart) throws IOException {
    // Maximum amount of data to read at one time
    final int maxCount = ...;
    byte[] buffer = new byte[maxCount];

    int count;
    while ((count = uart.read(buffer, buffer.length)) > 0) {
        Log.d(TAG, "Read " + count + " bytes from peripheral");
    }
}
@Override
protected void onStop() {
    super.onStop();
    // Interrupt events no longer necessary
    mDevice.unregisterUartDeviceCallback(mUartCallback);
}
private UartDeviceCallback mUartCallback = new UartDeviceCallback() {
    @Override
    public boolean onUartDeviceDataAvailable(UartDevice uart) {
        // Read available data from the UART device
        try {
            readUartBuffer(uart);
        } catch (IOException e) {
            Log.w(TAG, "Unable to access UART device", e);
        }
        // Continue listening for more interrupts
        return true;
    }
    @Override
    public void onUartDeviceError(UartDevice uart, int error) {
        Log.w(TAG, uart + ": Error event " + error);
    }
};
5.關閉連接:當你完成和外部設備的通信,調用close()方法關閉連接並釋放資源。此外在現有端口關閉之前,你不能打開相同端口的新連接。
@Override
protected void onDestroy() {
    super.onDestroy();
    if (mDevice != null) {
        try {
            mDevice.close();
            mDevice = null;
        } catch (IOException e) {
            Log.w(TAG, "Unable to close UART device", e);
        }
    }
}
三、案例演示
這裏我們和大家演示一下,電腦和樹莓派如何通過FTDI TTL-232R連接線進行信息傳遞,該線使用的是UART接口。
1.硬件準備
     樹莓派3開發板 1塊
     FTDI芯片 TTL-232R-3V3 USB轉TTL線 1根
廣告時間咯:如果你還沒有自己的開發板和元器件,到我們的“1024工場旗艦店”來逛逛一逛吧(文章底部二維碼),這裏能一次性有買到你想要的!
2.電路搭建


注意:在連接線的時候是連接線的TX連接線插入樹莓派的RX引腳,同理RX插入TX。
2.代碼編寫
UARTDemo\app\src\main\java\com\chengxiang\uartdemo\MainActivity.java
public class MainActivity extends AppCompatActivity {
    private static final String TAG = "LoopbackActivity";
    private static final String UART_DEVICE_NAME = "UART0";
    private static final int BAUD_RATE = 115200;
    private static final int DATA_BITS = 8;
    private static final int STOP_BITS = 1;
    private static final int CHUNK_SIZE = 512;

    private UartDevice mUartDevice;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        PeripheralManagerService peripheralManagerService = new PeripheralManagerService();
        try {
            //通過UART接口名稱UART0,打開接口
            mUartDevice = peripheralManagerService.openUartDevice(UART_DEVICE_NAME);
            //設置波特率、數據大小、校驗等參數
            mUartDevice.setBaudrate(BAUD_RATE);
            mUartDevice.setDataSize(DATA_BITS);
            mUartDevice.setParity(UartDevice.PARITY_NONE);
            mUartDevice.setStopBits(STOP_BITS);
            //註冊數據監聽,在有數據可讀的時候回調
            mUartDevice.registerUartDeviceCallback(mUartDeviceCallback);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    private UartDeviceCallback mUartDeviceCallback = new UartDeviceCallback() {
        @Override
        public boolean onUartDeviceDataAvailable(UartDevice uart) {
            try {
                //讀取PC終端發來的數據 ,並原封返回給PC
                byte[] buffer = new byte[CHUNK_SIZE];
                int read;
                while ((read = mUartDevice.read(buffer, buffer.length)) > 0) {
                    Log.w(TAG, "read from PC:"+ new String(buffer));
                    mUartDevice.write(buffer, read);
                }
            } catch (IOException e) {
                Log.w(TAG, "Unable to transfer data over UART", e);
            }
            return true;
        }

        @Override
        public void onUartDeviceError(UartDevice uart, int error) {
            Log.w(TAG, uart + ": Error event " + error);
        }
    };

    @Override
    protected void onDestroy() {
        super.onDestroy();
        //在不需要的時候,關閉連接
        if (mUartDevice != null) {
            try {
                mUartDevice.close();
                mUartDevice = null;
            } catch (IOException e) {
                Log.w(TAG, "Unable to close UART device", e);
            }
        }
    }
}

代碼庫:https://github.com/ThingsDeveloper/uartdemo

3.運行結果

我們是以windows系統演示,故使用了Termite終端,設置串口(相關驅動推薦使用驅動人生自動安裝) 連接參數(與代碼中一致,相關操作這裏就不詳細介紹)。

在終端輸入hello uart(藍色),就收到返回的hello uart(紅色)


1.拋棄各種找元器件的煩惱,來“1024工場”旗艦店,一次性買到你所想要的:樹莓派套裝—專爲Android Things打造。
樹莓派套裝
電腦用戶,點擊如下鏈接進入淘寶寶貝頁面:
https://item.taobao.com/item.htm?spm=686.1000925.0.0.3f11c9ed68fPu7&id=549263158263
手機用戶,打開淘寶客戶端掃描二維碼:
寶貝二維碼
2.完整和持續更新的《使用Android打開物聯網開發大門——Andoid Thigns開發》文檔,歡迎大家閱讀! 
https://www.kancloud.cn/workshop1024/android_things_develop/360773 
這裏寫圖片描述 
3.新技術,新未來!歡迎大家關注“1024工場”微信服務號,時刻關注我們的最新的技術訊息。
4.加入“Android Things開發”QQ討論羣,一起學習一起Hi。(甭客氣!盡情的掃描或者長按!)



     


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章