Demo下载地址:
谷歌官方串口库使用
引言:
现在的串口通信多用于嵌入设备中,Android主板与各种板卡之间的通信。因此串口通信在未来智能设备中应用会很广泛。
现在市面上几乎所有的Android串口通信库都是用的Google开源的https://github.com/cepr/android-serialport-api封装而成。
但是很多第三方库质量参差不齐,出了问题也不知道是什么原因。因此自己基于官方公布.so来封装串口库就显得犹为重要。
- 下载Goolgle官方串口库工程
前往https://github.com/cepr/android-serialport-api下载示例工程,并解压。会看到有两个文件夹,一个为android-sercd,一个为android-serialport-api。
- 新建自己的串口库使用工程
新建自己的工程,如GoogleSerialDemo,将上图android-serialport-api->project->libs文件夹下的三个.so文件夹拷到自己工程的libs目录下。
拷贝后:
- 配置自己的工程
双击android-serialport-api文件夹,进入project->src,这时你会发现又有一个android-serialport-api文件夹。
让我们来看看这个文件夹下的内容是什么?
该文件夹包含了写好的SerialPort.java类及SerialPortFinder.java类,这两个类的作用是提供应用调用底层串口C++代码的接口,而且完全是官方代码,因此不用担心被坑。
sample文件夹则是串口示例代码。
将这个android-serialport-api文件夹整个拷到自己工程下的src->main->java目录下。这时可能你有疑问了,我们需要的是SerialPort.java和SerialPortFinder.java这两个类,为什么要将整个文件夹一起拷过来?
这也是很多博客没有提及的。
原因其实也很简单,熟悉jni的都知道,jni调用是需要严格对应应用的包名的。而我们需要调用的是Google写好的C++代码,这些代码已经封装在.so库中,其包名已经确定了的。我们需要使用就必须知道其包名,其包名就是android_serialport_api。因此使用到jni的SerialPort.java和SerialPortFinder.java类必须要在android_serialport_api目录下。
拷贝过来后我们可以把目录下的sample删除掉以减少内存占用。然后打开工程我们就多了一个android_serialport_api的目录。
要使用串口还需要一步,还记得之前拷的那些.so的文件夹吗?这一步就需要在build.gradle的defaultConfig下面加入以下代码,注意是跟defaultConfig同级的,不是在defaultConfig声明里面。
sourceSets {
main {
jniLibs.srcDirs = ['libs']
}
}
- 使用串口库
到了这一步就可以愉快地使用串口库了,再也不用担心第三方串口库封装出现的bug了。这里提供一个封装的基类供参考。
package com.mhwang.goolgleserialdemo;
import android.util.Log;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.Map;
import android_serialport_api.SerialPort;
/**
* Description : 串口通信基类,定义串口通信的常量及操作方法
* Author :mhwang
* Date : 2018/6/14
* Version : V1.0
*/
abstract class BaseSerialPort {
InputStream mInputStream = null;
OutputStream mOutputStream = null;
SerialPort mSerialPort = null;
Map<String,String> mSerialMap;
abstract public boolean write(String data);
abstract public boolean write(byte[] data);
abstract public String receive();
abstract public byte[] receiveBytes();
abstract public boolean open();
abstract public boolean close();
/** 读取数据
* @param inputStream 串口对象
* @return byte[]数组,若没有,返回null
*/
byte[] readData(InputStream inputStream){
// // 暂停200毫秒以等待数据返回 有些串口延迟会出现粘包,比如门卡板,因此根据实际情况添加
// SystemClock.sleep(200);
int size;
try {
if (inputStream == null) {
showLog("inputStream is null");
return null;
}
byte[] buffer = new byte[256];
size = inputStream.read(buffer);
byte[] data = new byte[size];
System.arraycopy(buffer,0,data,0,size);
if (size > 0) {
return data;
}else{
showLog("receive no data");
}
}catch (Exception e){
showLog(e.toString());
}
return null;
}
/** 打开串口
* @param device 要打开的串口文件
* @param baudrate 波特率
* @param flag 标志
* @return true,打开成功,false,打开失败
*/
boolean openSerialPort(File device, int baudrate, int flag){
try {
mSerialPort = new SerialPort(device, baudrate, flag);
mInputStream = mSerialPort.getInputStream();
mOutputStream = mSerialPort.getOutputStream();
} catch (IOException e) {
mInputStream = null;
mOutputStream = null;
e.printStackTrace();
return false;
}
if (mInputStream == null || mOutputStream == null) return false;
return true;
}
boolean closeSerialPort(){ // 这里不做事情是因为有时应用频繁打开关闭会使得再次打开串口收不到消息
// try {
// if (mInputStream != null){
// mInputStream.close();
// mInputStream = null;
// }
// if (mOutputStream != null){
// mOutputStream.close();
// mOutputStream = null;
// }
// if (mSerialPort != null){
// mSerialPort.close();
// mSerialPort = null;
// }
// }catch (Exception e){
// FileUtil.writeNote("BaseSerialPort-->"+ AppError.SERIAL_CLOSE_FAIL+e.toString());
// return false;
// }
return true;
}
private void showLog(String s) {
Log.d("BaseSerialPort-->",s);
}
}