android串口通信—— 自动轮寻可以通信的串口
废话不多说,开撸代码。
用的是谷歌开源serialPort api ,下载链接
下载后全部导入项目中,什么也不用修改
写一个工具类SerialPortUtils,设置好波特率
记录开始发送时间和最后一次接收时间,用超时时间来判断串口是否能正常收发数据
如何连续三次超时就自动更换串口号,知道接收到数据为止
下面是具体的类,仅供参考
public class SerialPortUtils {
private final String TAG = "SerialPortUtils";
private final int baudrate = 38400;//波特率
private boolean serialPortStatus = false; //是否打开串口标志
private boolean threadStatus = false; //线程状态,为了安全终止线程
private SerialPort serialPort = null;//串口
private InputStream inputStream = null;
private OutputStream outputStream = null;
private int size; //读取数据的大小
private Integer i = 0;
private int j = 0;
private long lastReceiveTime ;
private long lastSendTime;
private final long TIME_OUT = 10 * 1000;
private static SerialPortUtils INSTANCE;
private List<String> list=null;
private SerialPortUtils() {
// 记录创建对象时的时间
lastReceiveTime = System.currentTimeMillis();
lastSendTime = System.currentTimeMillis();
openSerialPort();
}
public static synchronized SerialPortUtils getInstance() {
if (INSTANCE == null) {
INSTANCE = new SerialPortUtils();
}
return INSTANCE;
}
/**
* 打开串口
*
* @return serialPort串口对象
*/
private void openSerialPort() {
// i=0;
try {
if (serialPort == null) {
serialPort = new SerialPort(new File(ApiAddress.path), baudrate, 0);
serialPortStatus = true;
threadStatus = false; //线程状态
//获取打开的串口中的输入输出流,以便于串口数据的收发
inputStream = serialPort.getInputStream();
outputStream = serialPort.getOutputStream();
//开始线程监控是否有数据要接收
new ReadThread().start();
Tray.putString(MyApp.myApp,"chuankou",ApiAddress.path);
}
} catch (IOException e) {
MainUtil.printLogger(TAG, "openSerialPort: 打开串口异常:" + e.toString());
}
}
/**
* 关闭串口
*/
public void closeSerialPort() {
try {
inputStream.close();
outputStream.close();
serialPortStatus = false;
threadStatus = true; //线程状态
serialPort.close();
serialPort = null;
} catch (IOException e) {
MainUtil.printLogger(TAG, "closeSerialPort: 关闭串口异常:" + e.toString());
}
MainUtil.printLogger(TAG, "closeSerialPort: 关闭串口成功");
}
/**
* 发送串口指令(字符串)
*
* @param sendData String数据指令
*/
public synchronized void sendSerialPort(byte[] sendData) {
try {
if (sendData.length > 0) {
if (null != outputStream) {
outputStream.write(sendData);
outputStream.flush();
MainUtil.printLogger(TAG, "串口发送" + ByteHEXUtils.bytesTo_HexString(sendData));
lastSendTime = System.currentTimeMillis();
}
long miss = lastSendTime - lastReceiveTime;
if (miss > TIME_OUT) {
//超时
i++;
if (i > 3) {
if (onChuankouListener != null) {
onChuankouListener.OnChuankouChange(2);
}
list=getDevices();
if(null!=list){
Tray.putString(MyApp.myApp,"chuankou",list.get(j));
serialPort = null;
openSerialPort();
j++;
}else {
if("/dev/ttyS1".equals(Tray.getString(MyApp.myApp, "chuankou", "/dev/ttyS2"))){
Tray.putString(MyApp.myApp,"chuankou","/dev/ttyS2");
serialPort = null;
openSerialPort();
}
if("/dev/ttyS2".equals(Tray.getString(MyApp.myApp, "chuankou", "/dev/ttyS2"))){
Tray.putString(MyApp.myApp,"chuankou","/dev/ttyS1");
serialPort = null;
openSerialPort();
}
}
}
}
}
} catch (IOException e) {
MainUtil.printLogger(TAG, "sendSerialPort: 串口数据发送失败:" + e.toString());
}
}
private final StringBuffer sb = new StringBuffer();
/**
* 单开一线程,来读数据
*/
private class ReadThread extends Thread {
@Override
public void run() {
super.run();
while (!threadStatus) {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
final byte[] buffer = new byte[256];
// do something
try {
size = inputStream.read(buffer);
String message = new String(ByteHEXUtils.bytesTo_HexString(buffer).getBytes(), 0, size * 2);
if (message.startsWith("FFFF") && message.endsWith("0D0A")) {
if (ByteHEXUtils.count(message, "FFFF") > 1) {
message = message.substring(message.lastIndexOf("FFFF"));
}
if (message.substring(message.length() - 6, message.length() - 4).equals(ByteHEXUtils.makeChecksum(message.substring(0, message.length() - 6))) && onDataReceiveListener != null) {
if (onChuankouListener != null) {
i = 0;
onChuankouListener.OnChuankouChange(1);
lastReceiveTime = System.currentTimeMillis();
}
MainUtil.printLogger(TAG, "串口回调" + message);
onDataReceiveListener.onDataReceive(message, size);
}
sb.setLength(0);
} else {
sb.append(message);
if (ByteHEXUtils.count(sb.toString(), "FFFF") > 1) {
String str = sb.toString();
sb.setLength(0);
sb.append(str.substring(str.lastIndexOf("FFFF")));
}
if (sb.toString().startsWith("FFFF") && sb.toString().endsWith("0D0A")) {
if (sb.substring(sb.length() - 6, sb.length() - 4).equals(ByteHEXUtils.makeChecksum(sb.substring(0, sb.length() - 6))) && onDataReceiveListener != null) {
lastReceiveTime = System.currentTimeMillis();
if (onChuankouListener != null) {
i = 0;
onChuankouListener.OnChuankouChange(1);
}
MainUtil.printLogger(TAG, "串口回调" + sb.toString());
onDataReceiveListener.onDataReceive(sb.toString(), size);
}
sb.setLength(0);
}
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
private OnDataReceiveListener onDataReceiveListener = null;
private OnChuankouChangeListener onChuankouListener = null;
public interface OnDataReceiveListener {
void onDataReceive(String buffer, int size);
}
public void setOnDataReceiveListener(OnDataReceiveListener dataReceiveListener) {
onDataReceiveListener = dataReceiveListener;
}
// 自定义接口
public interface OnChuankouChangeListener {
void OnChuankouChange(int status);
}
public void setOnChuankouListener(OnChuankouChangeListener chuankouListener) {
onChuankouListener = chuankouListener;
}
public List<String>getDevices() {
if (null == list) {
list = new ArrayList<>();
File dev = new File("/dev");
File[] files = dev.listFiles();
int i;
for (i = 0; i < files.length; i++) {
if (files[i].getAbsolutePath().startsWith("/dev/ttyS")) {
MainUtil.printLogger(TAG, "Found new device: " + files[i]);
list.add(files[i].toString());
}
}
}
return list;
}
}
本工具类中有自动替换串口,知道可以通信为止的方法
由于android端接收串口数据并不是一次性就可以全部接收到,有可能分两段,也有可能丢失,所有在接收消息的时候,我做了拼接校验,比如和板子开发人员确定好头部和尾部以及校验位,本工具类中头部是FFFF开头0D0A结尾的,对不符合的数据进行了舍弃,并及时清空缓冲区
本工具类中Tray类似于共享参数,保存了串口路径,可以用SharedPreferences或者file代替
如有不对请指正。
我的csdn地址: https://blog.csdn.net/u011847849/article/details/105999406