废话不多说,开撸代码。
- 用的是谷歌开源serialPort api ,下载链接
- 下载后全部导入项目中,什么也不用修改
- 写一个工具类SerialPortUtils,设置好波特率
- 记录开始发送时间和最后一次接收时间,用超时时间来判断串口是否能正常收发数据
- 如何连续三次超时就自动更换串口号,知道接收到数据为止
下面是具体的类,仅供参考
[code]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 {@Overridepublic void run() {super.run();while (!threadStatus) {try {Thread.sleep(100);} catch (InterruptedException e) {e.printStackTrace();}final byte[] buffer = new byte[256];// do somethingtry {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代替
- 如有不对请指正。