1. 程式人生 > 其它 >Android--關於串列埠通訊

Android--關於串列埠通訊

利用串列埠,可以讓Android主機板與各種感測器和智慧裝置之間通訊。Google自己有一個關於Android串列埠通訊

整合環境

一般串列埠通訊開發,需要用到JNI和NDK方面的知識。首先需要搭建環境,匯入相應的.so檔案(.so檔案是Unix的動態連線庫,本身是二進位制檔案,是由C/C++編譯而來的),沒有就自己新建libs,將.so檔案複製進去。

之後需要再Gradle檔案,將libs中的東西引入編譯,不然訪問不到。如下圖

android {
    compileSdkVersion 30
    buildToolsVersion "30.0.3"
    
    defaultConfig {
       ......

      /*選擇處理器相應的架構*/
        ndk {
            abiFilters "armeabi"
        }

        testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
    }
        .....
    /*載入 so庫*/
    sourceSets {
        main {
            jniLibs.srcDirs = ['libs']
        }
    }
}

Google的demo中的 SerialPort.java (串列埠程式碼)

/*
 * Copyright 2009 Cedric Priscal
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * 
 * http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License. 
 */

package android_serialport_api;

import java.io.File;
import java.io.FileDescriptor;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;

import android.util.Log;

public class SerialPort {

	private static final String TAG = "SerialPort";

	/*
	 * Do not remove or rename the field mFd: it is used by native method close();
	 */
	private FileDescriptor mFd;
	private FileInputStream mFileInputStream;//輸入流
	private FileOutputStream mFileOutputStream;//輸出流

    // 裝置號(串列埠地址),波特率,flags 預設為0
	public SerialPort(File device, int baudrate, int flags) throws SecurityException, IOException {

		/* Check access permission  檢查許可權 */
		if (!device.canRead() || !device.canWrite()) {
			try {
				/* Missing read/write permission, trying to chmod the file */
				Process su;
				su = Runtime.getRuntime().exec("/system/bin/su");
				String cmd = "chmod 666 " + device.getAbsolutePath() + "\n"
						+ "exit\n";
				su.getOutputStream().write(cmd.getBytes());
				if ((su.waitFor() != 0) || !device.canRead()
						|| !device.canWrite()) {
					throw new SecurityException();
				}
			} catch (Exception e) {
				e.printStackTrace();
				throw new SecurityException();
			}
		}

		mFd = open(device.getAbsolutePath(), baudrate, flags);//開啟串列埠
		if (mFd == null) {
			Log.e(TAG, "native open returns null");
			throw new IOException();
		}
		mFileInputStream = new FileInputStream(mFd);
		mFileOutputStream = new FileOutputStream(mFd);
	}

	// Getters and setters
	public InputStream getInputStream() {
		return mFileInputStream;
	}

	public OutputStream getOutputStream() {
		return mFileOutputStream;
	}

	// JNI
	private native static FileDescriptor open(String path, int baudrate, int flags);
	public native void close();
	static {
		System.loadLibrary("serial_port");
	}
}

// 如何使用
SerialPort serial = new SerialPort(new File("/dev/goc_serial"),115200,0);

**[SerialPortUtil](https://juejin.cn/post/6844903606982967303)**
public class SerialPortUtil {

    private SerialPort serialPort = null;
    private InputStream inputStream = null;
    private OutputStream outputStream = null;
    private ReceiveThread mReceiveThread = null;
    private boolean isStart = false;

    /**
     * 開啟串列埠,接收資料
     * 通過串列埠,接收單片機發送來的資料
     */
    public void openSerialPort() {
        try {
            serialPort = new SerialPort(new File("/dev/ttyS0"), 9600, 0);
            //呼叫物件SerialPort方法,獲取串列埠中"讀和寫"的資料流
            inputStream = serialPort.getInputStream();
            outputStream = serialPort.getOutputStream();
            isStart = true;

        } catch (IOException e) {
            e.printStackTrace();
        }
        getSerialPort();
    }

    /**
     * 關閉串列埠
     * 關閉串列埠中的輸入輸出流
     */
    public void closeSerialPort() {
        Log.i("test", "關閉串列埠");
        try {
            if (inputStream != null) {
                inputStream.close();
            }
            if (outputStream != null) {
                outputStream.close();
            }
            isStart = false;
        } catch (IOException e) {
            e.printStackTrace();
        }

    }

    /**
     * 傳送資料
     * 通過串列埠,傳送資料到微控制器
     *
     * @param data 要傳送的資料
     */
    public void sendSerialPort(String data) {
        try {
            byte[] sendData = DataUtils.HexToByteArr(data);//字串轉為位元組陣列
            outputStream.write(sendData);
            outputStream.flush();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    private void getSerialPort() {
        if (mReceiveThread == null) {

            mReceiveThread = new ReceiveThread();
        }
        mReceiveThread.start();
    }

    /**
     * 接收串列埠資料的執行緒
     */

    private class ReceiveThread extends Thread {
        @Override
        public void run() {
            super.run();
            while (isStart) {
                if (inputStream == null) {
                    return;
                }
                byte[] readData = new byte[1024];
                try {
                    int size = inputStream.read(readData);
                    if (size > 0) {
                        String readString = DataUtils.ByteArrToHex(readData, 0, size);//位元組陣列轉為字串
                        //EventBus.getDefault().post(readString);事件通知,拿到資料
                    }

                } catch (IOException e) {
                    e.printStackTrace();
                }
            }

        }
    }

}