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(紅色)
電腦用戶,點擊如下鏈接進入淘寶寶貝頁面:
https://item.taobao.com/item.htm?spm=686.1000925.0.0.3f11c9ed68fPu7&id=549263158263
手機用戶,打開淘寶客戶端掃描二維碼:
https://www.kancloud.cn/workshop1024/android_things_develop/360773