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

寫在前面的話:由于外設(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在連接在同一本地總線上的兩個(gè)或多個(gè)智能設(shè)備之間傳輸更大的數(shù)據(jù)有效負(fù)載伟墙。 下表概述了每個(gè)支持的串行協(xié)議的基本屬性:

協(xié)議 傳輸類型 電線數(shù)量 外圍設(shè)備數(shù)量 傳輸速度
I2C 同步 2 Up to 127 Low
SPI 同步 4+ Unlimited High
UART 異步 2 or 4 1 Medium

UART

復(fù)雜的外圍設(shè)備,如GPS模塊爹袁,LCD顯示器和XBee無線電通常使用通用異步收發(fā)器(UART)端口(通常簡稱為串行端口)進(jìn)行通信远荠。
??UART是用于與外圍設(shè)備交換原始數(shù)據(jù)的通用接口。 它是通用的失息,因?yàn)閿?shù)據(jù)傳輸速度和數(shù)據(jù)字節(jié)格式都是可配置的譬淳。 它是異步的,因?yàn)椴淮嬖谟糜谕絻蓚€(gè)設(shè)備之間的數(shù)據(jù)傳輸?shù)臅r(shí)鐘信號(hào)盹兢。 設(shè)備硬件以先進(jìn)先出(FIFO)緩沖區(qū)收集所有傳入數(shù)據(jù)邻梆,直到應(yīng)用程序讀取為止。
??UART數(shù)據(jù)傳輸是全雙工的绎秒,意味著數(shù)據(jù)可以同時(shí)發(fā)送和接收浦妄。 它通常比I2C快,但缺乏共享時(shí)鐘意味著兩個(gè)設(shè)備必須達(dá)成一個(gè)共同的數(shù)據(jù)傳輸速率见芹,每個(gè)設(shè)備可以獨(dú)立遵守與最小的定時(shí)誤差剂娄。

UART連接

UART外設(shè)通常有兩種類型:

  • 3線端口包括數(shù)據(jù)接收(RX),數(shù)據(jù)發(fā)送(TX)和接地參考(GND)信號(hào)玄呛。
  • 5線端口添加用于硬件流控制的請求發(fā)送(RTS)和清除發(fā)送(CTS)信號(hào)阅懦。 流控制允許接收設(shè)備指示其FIFO緩沖器臨時(shí)滿,并且發(fā)送設(shè)備在發(fā)送任何更多數(shù)據(jù)之前應(yīng)該等待徘铝。

與SPI和I2C不同耳胎,UART僅支持兩個(gè)器件之間的點(diǎn)對點(diǎn)通信惯吕。

管理連接

為了打開到特定UART的連接,您需要知道唯一的端口名稱怕午。 在開發(fā)的初始階段或?qū)?yīng)用程序移植到新硬件時(shí)废登,可以通過 getUartDeviceList()從PeripheralManagerService找到所有可用的設(shè)備名稱:

PeripheralManagerService manager = new PeripheralManagerService();
List<String> deviceList = manager.getUartDeviceList();
if (deviceList.isEmpty()) {
    Log.i(TAG, "No UART port available on this device.");
} else {
    Log.i(TAG, "List of available devices: " + deviceList);
}

一旦知道目標(biāo)名稱,就可以使用PeripheralManagerService連接到該設(shè)備郁惜。 與外圍設(shè)備通信后堡距,關(guān)閉連接以釋放資源。 此外扳炬,在現(xiàn)有連接關(guān)閉之前吏颖,無法打開與設(shè)備的新連接。 要關(guān)閉連接恨樟,請使用設(shè)備的close()方法半醉。

public class HomeActivity extends Activity {
    // UART設(shè)備名稱
    private static final String UART_DEVICE_NAME = ...;

    private UartDevice mDevice;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        // 嘗試訪問UART設(shè)備
        try {
            PeripheralManagerService manager = new PeripheralManagerService();
            mDevice = manager.openUartDevice(UART_DEVICE_NAME);
        } catch (IOException e) {
            Log.w(TAG, "Unable to access UART 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 UART device", e);
            }
        }
    }
}

配置端口參數(shù)

建立連接后,配置數(shù)據(jù)傳輸速率和幀格式以匹配連接的外圍設(shè)備劝术。

數(shù)據(jù)幀

通過UART發(fā)送的每個(gè)字符都包裹在一個(gè)數(shù)據(jù)幀中缩多,該數(shù)據(jù)幀包含以下組件:

