串口通訊庶弃,對于沒接觸過這方面的朋友們衫贬,確實會感到頭疼,不知道從何下手歇攻。
其實固惯,串口通訊和服務器之間的通訊是一樣的,都是傳一些參數(shù)過去缴守,然后返回一些數(shù)據(jù)回來葬毫。不過串口通訊管這些參數(shù)叫做指令,而這些指令是由硬件的通訊協(xié)議而定的屡穗,通訊協(xié)議不同贴捡,指令自然也不同。在我開發(fā)的這個項目里村砂,兼容了四種硬件通訊協(xié)議烂斋,這四種協(xié)議各不相同,所以箍镜,那些指令就不在代碼里面寫出來了源祈。
串口通訊,第一步要做的當然是打開串口色迂,打開串口的方法如下:
首先在app下建立一個libs文件夾香缺,把.so文件復制到libs下
用android studio的朋友們要記得在build.gradle 文件中添加這段 jniLibs.srcDirs = ['libs'] ,我有一次看見別人的代碼里面可以不加這段歇僧,照樣能運行图张,有知道的可以和大家分享一下。不過這些都不重要诈悍,只要能開串口就行祸轮。然后,在java的根目錄下建一個包侥钳,注意是根目錄适袜,包名為:android_serialport_api,這個包名是固定的舷夺,不能少也不能多苦酱。然后把類SerialPort復制到包下面。
// JNI
private native static FileDescriptor open(String path, int baudrate, int flags);
public native void close();
static { System.loadLibrary("serial_port"); }
上面的第一個函數(shù)open是調(diào)用jni打開串口的方法给猾,調(diào)用該方法的時候會返回一個FileDescriptor對象疫萤,通過該對象可以獲取輸入輸出流。第二個close函數(shù)是關(guān)閉串口的方法敢伸,可以通過此方法關(guān)閉串口扯饶。這兩個函數(shù)最好是能成對出現(xiàn),在程序打開的時候把串口打開,程序退出了就把串口關(guān)閉尾序,這樣可以避免一些問題出現(xiàn)钓丰。第三個是加載.so文件里面的代碼的,加載了之后串口才能用每币。
···
public SerialPort(File device, int baudrate, int flags) throws SecurityException, IOException {
System.out.println("device======"+device.getAbsolutePath());
/* Check access permission /
if (!device.canRead() || !device.canWrite()) {
try {
/ Missing read/write permission, trying to chmod the file */
Process 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);
}
···
上面的這段代碼中斑粱,su.getOutputStream().write(cmd.getBytes());這行是獲取root權(quán)限的,打開串口是需要root權(quán)限的脯爪,如果不能獲取root權(quán)限,串口也是打不開的矿微,其他的就是一些判斷了痕慢,在這就不做詳細講解了。
上面這些是開串口之前的準備涌矢,準備完畢后掖举,我們來打開串口,打開串口就是調(diào)用open函數(shù)娜庇,調(diào)用open函數(shù)需要傳三個參數(shù)塔次,第一個參數(shù)path是串口名,比如:”/dev/ttyS0“名秀,這些是根據(jù)實際接口來定的励负,第二個參數(shù)baudrate是波特率,一般都是9600匕得,15200继榆,這個需要根據(jù)硬件來定,第三個我就不清楚了汁掠,我都是傳0略吨,有知道的可以和大家分享一下。
···
/**
* 初始化串口
* @param lockerPortInterface
/
private void setSerialPort(LockerPortInterface lockerPortInterface){
this.sportInterface = lockerPortInterface;
try {
/ Check parameters /
if ((path.length() == 0) || (baudrate == -1)) {
throw new InvalidParameterException();
}
/ Open the serial port */
boxPort = new SerialPort(new File(path), baudrate, 0);
mOutputStreamBox = boxPort.getOutputStream();
mInputStreamBox = boxPort.getInputStream();
/* Create a serial rec buf thread */
mReadThreadBox = new ReadThreadBox();
// SerialPortState = true;
mReadThreadBox.start();
if (firstRegisterBox) {
if(mContext == null){
Log.e(TAG, "mContext nulll");
}
m_SerialRecBox = new SerialBroadcastReceiverBox(mContext);
m_SerialRecBox.registerAction();
firstRegisterBox = false;
Log.i(TAG, "----locker port--- 注冊完畢");
}
lockerPortInterface.onLockerOutputStream(mOutputStreamBox);
} catch (SecurityException e) {
e.printStackTrace();
DisplayError(mContext,R.string.error_security);
} catch (IOException e) {
e.printStackTrace();
DisplayError(mContext,R.string.error_unknown);
} catch (InvalidParameterException e) {
e.printStackTrace();
DisplayError(mContext,R.string.error_configuration);
}
}
···
boxPort = new SerialPort(new File(path), baudrate, 0);這行代碼是調(diào)用SerialPort的構(gòu)造方法考阱,通過他的構(gòu)造方法去調(diào)用open函數(shù)翠忠,然后通過SerialPort對象來獲取輸入輸出流。在這里解釋一下乞榨,輸入流是接收串口返回的數(shù)據(jù)秽之,輸出流是向串口發(fā)指令。 調(diào)用SerialPort的構(gòu)造方法可能會發(fā)生三種異常姜凄,第一種異常(SecurityException)是串口無讀寫權(quán)限政溃,拋出這種異常的話就說明你可能沒有root權(quán)限,第二種異常(IOException )串口不能打開态秧,可能就是你沒有這個串口董虱,第三種異常(InvalidParameterException)是傳的參數(shù)有誤,可能是你的波特率不對。我理解的就是這樣的愤诱,不知道對不對云头。
這是我用模擬器測試的,只要有請求root權(quán)限的頁面淫半,并且拋的是IO異常溃槐,打開串口應該就沒問題了。
最后就是向串口發(fā)指令科吭,向串口發(fā)指令是用輸出流向串口寫入昏滴,至于具體的指令是什么,需要根據(jù)協(xié)議來定对人。發(fā)完指令之后串口會回數(shù)據(jù)結(jié)果給你谣殊,你需要接收這些數(shù)據(jù)來做業(yè)務,硬件不同牺弄,回數(shù)據(jù)結(jié)果的方式也不同姻几,有些硬件是發(fā)完指令后把結(jié)果直接回給你,有些硬件是先給你一小部分势告,然后等1s再回另外一部分數(shù)據(jù)蛇捌。
在我寫的demo里面用的方法是針對硬件一次性把數(shù)據(jù)結(jié)果全部返回的方式,onLockerDataReceived直接用這個方法接收數(shù)據(jù)咱台,這樣就比較簡單了络拌。串口通訊說到這里就結(jié)束了。
最后貼上自己寫的一個小demo地址:https://github.com/fm183/SerialportDemo.git吵护,以供大家參考盒音。