串口通讯,对于没接触过这方面的朋友们,确实会感到头疼,不知道从何下手。

其实,串口通讯和服务器之间的通讯是一样的,都是传一些参数过去,然后返回一些数据回来。不过串口通讯管这些参数叫做指令,而这些指令是由硬件的通讯协议而定的,通讯协议不同,指令自然也不同。在我开发的这个项目里,兼容了四种硬件通讯协议,这四种协议各不相同,所以,那些指令就不在代码里面写出来了。

串口通讯,第一步要做的当然是打开串口,打开串口的方法如下:

QQ截图20161211220537.png

首先在app下建立一个libs文件夹,把.so文件复制到libs下

QQ截图20161211220537.png

用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"); }

上面的第一个函数open是调用jni打开串口的方法,调用该方法的时候会返回一个FileDescriptor对象,通过该对象可以获取输入输出流。第二个close函数是关闭串口的方法,可以通过此方法关闭串口。这两个函数最好是能成对出现,在程序打开的时候把串口打开,程序退出了就把串口关闭,这样可以避免一些问题出现。第三个是加载.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权限的,打开串口是需要root权限的,如果不能获取root权限,串口也是打不开的,其他的就是一些判断了,在这就不做详细讲解了。

上面这些是开串口之前的准备,准备完毕后,我们来打开串口,打开串口就是调用open函数,调用open函数需要传三个参数,第一个参数path是串口名,比如:”/dev/ttyS0“,这些是根据实际接口来定的,第二个参数baudrate是波特率,一般都是9600,15200,这个需要根据硬件来定,第三个我就不清楚了,我都是传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);这行代码是调用SerialPort的构造方法,通过他的构造方法去调用open函数,然后通过SerialPort对象来获取输入输出流。在这里解释一下,输入流是接收串口返回的数据,输出流是向串口发指令。 调用SerialPort的构造方法可能会发生三种异常,第一种异常(SecurityException)是串口无读写权限,抛出这种异常的话就说明你可能没有root权限,第二种异常(IOException )串口不能打开,可能就是你没有这个串口,第三种异常(InvalidParameterException)是传的参数有误,可能是你的波特率不对。我理解的就是这样的,不知道对不对。

openserialport.gif

这是我用模拟器测试的,只要有请求root权限的页面,并且抛的是IO异常,打开串口应该就没问题了。

最后就是向串口发指令,向串口发指令是用输出流向串口写入,至于具体的指令是什么,需要根据协议来定。发完指令之后串口会回数据结果给你,你需要接收这些数据来做业务,硬件不同,回数据结果的方式也不同,有些硬件是发完指令后把结果直接回给你,有些硬件是先给你一小部分,然后等1s再回另外一部分数据。

在我写的demo里面用的方法是针对硬件一次性把数据结果全部返回的方式,onLockerDataReceived直接用这个方法接收数据,这样就比较简单了。串口通讯说到这里就结束了。

最后贴上自己写的一个小demo地址:https://github.com/fm183/SerialportDemo.git,以供大家参考。

Logo

为开发者提供学习成长、分享交流、生态实践、资源工具等服务,帮助开发者快速成长。

更多推荐