1. 程式人生 > >Android之串列埠程式設計

Android之串列埠程式設計

閱讀時長:10分鐘

原文地址:juejin.im/post/5bd96c…

原文作者:YKamh

技術預備:Java基礎

如今我們生活中充滿了各種智慧裝置,方便了我們的生活,這正是物聯網時代。如果我們要開發智慧裝置,那麼Android串列埠程式設計是我們應該必備的技能。

在投身到Android開發行業前,作者一直以為Android開發就是單純的寫手機端應用。隨著接觸的專案越來越多,漸漸的開始接觸到了Android應用結合控制硬體裝置的專案了,應用控制鎖、印表機、掃碼器等等,這正是要使用到安卓串列埠程式設計的知識。

STEP1

安卓串列埠程式設計中使用到的是谷歌開源serialPort api

下載連結:

github.com/cepr/androi…

在GitHub上把所需資源下載下來之後就可以按下圖的目錄結構放置資源

請讀者注意框框內的東東,其中應為使用到Google的原生so庫,SerialPort類的包名一定要是android_serialport_api,如果想修改這個包名,就需要重新生成對應的so庫。

還有就是SerialPort.java檔案中的open()和close()方法雖然是紅色的但我們不用理會,編譯是通過的。

STEP2

在專案gradle檔案中的buildTypes節點下加上下面一句話

STEP3

編寫封裝串列埠工具類,主要分為以下步驟來開啟串列埠:

  1. 設定埠號、波特率

  2. 獲取開啟的串列埠中的輸入輸出流,以便於串列埠資料的收發

  3. 開啟讀取串列埠資訊執行緒(接收串列埠返回資訊很多時候都是需要等待的耗時操作,因此開啟執行緒去等待)

  4. 繫結串列埠返回監聽

  • path:埠號,一定要以這種格式編寫,針對硬體的不同可能會用到/dev/ttyS2或者/dev/ttyS1等等。

  • baudrate:波特率

  • serialPortStatus:串列埠開啟標誌

  • data_:傳送的串列埠資料

  • threadStatus:終止執行緒標誌位(這裡更應該加上Volatile修飾)

  • mSerialPort:谷歌提供的api

  • mInputStream:串列埠輸入流

  • mOutputStream:串列埠輸出流

/**
 * 
 * 開啟串列埠     
 * @return  serialPort串列埠物件     
 */
public SerialPort openSerialPort()
{
    try {
        mSerialPort = new SerialPort(new File(path), baudrate, 0);
        this.serialPortStatus = true;
        threadStatus = false;
        //獲取開啟的串列埠中的輸入輸出流,以便於串列埠資料的收發            
        mInputStream = mSerialPort.getInputStream();
        mOutputStream = mSerialPort.getOutputStream();
        new ReadThread().start();//開啟執行緒監控是否有資料的收發        
    } catch (IOException e){
        Log.e(TAG, "openSerialPort:開啟串列埠異常:" + e.toString());
        return mSerialPort;
    }
    Log.d(TAG, "openSerialPort: 開啟串列埠");
    return mSerialPort;
}
複製程式碼

開啟串列埠方法主要完成了使用Google API的構造方法傳入埠號和波特率,獲取輸入輸出流,開啟監聽執行緒。

/**
 * 
 * 關閉串列埠     
 */
public void closeSerialPort()
{
    try {
        if (mInputStream != null) {
            mInputStream.close();
        }
        if (mOutputStream != null) {
            mOutputStream.close();
        }
        this.threadStatus = true;
        this.serialPortStatus = false;
        mSerialPort.close();
    } catch (IOException e){
        Log.e(TAG, "closeSerialPort: 關閉串列埠異常" + e.toString());
        return;
    }
    Log.d(TAG, "closeSerialPort: 串列埠關閉成功");
}
複製程式碼

關閉串列埠方法裡主要完成了把輸入輸出流關閉,呼叫Google API關閉串列埠方法和使用標誌位方法安全關閉監聽執行緒。

public void sendSerialPort(String data)
{
    Log.d(TAG, "sendSerialPort: 傳送資料" + data);
    try {
        byte[]
        sendData = data.getBytes("gb2312");
        this.data_ = new String(sendData);
        if (sendData.length > 0) {
            mOutputStream.write(sendData);
            mOutputStream.write('\n');
            mOutputStream.flush();
            Log.d(TAG, "sendSerialPort: 傳送串列埠資料成功");
        }
    } catch (IOException e)
    {
        Log.e(TAG, "sendSerialPort: 串列埠傳送資料失敗 " + e.toString());
    }
}
複製程式碼

傳送方法中,這個方法只是針對印表機操作例項來實現的,紅框中我們要把傳送的字串換成gb2312的byte陣列傳送出去。

其實在串列埠通訊中,所有的指令都要轉化為byte陣列傳送出去的。大家可以在作者的這個簡單工具類中加以改進,使其更加通用。

class ReadThread extends Thread {
    
    @Override 
    public void run() {
        super.run();            //判斷執行緒是否安全進行,更安全的結束執行緒            
        while (!threadStatus){
            Log.d(TAG, "進入執行緒run");
            byte[] buffer = new byte[64];
            int size;
            try {
                size = mInputStream.read(buffer);
                if (size > 0) {
                    Log.d(TAG, "run: 接收到資料大小:" + size);
                    onDataReceiveListener.onDataReceive(buffer, size);
                }
            } catch (IOException e){
                Log.e(TAG, "run: 資料讀取異常" + e.toString());
            }
        }
    }
}
複製程式碼

監聽執行緒中重點在try程式碼塊中,InputStream.read()方法是一個阻塞操作,可根據專案需要使用interrupt()方法快速關閉執行緒,無需使用標誌位等待到下一個迴圈才結束。

此外try程式碼塊中還呼叫了onDataReceive()自定義介面的方法,用於返回執行緒監聽的資料。

public OnDataReceiveListener onDataReceiveListener = null;

public static interface OnDataReceiveListener
{
    void onDataReceive(byte[] buffer, int size);
}
public void setOnDataReceiveListener(OnDataReceiveListener listener)
{
    this.onDataReceiveListener = listener;
}
複製程式碼

工具類中還有一個OnDataReceiveListener變數,用於在外部呼叫者設定監聽的介面。

注意這裡onDataReceive()方法中的引數 buffer,同樣的道理串列埠傳送指令最終轉換為byte陣列傳送,接收到的資訊同樣也是byte陣列型別,所以根據需求可以將這個byte陣列轉化為字串等等其他。

下面提供byte陣列轉換為字串的方法和字串轉換成十六進位制byte陣列的方法。

完整程式碼:

github.com/YKamh/Seria…

PS:Demo只是簡單實現了基本的串列埠程式設計功能,並沒有對細節優化。

結語

面臨物聯網時代的趨勢,android串列埠程式設計也是我們所應該必備的。在以上知識點中,其中的的核心程式碼依然是Java基礎,也體現出Java基礎的重要性。

在作者接觸結合硬體的專案的時候,心情是彷彿發現了新大陸,串列埠程式設計更是有趣,沒有開發純應用的枯燥。

希望大家一起努力,一起成長!

----- End -----

更多好文

請掃描下面二維碼

歡迎關注~