Android进阶之路Android开发Android开发经验谈

android串口通信—— 自动轮寻可以通信的串口

2020-05-08  本文已影响0人  花椒粑粑_27a4

废话不多说,开撸代码。

用的是谷歌开源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

上一篇下一篇

猜你喜欢

热点阅读