精华内容
下载资源
问答
  • android 串口开发(二) 之 串口读写操作】
    2020-05-10 10:21:00

    串口的读写操作

    看这篇文章前,建议先看看这篇文章: 【android 串口开发(一) 之生成so文件】

    既然,我们的so已经生成了,那么接下来就是串口的读写操作啦。

    下面贴出关键类的代码:

    **
     * 串口操作类
     */
    public class SerialPortUtil {
        private String TAG = SerialPortUtil.class.getSimpleName();
        private SerialPort mSerialPort;
        private OutputStream mOutputStream;
        private InputStream mInputStream;
        private ReadThread mReadThread;
        private String path = "/dev/ttyS4"; //这个是我们要读取的串口路径,这个硬件开发人员会告诉我们的
        private int baudrate = 9600;//这个参数,硬件开发人员也会告诉我们的
        private static SerialPortUtil portUtil;
        private OnDataReceiveListener onDataReceiveListener = null;
        private boolean isStop = false;
    
        public interface OnDataReceiveListener {
            public void onDataReceive(byte[] buffer, int size);
        }
    
        public void setOnDataReceiveListener(OnDataReceiveListener dataReceiveListener) {
            onDataReceiveListener = dataReceiveListener;
        }
    
        public static SerialPortUtil getInstance() {
            if (null == portUtil) {
                portUtil = new SerialPortUtil();
                portUtil.onCreate();
            }
            return portUtil;
        }
    
        /**
         * 初始化串口信息
         */
        public void onCreate() {
            try {
                mSerialPort = new SerialPort(new File(path), baudrate, 0);
                mOutputStream = mSerialPort.getOutputStream();
                mInputStream = mSerialPort.getInputStream();
    
                mReadThread = new ReadThread();
                isStop = false;
                mReadThread.start();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    
        /**
         * 发送指令到串口
         *
         * @param cmd
         * @return
         */
        public boolean sendCmds(String cmd) {
            boolean result = true;
            String str = cmd;
            str = str.replace(" ", "");
            byte[] mBuffer = SerialDataUtils.HexToByteArr(str);
            if (!isStop) {
                try {
                    if (mOutputStream != null) {
                        mOutputStream.write(mBuffer);
                    } else {
                        result = false;
                    }
                } catch (IOException e) {
                    e.printStackTrace();
                    result = false;
                }
            } else {
                System.out.println("sendCmds serialPort isClose");
                result = false;
            }
    
            return result;
        }
    
    
        private class ReadThread extends Thread {
    
            @Override
            public void run() {
                super.run();
                System.out.println("ReadThread.run isInterrupted()=" + isInterrupted());
                while (!isStop && !isInterrupted()) {
                    System.out.println("ReadThread.run mInputStream=" + mInputStream);
                    int size;
                    try {
                        if (mInputStream == null){
                            System.out.println("ReadThread.run return");
                            return;
                        }
    
                        byte[] buffer = new byte[512];
                        System.out.println("ReadThread.run buffer");
                        size = mInputStream.read(buffer);//该方法读不到数据时,会阻塞在这里
                        System.out.println("ReadThread.run size=" + size);
                        if (size > 0) {
                           /* if(MyLog.isDyeLevel()){
                                MyLog.log(TAG, MyLog.DYE_LOG_LEVEL, "length is:"+size+",data is:"+new String(buffer, 0, size));
                            }*/
                            byte[] buffer2 = new byte[size];
                            for (int i = 0; i < size; i++) {
                                buffer2[i] = buffer[i];
                            }
                            if (onDataReceiveListener != null) {
                                onDataReceiveListener.onDataReceive(buffer2, size);
                            }
                        }
                        Thread.sleep(50);//延时 50 毫秒
                    } catch (Exception e) {
                        e.printStackTrace();
                        System.out.println("ReadThread.run  e.printStackTrace() " + e);
                        return;
                    }
                }
            }
        }
    
        /**
         * 关闭串口
         */
        public void closeSerialPort() {
            isStop = true;
            if (mReadThread != null) {
                mReadThread.interrupt();
            }
            if (mSerialPort != null) {
                mSerialPort.close();
            }
        }
    
    
    
    
    }
    

    把这个进制转换的工具类也贴出一下:

    package com.everyoo.serialportdaemon2;
    
    /**
     * 串口数据转换工具类
     * Created by Administrator on 2016/6/2.
     */
    public class SerialDataUtils {
        //-------------------------------------------------------
        // 判断奇数或偶数,位运算,最后一位是1则为奇数,为0是偶数
        public static int isOdd(int num) {
            return num & 1;
        }
    
        //-------------------------------------------------------
        //Hex字符串转int
        public static int HexToInt(String inHex) {
            return Integer.parseInt(inHex, 16);
        }
    
        //-------------------------------------------------------
        //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;
        }
    }
    
    

    最后你在你的MainActivity中,直接调用 serialPort.sendCmds(“7e01010d”) 方法即可,需要注意一点的就是:像7e01010d 是十六进制的字符:

        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
            ButterKnife.inject(this);
            initEvent();
            SerialPortUtil  serialPort = SerialPortUtil.getInstance();
            
            //该方法是读取数据的回调监听,一旦读取到数据,就立马回调
            serialPort.setOnDataReceiveListener(new SerialPortUtil.OnDataReceiveListener() {
                @Override
                public void onDataReceive(byte[] buffer, int size) {
                    receiveString = SerialDataUtils.ByteArrToHex(buffer).trim();
                    System.out.println("MainActivity2.onDataReceive receiveString= " + receiveString);
                    runOnUiThread(new Runnable() {
                        @Override
                        public void run() {
                            result.append(receiveString + "\r\n");
                        }
                    });
    
                }
            });
    
    
        }
    

    CMake相关参考文章:
    Android开发:JNI开发过程以及两种生成.so文件的方法
    Android Studio中CMakeList的写法
    Android-串口(通过jni技术生成自己的so)

    google官方地址: https://github.com/cepr/android-serialport-api

    android串口通信以及串口协议解析

    android 串口编程

    Android串口通信:串口读写实例

    【Android应用开发】-(19)Android 串口编程原理和实现方式(附源码)

    更多相关内容
  • 如果未配置ndk配置的朋友,或者对jni不熟悉的朋友,请查看上一篇文章,android 串口开发第一篇:搭建ndk开发环境以及第一个jni调用程序 ,串口通信和java操作io类似,先打开串口,然后向串口发送或者读取数据,最后关闭...
  • Android 串口开发demo

    2020-06-11 20:26:47
    这个demo实现了Android串口开发,实现Android发送串口命令到硬件,使硬件执行相应是命令操作
  • Android串口开发框架

    2018-04-10 17:34:32
    Android串口开发框架 Android串口开发框架 Android串口开发框架
  • 这里主要是参考了开源项目android-serialport-api。串口编程需要了解的基本知识点:对于串口编程,我们只需对串口进行一系列的设置,然后打开串口,这些操作我们可以参考串口调试助手的源码进行学习。在Java中如果要...
  • 三星安卓平台摄像头串口文件,使用Java开发,可实现对安卓开发板的底层控制
  • Android 串口通信 ,demo 支持数据位 停止位设定和 奇偶 校验,
  • Android串口开发配置文件
  • Android串口开发

    千次阅读 2019-01-07 13:07:27
    1.开发工具:Android Studio 2.所用资源: 3.

    1.开发工具:Android Studio
    2.所用资源:谷歌开源 serialPort api (下载地址:https://download.csdn.net/download/qq_30297763/10900944

    开发:

    1. 将文件copy到相应位置:(注意:因为用的谷歌原生so库,所以SerialPort类的包名一定要是android_serialport_api,如果想修改这个包名,就需要重新生成对应的so库

     SerialPort类是咱们Android可以调用的类, jni目录下放着c源码和h头文件, jniLibs下面放的就是so库。

    2.在buil.gradle添加以下代码

      buildTypes {
            sourceSets {
                main {
                    jni.srcDirs = []
                }
            }
        }
    

    3.串口操作类:

    import android.util.Log;
    import java.io.File;
    import java.io.IOException;
    import java.io.InputStream;
    import java.io.OutputStream;
    import android_serialport_api.SerialPort;
    
    public class SerialPortUtils {
        private final String TAG = "SerialPortUtils";
        private String path = "/dev/ttyS4";  // 可根据设备不同修改
        private int baudrate = 9600; //波率
        public boolean serialPortStatus = false; //是否打开串口标志
        public boolean threadStatus; //线程状态,为了安全终止线程
    
        public SerialPort serialPort = null;
        public InputStream inputStream = null;
        public OutputStream outputStream = null;
    
    
        /**
         * 打开串口
         *
         * @return serialPort串口对象
         */
        public SerialPort openSerialPort() {
            try {
                serialPort = new SerialPort(new File(path), baudrate, 0);
                this.serialPortStatus = true;
                threadStatus = false; //线程状态
    
                //获取打开的串口中的输入输出流,以便于串口数据的收发
                inputStream = serialPort.getInputStream();
                outputStream = serialPort.getOutputStream();
    
                new ReadThread().start(); //开始线程监控是否有数据要接收
            } catch (IOException e) {
                Log.e(TAG, "openSerialPort: 打开串口异常:" + e.toString());
                return serialPort;
            }
            Log.d(TAG, "openSerialPort: 打开串口");
            return serialPort;
        }
    
        /**
         * 关闭串口
         */
        public void closeSerialPort() {
            try {
                inputStream.close();
                outputStream.close();
    
                this.serialPortStatus = false;
                this.threadStatus = true; //线程状态
                serialPort.close();
            } catch (IOException e) {
                Log.e(TAG, "closeSerialPort: 关闭串口异常:" + e.toString());
                return;
            }
            Log.d(TAG, "closeSerialPort: 关闭串口成功");
        }
    
        /**
         * 发送串口指令(字符串)
         * @param data String数据指令
         */
        public void sendSerialPort(String data) {
            if (!data.isEmpty()){
                Log.d(TAG, "sendSerialPort: 发送数据");
                data = data.toUpperCase();
                int len = data.length()/2;
                byte[] sendData = new byte[len];
                char[] hc = data.toCharArray();
                for (int i=0; i<len; i++){
                    int p=2*i;
                    sendData[i] = (byte) (charToByte(hc[p]) << 4 | charToByte(hc[p+1]));
                }
    
                try {
                    outputStream.write(sendData);
                    //outputStream.write('\n');  
                    //outputStream.write('\r'+'\n');
                    outputStream.flush();
                    Log.d(TAG, "sendSerialPort: 串口数据发送成功 "+data+"  sendData:"+ sendData.toString()  );
                } catch (IOException e) {
                    Log.e(TAG, "sendSerialPort: 串口数据发送失败:" + e.toString());
                }
    
            }else {
                return;
            }
        }
    
        /**
         * 单开一线程,来读数据
         */
        private class ReadThread extends Thread {
            @Override
            public void run() {
                super.run();
                //判断进程是否在运行,更安全的结束进程
                while (!threadStatus) {
                    Log.d(TAG, "进入线程run");
                    //64   1024
                    byte[] buffer = new byte[64];
                    int size; //读取数据的大小
                    try {
                        size = inputStream.read(buffer);
                        if (size > 0) {
                            Log.d(TAG, "run: 接收到了数据大小:" + String.valueOf(size));
                            onDataReceiveListener.onDataReceive(buffer, size);
                        }
                    } catch (IOException e) {
                        Log.e(TAG, "run: 数据读取异常:" + e.toString());
                    }
                }
            }
        }
    
        //监听接收数据
        public OnDataReceiveListener onDataReceiveListener = null;
    
        public static interface OnDataReceiveListener {
            public void onDataReceive(byte[] buffer, int size);
        }
    
        public void setOnDataReceiveListener(OnDataReceiveListener dataReceiveListener) {
            onDataReceiveListener = dataReceiveListener;
        }
    
        /**
         * 字符转换为字节
         */
        private static byte charToByte(char c) {
            return (byte) "0123456789ABCDEF".indexOf(c);
        }
    }
    
    

    简单运用:

    import android.os.Bundle;
    import android.support.v7.app.AppCompatActivity;
    import android.util.Log;
    
    public class MainActivity extends AppCompatActivity {
    
        private SerialPortUtils serialPortUtils;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
    
            serialPortUtils = new SerialPortUtils();
            serialPortUtils.openSerialPort();  //打开串口
            serialPortUtils.sendSerialPort("01010101");//发送指令
    
            //串口数据监听事件
            serialPortUtils.setOnDataReceiveListener(new SerialPortUtils.OnDataReceiveListener() {
                @Override
                public void onDataReceive(byte[] buffer, int size) {
                    Log.d("SerialPort", "监听到的数据: " + new String(buffer));
                }
            });
    
            serialPortUtils.closeSerialPort();//关闭串口
        }
    
    }
    
    

    简单demo: ( https://download.csdn.net/download/qq_30297763/10901105

    展开全文
  • android 串口开发

    2018-07-21 11:49:39
    Android系统自然也能进行物联网开发。除开Android本身自带的模块还有一类通过外部链接的设备需要通过串口来进行通信。 关于串口 串口通信指串口按位(bit)发送和接收字节。尽管比按字节(byte)的并行通信慢,...

    前言

    物联网开发开发是时下热门的行业。Android系统自然也能进行物联网开发。除开Android本身自带的模块还有一类通过外部链接的设备需要通过串口来进行通信。

    关于串口

    串口通信指串口按位(bit)发送和接收字节。尽管比按字节(byte)的并行通信慢,但是串口可以在使用一根线发送数据的同时用另一根线接收数据。

    在串口通信中,常用的协议包括RS-232、RS-422和RS-485。

    当然具体是那种协议和你选择的硬件有关,将你的硬件插到对应协议的串口口即可。

     

    开发前的准备

    1.检查你的开发板设备,包括开发板信息,开发板上面包含的模块信息。是否有Wifi模块 蓝牙模块 指定接口等。还有一方面就是关于开发板系统的信息,开发板的系统版本。如果需要特别定制,可以和厂商商量。

    关于系统定制
    某些特殊的板块需要隐藏状态栏不能被下拉,否则会被退出应用。还有一方面就是可以定制取消掉下导航栏。

    2.检查你的硬件装备
    正确连接你的设备,向你的硬件提供商索要开发资料。基本的资料包括硬件的通讯命令格式。当然更好的是如果能要到开发程序资料。比如android程序或者源码那就更好了。

    3.正确的连接,测试你的硬件与系统
    Android串口助手
    下载一个串口调试助手,按照资料输入命令。测试是否能够成功的启动设备。并且收到对应的返回数据。

     开发阶段

    需要一点点的JNI知识和一点点Android多线程开发经验

    整体的开发流程如下:打开指定串口-->开启接收数据线程(readthead)-->发送串口数据-->接收数据处理返回信息-->关闭接收数据线程(readthead)-->关闭串口。

    导入so库

    谷歌开源serialPort api项目

    里面封装了c层代码调用底层代码的通信方式,如果你们喜欢改东西的话。可以自己改着玩,不过我觉得没有必要,因为这些代码已经封装的很好了。直接使用即可。

    至于通过c代码如何生成相应的so文件,以及如何java层调用c层代码都是很基础的东西啦。
    我不想在这里展开大篇幅的讲JNI,因为串口通信其实用的JNI知识不多。

    首先把JNI相关代码导入到自己的工程里面:

    先看下目录结构吧:

    jni目录:

     java 目录:

    SerialPort.java

    了解JNI的同学都知道的,这个SerialPort.h对应的就是SerialPort.java层的native 方法。

    这里用两个方法

    private native static FileDescriptor open(String path, int baudrate, int flags);
    public native void close();
    

    很显然一个是打开串口 一个是 关闭串口 方法

    打开串口之前,程序需要获得最高权限,SerialPort.java的构造函数里面需要获得设备的超级root权限,也是通过输入su命令完成。

    if (!device.canRead() || !device.canWrite()) { try { /* Missing read/write permission, trying to chmod the file */ Process su; su = Runtime.getRuntime().exec("/system/bin/su"); String cmd = "chmod 666 " + device.getAbsolutePath() + "\n" + "exit\n"; su.getOutputStream().write(cmd.getBytes()); if ((su.waitFor() != 0) || !device.canRead() || !device.canWrite()) { throw new SecurityException(); } } catch (Exception e) { e.printStackTrace(); throw new SecurityException(); } }

    最后记得调用生成的.so文件

    static {
            System.loadLibrary("serial_port");
        }
    

    SerialPortFinder

    这个类很简单,能用于获取设备的串口信息。通常一个开发板会有几个到十几个的串口。
    两个public方法:

    • public String[] getAllDevices() 获取所有串口名称
    • public String[] getAllDevicesPath() 获取所有串口地址

    开始通信

     

    这个类很简单,能用于获取设备的串口信息。通常一个开发板会有几个到十几个的串口。
    两个public方法:

    • public String[] getAllDevices() 获取所有串口名称
    • public String[] getAllDevicesPath() 获取所有串口地址

    开始通信

    这个类很简单,能用于获取设备的串口信息。通常一个开发板会有几个到十几个的串口。
    两个public方法:

    • public String[] getAllDevices() 获取所有串口名称
    • public String[] getAllDevicesPath() 获取所有串口地址

    开始通信

     

    整个信息发送接收步骤如下:

    1.初始化SerialPort 获得权限打开指定串口
    2.打开ReadThread监听数据返回
    3.使用SendThread发送数据
    4.继续发送或者关闭

    为此我们需要写一个SerialHelper来简化代码,以下是核心代码:

    构造函数

     

    public SerialHelper(String sPort, int iBaudRate) { this.sPort = "/dev/ttyS3"; this.iBaudRate = 9600; this._isOpen = false; this._bLoopData = new byte[]{48}; this.iDelay = 500; this.sPort = sPort; this.iBaudRate = iBaudRate; }


     打开 关闭 串口

    //打开时打开监听线程 public void open() throws SecurityException, IOException, InvalidParameterException { this.mSerialPort = new SerialPort(new File(this.sPort), this.iBaudRate, 0); this.mOutputStream = this.mSerialPort.getOutputStream(); this.mInputStream = this.mSerialPort.getInputStream(); this.mReadThread = new SerialHelper.ReadThread(); this.mReadThread.start(); this.mSendThread = new SerialHelper.SendThread(); this.mSendThread.setSuspendFlag(); this.mSendThread.start(); this._isOpen = true; } // 关闭线程 释放函数 public void close() { if (this.mReadThread != null) { this.mReadThread.interrupt(); } if (this.mSerialPort != null) { this.mSerialPort.close(); this.mSerialPort = null; } this._isOpen = false; }

    两个线程 发送线程:
     

    private class SendThread extends Thread { public boolean suspendFlag; private SendThread() { this.suspendFlag = true; } public void run() { super.run(); while(!this.isInterrupted()) { synchronized(this) { while(this.suspendFlag) { try { this.wait(); } catch (InterruptedException var5) { var5.printStackTrace(); } } } SerialHelper.this.send(SerialHelper.this.getbLoopData()); try { Thread.sleep((long)SerialHelper.this.iDelay); } catch (InterruptedException var4) { var4.printStackTrace(); } } } public void setSuspendFlag() { this.suspendFlag = true; } public synchronized void setResume() { this.suspendFlag = false; this.notify(); } }

    读取线程

    private class ReadThread extends Thread { private ReadThread() { } public void run() { super.run(); while(!this.isInterrupted()) { try { if (SerialHelper.this.mInputStream == null) { return; } byte[] buffer = new byte[512]; int size = SerialHelper.this.mInputStream.read(buffer); if (size > 0) { ComBean ComRecData = new ComBean(SerialHelper.this.sPort, buffer, size); SerialHelper.this.onDataReceived(ComRecData); } } catch (Throwable var4) { Log.e("error", var4.getMessage()); return; } } } }


     其他函数见代码,包括数值和文本发送 波特率的设置等等。

    虽然整个JNI移植过程非常简单,但是问题出现了。如果大家使用的3.0版本的AS、会发现默认的JNI使用Cmake而不是.mk文件配置的。

    所以又增加了一个难度,为了方便大家。我把所有关于串口的资源打包成aar 文件,大家直接使用即可。

    谷歌android串口开发 aar文件

    使用过程:
    aar文件导入lib文件夹
    gradle文件

     

    repositories { flatDir { dirs 'libs' } } dependencies { implementation(name: 'serialport-1.0.1', ext: 'aar') }

     

    资料参考:https://www.jianshu.com/p/d79f4ccbbf44

     

     


     

    展开全文
  • 谷歌android串口开发 使用nexus 生成的 aar文件,直接导入项目即可使用 1.0为谷歌源文件打包生成 1.0.1 是个人稍作修改的版本
  • SerialPort Android串口开发.so文件和java调用.so类
  • Android系统自然也能进行物联网开发。除开Android本身自带的模块还有一类通过外部链接的设备需要通过串口来进行通信。本人在做完两个相关的抓娃娃和寄存柜项目之后觉得需要总结一点东西给大家。一些预备知识关于串口...

    前言

    物联网开发开发是时下热门的行业。Android系统自然也能进行物联网开发。除开Android本身自带的模块还有一类通过外部链接的设备需要通过串口来进行通信。本人在做完两个相关的抓娃娃和寄存柜项目之后觉得需要总结一点东西给大家。

    一些预备知识

    关于串口

    串口通信指串口按位(bit)发送和接收字节。尽管比按字节(byte)的并行通信慢,但是串口可以在使用一根线发送数据的同时用另一根线接收数据。

    在串口通信中,常用的协议包括RS-232、RS-422和RS-485。

    当然具体是那种协议和你选择的硬件有关,将你的硬件插到对应协议的串口口即可。

    开发前的准备

    检查你的开发板设备,包括开发板信息,开发板上面包含的模块信息。是否有Wifi模块 蓝牙模块 指定接口等。还有一方面就是关于开发板系统的信息,开发板的系统版本。如果需要特别定制,可以和厂商商量。关于系统定制

    某些特殊的板块需要隐藏状态栏不能被下拉,否则会被退出应用。还有一方面就是可以定制取消掉下导航栏。

    检查你的硬件装备。正确连接你的设备,向你的硬件提供商索要开发资料。基本的资料包括硬件的通讯命令格式。当然更好的是如果能要到开发程序资料。比如android程序或者源码那就更好了。

    正确的连接,测试你的硬件与系统。Android串口助手下载地址:http://zhushou.360.cn/detail/index/soft_id/162355?recrefer=SE_D_%E4%B8%B2%E5%8F%A3%E5%8A%A9%E6%89%8B

    下载一个串口调试助手,按照资料输入命令。测试是否能够成功的启动设备。并且收到对应的返回数据。

    开发阶段

    需要一点点的JNI知识和一点点Android多线程开发经验

    整体的开发流程如下:打开指定串口-->开启接收数据线程(readthead)-->发送串口数据-->接收数据处理返回信息-->关闭接收数据线程(readthead)-->关闭串口。

    导入so库

    谷歌开源serialPort api项目https://github.com/cepr/android-serialport-api

    里面封装了c层代码调用底层代码的通信方式,如果你们喜欢改东西的话。可以自己改着玩,不过我觉得没有必要,因为这些代码已经封装的很好了。直接使用即可。

    至于通过c代码如何生成相应的so文件,以及如何java层调用c层代码都是很基础的东西啦。我不想在这里展开大篇幅的讲JNI,因为串口通信其实用的JNI知识不多。

    首先把JNI相关代码导入到自己的工程里面,先看下目录结构吧:

    jni目录

    java 目录

    SerialPort.java

    了解JNI的同学都知道的,这个SerialPort.h对应的就是SerialPort.java层的native 方法。这里用两个方法private native static FileDescriptor open(String path, int baudrate, int flags);

    public native void close();

    很显然一个是打开串口 一个是 关闭串口 方法。打开串口之前,程序需要获得最高权限,SerialPort.java的构造函数里面需要获得设备的超级root权限,也是通过输入su命令完成。if (!device.canRead() || !device.canWrite()) {

    try {

    /* Missing read/write permission, trying to chmod the file */

    Process su;

    su = Runtime.getRuntime().exec("/system/bin/su");

    String cmd = "chmod 666 " + device.getAbsolutePath() + "\n"

    + "exit\n";

    su.getOutputStream().write(cmd.getBytes());

    if ((su.waitFor() != 0) || !device.canRead()

    || !device.canWrite()) {

    throw new SecurityException();

    }

    } catch (Exception e) {

    e.printStackTrace();

    throw new SecurityException();

    }

    }

    最后记得调用生成的.so文件static {

    System.loadLibrary("serial_port");

    }

    SerialPortFinder

    这个类很简单,能用于获取设备的串口信息。通常一个开发板会有几个到十几个的串口。

    两个public方法:public String[] getAllDevices() 获取所有串口名称

    public String[] getAllDevicesPath() 获取所有串口地址

    开始通信

    整个信息发送接收步骤如下:初始化SerialPort 获得权限打开指定串口

    打开ReadThread监听数据返回

    使用SendThread发送数据

    继续发送或者关闭

    为此我们需要写一个SerialHelper来简化代码,以下是核心代码:

    构造函数public SerialHelper(String sPort, int iBaudRate) {

    this.sPort = "/dev/ttyS3";

    this.iBaudRate = 9600;

    this._isOpen = false;

    this._bLoopData = new byte[]{48};

    this.iDelay = 500;

    this.sPort = sPort;

    this.iBaudRate = iBaudRate;

    }

    打开 关闭 串口//打开时打开监听线程

    public void open() throws SecurityException, IOException, InvalidParameterException {

    this.mSerialPort = new SerialPort(new File(this.sPort), this.iBaudRate, 0);

    this.mOutputStream = this.mSerialPort.getOutputStream();

    this.mInputStream = this.mSerialPort.getInputStream();

    this.mReadThread = new SerialHelper.ReadThread();

    this.mReadThread.start();

    this.mSendThread = new SerialHelper.SendThread();

    this.mSendThread.setSuspendFlag();

    this.mSendThread.start();

    this._isOpen = true;

    }

    // 关闭线程 释放函数

    public void close() {

    if (this.mReadThread != null) {

    this.mReadThread.interrupt();

    }

    if (this.mSerialPort != null) {

    this.mSerialPort.close();

    this.mSerialPort = null;

    }

    this._isOpen = false;

    }

    两个线程 发送线程private class SendThread extends Thread {

    public boolean suspendFlag;

    private SendThread() {

    this.suspendFlag = true;

    }

    public void run() {

    super.run();

    while(!this.isInterrupted()) {

    synchronized(this) {

    while(this.suspendFlag) {

    try {

    this.wait();

    } catch (InterruptedException var5) {

    var5.printStackTrace();

    }

    }

    }

    SerialHelper.this.send(SerialHelper.this.getbLoopData());

    try {

    Thread.sleep((long)SerialHelper.this.iDelay);

    } catch (InterruptedException var4) {

    var4.printStackTrace();

    }

    }

    }

    public void setSuspendFlag() {

    this.suspendFlag = true;

    }

    public synchronized void setResume() {

    this.suspendFlag = false;

    this.notify();

    }

    }

    读取线程private class ReadThread extends Thread {

    private ReadThread() {

    }

    public void run() {

    super.run();

    while(!this.isInterrupted()) {

    try {

    if (SerialHelper.this.mInputStream == null) {

    return;

    }

    byte[] buffer = new byte[512];

    int size = SerialHelper.this.mInputStream.read(buffer);

    if (size > 0) {

    ComBean ComRecData = new ComBean(SerialHelper.this.sPort, buffer, size);

    SerialHelper.this.onDataReceived(ComRecData);

    }

    } catch (Throwable var4) {

    Log.e("error", var4.getMessage());

    return;

    }

    }

    }

    }

    其他函数见代码,包括数值和文本发送 波特率的设置等等。

    实战一个串口数据调试助手

    下面使用封装的SerialHelper来完成整个数据发送接收。界面随便搞一下:

    然后开始逻辑代码。首先实例化SerialPortFinder 实现数据接收写入列表serialPortFinder = new SerialPortFinder();

    serialHelper = new SerialHelper() {

    @Override

    protected void onDataReceived(final ComBean comBean) {

    runOnUiThread(new Runnable() {

    @Override

    public void run() {

    Toast.makeText(getBaseContext(), FuncUtil.ByteArrToHex(comBean.bRec), Toast.LENGTH_SHORT).show();

    logListAdapter.addData(comBean.sRecTime+":   "+FuncUtil.ByteArrToHex(comBean.bRec));

    recy.smoothScrollToPosition(logListAdapter.getData().size());

    }

    });

    }

    };

    然后利用SerialPortFinder找到所有的串口号,列出来所有的波特率 ,都传给spinnerfinal String[] ports = serialPortFinder.getAllDevicesPath();

    final String[] botes = new String[]{"0", "50", "75", "110", "134", "150", "200", "300", "600", "1200", "1800", "2400", "4800", "9600", "19200", "38400", "57600", "115200", "230400", "460800", "500000", "576000", "921600", "1000000", "1152000", "1500000", "2000000", "2500000", "3000000", "3500000", "4000000"};

    SpAdapter spAdapter = new SpAdapter(this);

    spAdapter.setDatas(ports);

    spSerial.setAdapter(spAdapter);

    SpAdapter spAdapter2 = new SpAdapter(this);

    spAdapter2.setDatas(botes);

    spBote.setAdapter(spAdapter2)

    打开串口btOpen.setOnClickListener(new View.OnClickListener() {

    @Override

    public void onClick(View v) {

    try {

    serialHelper.open();

    btOpen.setEnabled(false);

    } catch (IOException e) {

    e.printStackTrace();

    }

    }

    });

    数据发送(两种数据发送格式):文本类型if (serialHelper.isOpen()) {

    serialHelper.sendTxt(edInput.getText().toString());

    } else {

    Toast.makeText(getBaseContext(), "搞毛啊,串口都没打开", Toast.LENGTH_SHORT).show();

    }Hex类型if (serialHelper.isOpen()) {

    serialHelper.sendHex(edInput.getText().toString());

    } else {

    Toast.makeText(getBaseContext(), "搞毛啊,串口都没打开", Toast.LENGTH_SHORT).show();

    }

    最后记得关闭一下串口咯@Override

    protected void onDestroy() {

    super.onDestroy();

    serialHelper.close();

    }

    好的 ,完事了。 测试一下。连线开机:

    发串口信息

    同时设备也滴塌滴塌的响了,完美。

    一些要说的

    虽然整个JNI移植过程非常简单,但是问题出现了。如果大家使用的3.0版本的AS、会发现默认的JNI使用Cmake而不是.mk文件配置的。

    所以又增加了一个难度,为了方便大家。我把所有关于串口的资源打包成aar 文件,大家直接使用即可。

    谷歌android串口开发 aar文件,地址如下所示:https://download.csdn.net/download/lw_zhaoritian/9961190

    使用过程

    aar文件导入lib文件夹。

    gradle文件repositories {

    flatDir {

    dirs 'libs'

    }

    }

    dependencies {

    implementation(name: 'serialport-1.0.1', ext: 'aar')

    }

    完成。

    总结

    基本的串口通信到此结束。到了实际生产,更多的要解决多线程上的逻辑问题。设备的各种状态以及突发状况的处理等等。所以串口通信成功只是一个小小的开始,更多的问题还在后面。github地址如下所示:https://github.com/HuRuWo/SerialPortHelper

    展开全文
  • Android串口开发(android-serialport-api开发)工程实例。SerialPortUtil里面有我常用的转换工具(16进制字符串转二进制字符串并补位、二进制字符串转16进制字符串并补位)
  • 主要给大家介绍了关于android串口开发入门之搭建ndk开发环境及第一个jni调用程序的相关资料,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习...
  • Android蓝牙串口开发指南
  • 公司业务是开发智能快递柜的,最近几天再研究串口编程。这是很据android-serialport-api 自己简化的一个demo ,主要实现 串口连接的 开启,关闭,发送数据,获取数据等。可以使用。
  • QT for Android串口开发

    千次阅读 2019-12-28 10:35:41
    最近在搞QT for Android开发,在网上搜了下解决方案发现都是需要java库的支持,QT原生接口QSerialPort不支持Android系统的串口开发,因为QT的接口掉的都是标准的接口,而Android都是非标准的,所以用不了,只能自己...
  • Android 串口开发

    2019-06-25 17:34:10
    最近项目需要android和硬件进行通信,通讯方式都是通过串口,android串口通讯google有个开源的demo ,我和很多人一样我也是通过下载这个demo进行开发和研究的。 google android串口通讯开源demo地址: ...
  • 里面包含有自定义串口协议及方法,以及封装好的串口调用JNI接口libserialportJni.so库及Android层调用的serialport.jar包,下载导入即可使用,并附有串口协议开发详解文档说明。使用案例:Android手机或手表通过串口...
  • Android USB转串口通信开发实例详解 好久没有写文章了,年前公司新开了一个项目,是和usb转串口通信相关的,需求是用安卓平板通过usb转接后与好几个外设进行通信,一直忙到最近,才慢慢闲下来,趁着这个周末不忙,...
  • android串口开发demo

    热门讨论 2014-04-30 20:54:10
    这个串口调试demo应该可以说运行于任何厂家做的android开发板,主要是这个没有采用厂家的库文件,就我测试的,一个我们自己做的android2.3系统,底层硬件操作(指串口)有专门的*.so文件支持,一个是其他公司的,也...
  • android 串口开发

    千次阅读 2017-04-07 16:50:06
    说到串口开发,不得不先明确...串行接口简称 串口,也称 串行通信接口 或 串行通讯接口(通常指COM接口)。是指数据一位一位地顺序传送,其特点是通信线路简单,只要一对传输线就可以实现双向通信,从而大大降低了成本
  • Android利用Android串口开发与硬件利用1K Xmodem协议远程升级,Android串口232开发,硬件利用1K Xmodem协议进行远程升级
  • 歌开源的android-serialport-api项目(http://code.google.com/p/android-serialport-api/)

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 15,943
精华内容 6,377
关键字:

android串口开发