引言:
最近项目用到了串口通信功能,刚好写一篇文章来记录一下.
为什么学习Android串口通信:
- 现在,对于很多公司而言,Android主板与各种传感器和智能设备之间通信是很常见的事情了,那么安卓开发中,串口通信就是必须学习的事情了!
- Google出品,必属精品。Android串口通信的源代码是Google公司在2011年开源的Google官方源代码
集成串口通信:
一 、新建库项目导入so库
二 、 配置Gradle文件:基本没啥可配置的
前置工作就这么完成了....
Google串口代码分析之SerialPort类
-
package android_serialport_api;
-
-
import android.util.Log;
-
-
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;
-
-
/**
-
* Google官方代码
-
* 此类的作用为,JNI的调用,用来加载.so文件的
-
* 获取串口输入输出流
-
*/
-
-
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;
-
-
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();
-
}
-
}
-
-
Log.v(TAG,
".\n********************************\nfile:" + device.getAbsolutePath() +
-
"\nbaudrate:" + baudrate +
"\nflags:" + flags +
"\n********************************");
-
-
mFd = open(device.getAbsolutePath(), baudrate, flags);
-
if (mFd ==
null) {
-
Log.e(TAG,
"native open returns null");
-
throw
new IOException();
-
}
-
Log.v(TAG,
"open:" + mFd);
-
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.out.println(
"==============================");
-
System.loadLibrary(
"serial_port");
-
System.out.println(
"********************************");
-
}
-
}
一:类作用及介绍
通过打开JNI的调用,打开串口。获取串口通信中的输入输出流,通过操作IO流,达到能够利用串口接收数据和发送数据的目的
A : 开启串口的方法:private native static FileDescriptor open(String path, int baudrate,int flags)
- path:为串口的物理地址,一般硬件工程师都会告诉你的例如ttyS0、ttyS1等,或者通过SerialPortFinder类去寻找得到可用的串口地址。
- baudrate:波特率,与外接设备一致
- flags:设置为0,原因较复杂,有兴趣的可以自己去研究一下
B : IO流
获取了输入输出流以后就可以对流进行操作了。
-
package com.seriallibrary.myserialport;
-
-
import android.util.Log;
-
-
-
import android_serialport_api.SerialPort;
-
-
import java.io.File;
-
import java.io.IOException;
-
import java.io.InputStream;
-
import java.io.OutputStream;
-
-
-
/**
-
* @author by AllenJ on 2018/4/20.
-
* <p>
-
* 通过串口用于接收或发送数据
-
*/
-
-
public
class SerialPortUtil {
-
-
private SerialPort serialPort =
null;
-
private InputStream inputStream =
null;
-
private OutputStream outputStream =
null;
-
private ReceiveThread mReceiveThread =
null;
-
private
boolean isStart =
false;
-
-
private SerialListen mSerialListen;
-
-
/**
-
* 打开串口,接收数据
-
* 通过串口,接收单片机发送来的数据
-
*/
-
public void openSerialPort(String path, int baudrate, int flags) {
-
try {
-
serialPort =
new SerialPort(
new File(path), baudrate, flags);
-
//调用对象SerialPort方法,获取串口中"读和写"的数据流
-
inputStream = serialPort.getInputStream();
-
outputStream = serialPort.getOutputStream();
-
isStart =
true;
-
}
catch (IOException e) {
-
e.printStackTrace();
-
}
-
-
getSerialPort();
-
}
-
-
public void setSerialListen(SerialListen vSerialListen) {
-
mSerialListen = vSerialListen;
-
}
-
-
/**
-
* 关闭串口
-
* 关闭串口中的输入输出流
-
*/
-
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();
-
}
-
try {
-
mReceiveThread.start();
-
}
catch (Exception e) {
-
e.printStackTrace();
-
}
-
}
-
-
/**
-
* 接收串口数据的线程
-
*/
-
-
private
class ReceiveThread extends Thread {
-
@Override
-
public void run() {
-
super.run();
-
//条件判断,只要条件为true,则一直执行这个线程
-
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);
-
if (mSerialListen !=
null) {
-
mSerialListen.getSerial(readData, readString);
-
}
-
}
-
}
catch (IOException e) {
-
e.printStackTrace();
-
}
-
}
-
}
-
}
-
}
SerialListen
-
package com.seriallibrary.myserialport;
-
-
-
public
interface
SerialListen {
-
-
void getSerial(byte[] bytes,String string);
-
}
串口数据转换工具类 DataUtils
-
package com.seriallibrary.myserialport;
-
-
import java.util.ArrayList;
-
import java.util.
List;
-
-
/**
-
* 串口数据转换工具类
-
* Created by Administrator on 2016/6/2.
-
*/
-
public
class DataUtils {
-
//-------------------------------------------------------
-
// 判断奇数或偶数,位运算,最后一位是1则为奇数,为0是偶数
-
public
static
int isOdd(
int num) {
-
return num &
1;
-
}
-
-
//-------------------------------------------------------
-
//Hex字符串转int
-
public
static
int HexToInt(
String inHex) {
-
return
Integer.parseInt(inHex,
16);
-
}
-
-
public
static
String IntToHex(
int intHex){
-
return
Integer.toHexString(intHex);
-
}
-
-
//-------------------------------------------------------
-
//Hex字符串转byte
-
public
static byte HexToByte(
String inHex) {
-
return (byte)
Integer.parseInt(inHex,
16);
-
}
-
-
//-------------------------------------------------------
-
//1字节转2个Hex字符
-
public
static
String Byte2Hex(Byte inByte) {
-
return
String.format(
"%02x",
new
Object[]{inByte}).toUpperCase();
-
}
-
-
//-------------------------------------------------------
-
//字节数组转转hex字符串
-
public
static
String ByteArrToHex(byte[] inBytArr) {
-
StringBuilder strBuilder =
new StringBuilder();
-
for (byte valueOf : inBytArr) {
-
strBuilder.append(Byte2Hex(Byte.valueOf(valueOf)));
-
strBuilder.append(
" ");
-
}
-
return strBuilder.toString();
-
}
-
-
//-------------------------------------------------------
-
//字节数组转转hex字符串,可选长度
-
public
static
String ByteArrToHex(byte[] inBytArr,
int offset,
int byteCount) {
-
StringBuilder strBuilder =
new StringBuilder();
-
-
int j = byteCount;
-
for (
int i = offset; i < j; i++) {
-
strBuilder.append(Byte2Hex(Byte.valueOf(inBytArr[i])));
-
}
-
return strBuilder.toString();
-
}
-
-
//-------------------------------------------------------
-
//转hex字符串转字节数组
-
public
static byte[] HexToByteArr(
String inHex) {
-
byte[] result;
-
int hexlen = inHex.length();
-
if (isOdd(hexlen) ==
1) {
-
hexlen++;
-
result =
new byte[(hexlen /
2)];
-
inHex =
"0" + inHex;
-
}
else {
-
result =
new byte[(hexlen /
2)];
-
}
-
int j =
0;
-
for (
int i =
0; i < hexlen; i +=
2) {
-
result[j] = HexToByte(inHex.substring(i, i +
2));
-
j++;
-
}
-
return result;
-
}
-
-
/**
-
* 按照指定长度切割字符串
-
*
-
* @param inputString 需要切割的源字符串
-
* @param length 指定的长度
-
* @return
-
*/
-
public
static
List<
String> getDivLines(
String inputString,
int length) {
-
List<
String> divList =
new ArrayList<>();
-
int remainder = (inputString.length()) % length;
-
// 一共要分割成几段
-
int number = (
int) Math.floor((inputString.length()) / length);
-
for (
int index =
0; index < number; index++) {
-
String childStr = inputString.substring(index * length, (index +
1) * length);
-
divList.add(childStr);
-
}
-
if (remainder >
0) {
-
String cStr = inputString.substring(number * length, inputString.length());
-
divList.add(cStr);
-
}
-
return divList;
-
}
-
-
/**
-
* 计算长度,两个字节长度
-
*
-
* @param val value
-
* @return 结果
-
*/
-
public
static
String twoByte(
String val) {
-
if (val.length() >
4) {
-
val = val.substring(
0,
4);
-
}
else {
-
int l =
4 - val.length();
-
for (
int i =
0; i < l; i++) {
-
val =
"0" + val;
-
}
-
}
-
return val;
-
}
-
-
/**
-
* 校验和
-
*
-
* @param cmd 指令
-
* @return 结果
-
*/
-
public
static
String sum(
String cmd) {
-
List<
String> cmdList = DataUtils.getDivLines(cmd,
2);
-
int sumInt =
0;
-
for (
String c : cmdList) {
-
sumInt += DataUtils.HexToInt(c);
-
}
-
String sum = DataUtils.IntToHex(sumInt);
-
sum = DataUtils.twoByte(sum);
-
cmd += sum;
-
return cmd.toUpperCase();
-
}
-
-
}
主要的类就是这么几个,一个so加载类,一个串口操作工具类,一个数据解析工具类,一个回调接口,主要是用来封装串口的!
调用方式: 主要分为实例化工具类,打开串口,设置接口回调方法,在需要使用串口的时候发送数据,数据是String格式的,在SerialPortUtil里面会自动转化,只需要使用即可
整个代码我已经封装了一个aar包,可以导入直接使用,如果需要免费下载!
----------------------------------------------------------------------------------------------------
源代码Here:
- Github下载地址:!------> SerialPortの源代码
- CSDN下载地址:!------> SerialPortの源代码
----------------------------------------------------------------------------------------------------
转载:https://blog.csdn.net/qq_36333309/article/details/111310038