android串口开发记录

作者: 编程的猫 | 来源:发表于2019-07-03 18:22 被阅读0次

    本次的串口开发是基于Google的Serialport-api库实现的Android应用程序与硬件设备进行的串口通信(调用C层代码基于JNA)。
    所以首先需要去Github上下载google-Serailport-api的源码,下载地址:Google-Serailport-api
    下载下来以后,在自己的Android studio上创建一个Android工程,创建一个跟google源码相同包路径的一个包,如下图:

    image.png

    步骤如下:

    1.从google-serialport-api项目下拷贝SerialPort和SerialPortFinder两个类到android_serialport_api包下放置。

    2.如图创建jni和jniLibs文件夹。jni文件夹下放置从google项目中拷贝的源代码,如下图: image.png
    而jniLibs文件夹下放置如下图的文件,文件也来源于google项目,另外jna的libjnidispatch.so文件可以去github上搜索源项目获取对应cup架构下的.so文件:
    image.png

    3.下图文件时JNA所需


    image.png

    必备的环境就是以上这些,下面我贴出我自己的调用示例代码:

    封装了一个串口Api调用代理类

    public class GoogleSerialPortUtils {
    
        private InputStream inputStream;
        private OutputStream outputStream;
        private ReceiveThread mReceiveThread;
        private boolean isStart = false;
        private int baudRate = 115200;
        private Activity activity;
        private TextView textView;
    
        public GoogleSerialPortUtils() {
        }
    
        private static GoogleSerialPortUtils googleSerialPortUtils = null;
    
        public static GoogleSerialPortUtils instance() {
            if (googleSerialPortUtils == null) {
                synchronized (GoogleSerialPortUtils.class) {
                    if (googleSerialPortUtils == null) {
                        googleSerialPortUtils = new GoogleSerialPortUtils();
                    }
                }
            }
            return googleSerialPortUtils;
        }
    
        //打开,连接串口
        public void connectSerialPort(Activity activity, int baudRate, String serialPortPath,
                                      TextView textView) {
            this.activity = activity;
            this.baudRate = baudRate;
            this.textView = textView;
            String[] allDevicesPath = new SerialPortFinder().getAllDevicesPath();
            if (allDevicesPath != null && allDevicesPath.length > 0) {
                for (int i = 0; i < allDevicesPath.length; i++) {
                    Log.i(TGFingerAPI.TAG, "   串口的名字:" + allDevicesPath[i]);
                    if (serialPortPath.equals(allDevicesPath[i])) {
                        Log.i(TGFingerAPI.TAG, "  SerialPort长度 =====  :" + allDevicesPath.length
                                + "   名称:" + allDevicesPath[i]);
                        try {
                            SerialPort serialPort = new SerialPort(new File(allDevicesPath[i]), baudRate, 0);
                            //调用serialPort对象,获取读和写的数据流
                            inputStream = serialPort.getInputStream();
                            outputStream = serialPort.getOutputStream();
                            if (inputStream != null && outputStream != null) {
                                Log.i(TGFingerAPI.TAG, "  SerialPort  连接成功 =====   pathName:" + allDevicesPath[i]);
                                isStart = true;
                            }
                        } catch (IOException e) {
                            e.printStackTrace();
                        }
                        break;
                    }
                }
            }
        }
    
    
        /**
         * 关闭串口
         * 关闭串口中的输入输出流
         */
        public void closeSerialPort() {
            Log.i(TGFingerAPI.TAG, "关闭串口");
            try {
                if (inputStream != null) {
                    inputStream.close();
                }
                if (outputStream != null) {
                    outputStream.close();
                }
                isStart = false;
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    
        public void sendMsgSerailPort(String sendMsgs) {
            if (!TextUtils.isEmpty(sendMsgs)) {
                byte[] sendData = MyFunc.HexToByteArr("123456789"/*sendMsgs*/);
                try {
                    outputStream.write(sendData);
                    outputStream.flush();
                    Log.i(TGFingerAPI.TAG, "   发送数据");
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    
        public void getSerialPort() {
            if (mReceiveThread == null) {
                mReceiveThread = new ReceiveThread();
            }
            if (!mReceiveThread.isAlive()) {
                mReceiveThread.start();
            }
        }
    
        public void destroyTh() {
            if (mReceiveThread != null && mReceiveThread.isAlive()) {
                mReceiveThread.interrupt();
            }
        }
    
        /**
         * 接收串口数据的线程
         */
        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) {
                            final String readString = DataUtils.bytesToHex(readData/*, 0, size*/);
    //                        Log.i(TGFingerAPI.TAG, "   接收到的数据:" + readString
    //                                + "    线程的名称:" + Thread.currentThread().getName());
                            if (activity != null) {
                                activity.runOnUiThread(new Runnable() {
                                    @Override
                                    public void run() {
                                        textView.setText(readString);
                                    }
                                });
                            }
                        }
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }
        }
    }
    
    

    调用的位置

    private static final String SERIAL_PORT_PATH = "/dev/ttyS0"/*"/dev/ttysWK2"*/;//
        private static final int RATE = 115200;
    
        private void innitPermission() {
            //申请权限
            int i = ContextCompat.checkSelfPermission(this, p[0]);
            if (i != PackageManager.PERMISSION_GRANTED) {
                ActivityCompat.requestPermissions(this, p, 0x12);
            } else {
            //连接串口
                GoogleSerialPortUtils.instance().connectSerialPort(this, RATE,
                        SERIAL_PORT_PATH, receiveMsg);
            }
        }
    
    

    连接串口的时候,要找对你主机和硬件设备的波特率以及平板主机的TTL串口地址,如果不是TTL串口地址,会导致串口通信失败

    通过串口发送消息

        case R.id.sendMsg:
                    String sendMsgs = sendContent.getText().toString().trim();
                    GoogleSerialPortUtils.instance().sendMsgSerailPort(sendMsgs);
                    break;
    

    获取串口的消息

    //接收数据
                        GoogleSerialPortUtils.instance().getSerialPort();
    

    关闭串口

        @Override
        protected void onDestroy() {
            super.onDestroy();
            GoogleSerialPortUtils.instance().closeSerialPort();
            GoogleSerialPortUtils.instance().destroyTh();
    //        FireFlySerialPortUtils.instance().closeSerailPort();
        }
    

    注意:如果你在连接硬件时候,你硬件的通信库也是需要是用串口往上层发送消息,这个时候你就不能在上层代码中开启google的轮询获取串口消息的接口,否则会占用通信库层的串口通信。上图的糊掉的就是我自己的通信库,当然并不是每个项目都会用自己的通信库。具体项目具体调试

    另外贴上串口通信Android端的调试工具,PC端的串口调试工具可使用友善串口调试工具

    apk下载

    只要平板端与PC端的串口调试工具间能够相互收发消息,即串口已经接通。串口地址一定要找对,否则够你头大的!!祝好运!!!~

    相关文章

      网友评论

        本文标题:android串口开发记录

        本文链接:https://www.haomeiwen.com/subject/qtmchctx.html