UART框架
  • 啟動(dòng)位 - 在發(fā)送數(shù)據(jù)之前,該行保持活動(dòng)狀態(tài)养晋,持續(xù)1位持續(xù)時(shí)間的固定時(shí)間間隔衬吆,以指示新字符的開始。
  • 數(shù)據(jù)位 - 表示數(shù)據(jù)字符的各位绳泉。 UART可以配置為在5-9個(gè)數(shù)據(jù)位之間發(fā)送以表示字符逊抡。 較少的位減少了數(shù)據(jù)的范圍,但可以增加有效的數(shù)據(jù)傳輸速率零酪。
  • 奇偶校驗(yàn)位 - 可選錯(cuò)誤校驗(yàn)值冒嫡。 如果UART配置為偶校驗(yàn)或奇校驗(yàn),則會(huì)在幀中添加一個(gè)額外的位四苇,以指示數(shù)據(jù)位的內(nèi)容是否為偶數(shù)或奇數(shù)值孝凌。 將此設(shè)置為none會(huì)從幀中刪除該位。
  • 停止位 - 在傳輸所有數(shù)據(jù)之后月腋,線路被重置一個(gè)可配置的時(shí)間間隔蟀架,以指示該字符的結(jié)束。 這可以配置為保持空閑1或2位持續(xù)時(shí)間榆骚。

注:大多數(shù)UART器件的默認(rèn)配置為8個(gè)數(shù)據(jù)位片拍,無奇偶校驗(yàn)和1個(gè)停止位(8N1)。

UART上的數(shù)據(jù)傳輸速率稱為波特率妓肢。 它表示接收和發(fā)送的速度(以位/秒為單位)穆碎。 由于在通過UART連接的兩個(gè)器件之間沒有共享時(shí)鐘,因此必須提前配置這兩個(gè)器件职恳,才能使用相同的波特率正確解碼數(shù)據(jù)所禀。
??常用波特率包括9600,19200,38400,57600,115200和921600.該速率包括數(shù)據(jù)幀(開始,停止和奇偶校驗(yàn)位)的開銷放钦,因此有效數(shù)據(jù)傳輸速率將略低色徘,并且根據(jù) 您配置的幀位數(shù)。
??以下代碼將UART連接配置為以115200波特操禀,8個(gè)數(shù)據(jù)位褂策,無奇偶校驗(yàn)和1個(gè)停止位(8N1)操作:

public void configureUartFrame(UartDevice uart) throws IOException {
    // 配置UART端口
    uart.setBaudrate(115200);
    uart.setDataSize(8);
    uart.setParity(UartDevice.PARITY_NONE);
    uart.setStopBits(1);
}

注意:選擇不常見的波特率可能導(dǎo)致數(shù)據(jù)傳輸中的高錯(cuò)誤率。 您應(yīng)該始終驗(yàn)證您選擇的波特率是否得到設(shè)備硬件的良好支持颓屑。

硬件流控制

如果您的設(shè)備支持5線UART端口斤寂,則啟用硬件流控制可以提高數(shù)據(jù)傳輸?shù)目煽啃浴?通常這也意味著您可以安全地使用更快的波特率,而丟失傳入數(shù)據(jù)的機(jī)會(huì)更低揪惦。

UART流控制

在硬件流控制使能的情況下遍搞,當(dāng)器件上的接收緩沖器已滿并且不能接受任何更多數(shù)據(jù)時(shí),UART將發(fā)送請求發(fā)送(RTS)信號(hào)器腋。 一旦緩沖液被排空溪猿,信號(hào)將被清除。 類似地纫塌,UART監(jiān)視清除發(fā)送(CTS)信號(hào)诊县,并且如果它看到由外圍設(shè)備斷言的線,則將暫停發(fā)送數(shù)據(jù)措左。
??要啟用硬件流控制依痊,請使用帶有HW_FLOW_CONTROL_AUTO_RTSCTS的setHardwareFlowControl()方法。 默認(rèn)值為HW_FLOW_CONTROL_NONE怎披,表示禁用流控制胸嘁。

public void setFlowControlEnabled(UartDevice uart, boolean enable) throws IOException {
    if (enable) {
        // 啟用硬件流控制
        uart.setHardwareFlowControl(UartDevice.HW_FLOW_CONTROL_AUTO_RTSCTS);
    } else {
        // 禁用流量控制
        uart.setHardwareFlowControl(UartDevice.HW_FLOW_CONTROL_NONE);
    }
}

傳輸輸出數(shù)據(jù)

要通過UART將數(shù)據(jù)緩沖區(qū)傳輸?shù)酵庠O(shè),請使用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");
}

注意:Java字節(jié)是一個(gè)8位值钳枕。 如果使用setDataSize()配置較小的數(shù)據(jù)寬度缴渊,每個(gè)字節(jié)的高位將被截?cái)唷?/p>

偵聽傳入數(shù)據(jù)

使用read()方法將輸入數(shù)據(jù)從UART FIFO緩沖區(qū)拉入應(yīng)用程序。 此方法接受空緩沖區(qū)以填充傳入數(shù)據(jù)和要讀取的最大字節(jié)數(shù)鱼炒。 UART讀取是非阻塞的衔沼,如果FIFO中沒有可用的數(shù)據(jù),則會(huì)立即返回昔瞧。
??UartDevice將在讀取時(shí)返回FIFO中的可用字節(jié)數(shù)指蚁,直到所請求的計(jì)數(shù)。 要確保所有數(shù)據(jù)都恢復(fù)自晰,請循環(huán)UART凝化,直到它報(bào)告沒有更多的數(shù)據(jù):

