下载地址: 串口开发环境
//串口
api(name: 'serialport-1.0.1', ext: 'aar')
/**
* 打开串口,接收,发送数据数据
* 通过串口,接收单片机发送来的数据
*/
public boolean openSerialPort(String port_name,int port_clound) {
try {
serialPort = new SerialPort(new File(port_name), port_clound, 0);
//调用对象SerialPort方法,获取串口中"读和写"的数据流
inputStream = serialPort.getInputStream();
outputStream = serialPort.getOutputStream();
isStart = true;
} catch (IOException e) {
e.printStackTrace();
}
getSerialPort();
return isStart;
}
上边的方法,首先看参数,port_name就是开发板上的对应的串口的名称,向继电器板发送命令就是通过该串口发送的,串口的名称一定要用开发板上的串口名称并且与串口所对应的位置一致,否则可能报错SecurityException。
port_clound是继电器的波特率,一定要和继电器的波特率对应好,不然可能会没有反应。
然后根据串口的名称和波特率创建SerialPort的实例,然后创建输入流(用来接收继电器返回的数据,一般时候也用不到,你只要看着灯亮了,关了就好了,还在乎继电器返回的数据干嘛~),输出流(用来向继电器发送串口命令),改变串口打开的状态isStart = true,同时调用了getSerialPort(),接下来看一下getSerialPort()里边的东西;
private void getSerialPort() {
mReceiveThread = new ReceiveThread();
mReceiveThread.start();
}
这里只是开启了一个ReceiveThread线程,看一下这个线程里边作了什么。
/**
* 接收串口数据的线程
*/
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);
if (!StringUtils.isEmpty(readString)) {
}
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
注释也说的很明白了,就是用来接收继电器返回的的数据用的,while (isStart) 说明只要你打开了串口,就开启一个死循环,在死循环里输入流一直在读取继电器返回来的数据。
/**
* 关闭串口
* 关闭串口中的输入输出流
*/
public void closeSerialPort() {
Log.i("test", "关闭串口");
try {
if (inputStream != null) {
inputStream.close();
}
if (outputStream != null) {
outputStream.close();
}
isStart = false;
} catch (IOException e) {
e.printStackTrace();
}
}
这里只是将输入流和输出进行关闭,并改变串口的打开状态:isStart = false; 终止ReceiveThread线程中的循环。
/**
* 发送数据
* 通过串口,发送数据到继电器
*
* @param data 要发送的数据
*/
public void sendSerialPort(String data) {
try {
byte[] sendData = DataUtils.HexToByteArr(data);
// byte[] sendData = data.getBytes();
outputStream.write(sendData);
outputStream.flush();
} catch (IOException e) {
e.printStackTrace();
}
}
其实也很简单就是通过DataUtils.HexToByteArr(data);将String类型的串口命令转换为字节数组,通过输出流将串口命令字节数组进行发送。
串口命令可以通过工具进行获取:串口命令获取工具
使用串口线将你的电脑和开发板进行连接,连接之后打开串口命令获取工具
刚打开的页面是这样的,输入开发板的串口名称,之后将对应的串口名称输入进去,点击打开串口按钮,之后会提示打开串口是否成功,对应的位置的两个线进行短路(短路之后你给串口发送什么串口命令,返回什么串口命令显示在左边的白色框内),然后点击Open按钮发送打开继电器的命令,如果你短路成功的话继电器命令会显示在左边白色框内,点击close按钮和点击Open按钮同理。
以上代码均出自:
/**
* Created by tehike
* Time : 2018/11/29.10:55
* data : 开关读写串口的工具类
*/
public class SerialPortUtil {
private SerialPort serialPort = null;
private InputStream inputStream = null;
private OutputStream outputStream = null;
private ReceiveThread mReceiveThread = null;
private boolean isStart = false;
private static SerialPortUtil portUtil;
//单例模式获取工具类的实例
public static SerialPortUtil getPortUtil() {
if (portUtil == null) {
portUtil = getInstance();
}
return portUtil;
}
/**
* 创建实例时加同步锁
*
* @return 返回当前实例
*/
private synchronized static SerialPortUtil getInstance() {
if (portUtil == null) {
portUtil = new SerialPortUtil();
}
return portUtil;
}
/**
* 打开串口,接收,发送数据数据
* 通过串口,接收单片机发送来的数据
*/
public boolean openSerialPort(String port_name,int port_clound) {
try {
serialPort = new SerialPort(new File(port_name), port_clound, 0);
// 调用对象SerialPort方法,获取串口中"读和写"的数据流
inputStream = serialPort.getInputStream();
outputStream = serialPort.getOutputStream();
isStart = true;
} catch (IOException e) {
e.printStackTrace();
}
getSerialPort();
return isStart;
}
/**
* 关闭串口
* 关闭串口中的输入输出流
*/
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);
// byte[] sendData = data.getBytes();
outputStream.write(sendData);
outputStream.flush();
} catch (IOException e) {
e.printStackTrace();
}
}
private void getSerialPort() {
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);
if (!StringUtils.isEmpty(readString)) {
}
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
最后附上DataUtils工具类的代码:
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 getDivLines(String inputString, int length) {
List 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 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();
}
}