public void readUartBuffer(UartDevice uart) throws IOException {
    // 一次讀取的最大數(shù)據(jù)量
    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");
    }
}

為了避免在緩沖區(qū)為空時(shí)不必要地輪詢UART,用UartDevice注冊一個(gè)UartDeviceCallback酬荞。 當(dāng)有可用于讀取的數(shù)據(jù)時(shí)搓劫,此回調(diào)調(diào)用onUartDeviceDataAvailable()方法瞧哟。 當(dāng)應(yīng)用程序不再偵聽傳入數(shù)據(jù)時(shí),應(yīng)該取消注冊回調(diào)枪向。

public class HomeActivity extends Activity {
    private UartDevice mDevice;
    ...

    @Override
    protected void onStart() {
        super.onStart();
        // 開始監(jiān)聽中斷事件
        mDevice.registerUartDeviceCallback(mUartCallback);
    }

    @Override
    protected void onStop() {
        super.onStop();
        // 中斷事件不再需要
        mDevice.unregisterUartDeviceCallback(mUartCallback);
    }

    private UartDeviceCallback mUartCallback = new UartDeviceCallback() {
        @Override
        public boolean onUartDeviceDataAvailable(UartDevice uart) {
            // 從UART設(shè)備讀取可用數(shù)據(jù)
            try {
                readUartBuffer(uart);
            } catch (IOException e) {
                Log.w(TAG, "Unable to access UART device", e);
            }

            // 繼續(xù)偵聽更多中斷
            return true;
        }

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

onUartDeviceDataAvailable()回調(diào)返回一個(gè)布爾值勤揩,指示回調(diào)是否應(yīng)該在接收未來中斷事件時(shí)自動(dòng)取消注冊。 此處返回true秘蛔,以便在每次UART FIFO中顯示數(shù)據(jù)時(shí)繼續(xù)接收事件陨亡。


參考文獻(xiàn) https://developer.android.google.cn/things/sdk

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市深员,隨后出現(xiàn)的幾起案子负蠕,更是在濱河造成了極大的恐慌,老刑警劉巖倦畅,帶你破解...
    沈念sama閱讀 206,013評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件遮糖,死亡現(xiàn)場離奇詭異,居然都是意外死亡滔迈,警方通過查閱死者的電腦和手機(jī)止吁,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,205評論 2 382
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來燎悍,“玉大人敬惦,你說我怎么就攤上這事√干剑” “怎么了俄删?”我有些...
    開封第一講書人閱讀 152,370評論 0 342
  • 文/不壞的土叔 我叫張陵,是天一觀的道長奏路。 經(jīng)常有香客問我畴椰,道長,這世上最難降的妖魔是什么鸽粉? 我笑而不...
    開封第一講書人閱讀 55,168評論 1 278
  • 正文 為了忘掉前任斜脂,我火速辦了婚禮,結(jié)果婚禮上触机,老公的妹妹穿的比我還像新娘帚戳。我一直安慰自己,他們只是感情好儡首,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,153評論 5 371
  • 文/花漫 我一把揭開白布片任。 她就那樣靜靜地躺著,像睡著了一般蔬胯。 火紅的嫁衣襯著肌膚如雪对供。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 48,954評論 1 283
  • 那天氛濒,我揣著相機(jī)與錄音产场,去河邊找鬼鹅髓。 笑死,一個(gè)胖子當(dāng)著我的面吹牛京景,可吹牛的內(nèi)容都是我干的迈勋。 我是一名探鬼主播,決...
    沈念sama閱讀 38,271評論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼醋粟,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了重归?” 一聲冷哼從身側(cè)響起米愿,我...
    開封第一講書人閱讀 36,916評論 0 259
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎鼻吮,沒想到半個(gè)月后育苟,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,382評論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡椎木,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,877評論 2 323
  • 正文 我和宋清朗相戀三年违柏,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片香椎。...
    茶點(diǎn)故事閱讀 37,989評論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡漱竖,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出畜伐,到底是詐尸還是另有隱情馍惹,我是刑警寧澤,帶...
    沈念sama閱讀 33,624評論 4 322
  • 正文 年R本政府宣布玛界,位于F島的核電站万矾,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏慎框。R本人自食惡果不足惜良狈,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,209評論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望笨枯。 院中可真熱鬧薪丁,春花似錦、人聲如沸猎醇。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,199評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽硫嘶。三九已至阻问,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間沦疾,已是汗流浹背称近。 一陣腳步聲響...
    開封第一講書人閱讀 31,418評論 1 260
  • 我被黑心中介騙來泰國打工第队, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人刨秆。 一個(gè)月前我還...
    沈念sama閱讀 45,401評論 2 352
  • 正文 我出身青樓凳谦,卻偏偏與公主長得像,于是被迫代替她去往敵國和親衡未。 傳聞我的和親對象是個(gè)殘疾皇子尸执,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,700評論 2 345

推薦閱讀更多精彩內(nèi)容