美文网首页我的收藏jni等杂项Android技术知识
android 如何打开串口以及与串口通讯

android 如何打开串口以及与串口通讯

作者: anddeveloper | 来源:发表于2016-12-11 23:32 被阅读5436次

    串口通讯,对于没接触过这方面的朋友们,确实会感到头疼,不知道从何下手。
    其实,串口通讯和服务器之间的通讯是一样的,都是传一些参数过去,然后返回一些数据回来。不过串口通讯管这些参数叫做指令,而这些指令是由硬件的通讯协议而定的,通讯协议不同,指令自然也不同。在我开发的这个项目里,兼容了四种硬件通讯协议,这四种协议各不相同,所以,那些指令就不在代码里面写出来了。
    串口通讯,第一步要做的当然是打开串口,打开串口的方法如下:

    QQ截图20161211220537.png
        首先在app下建立一个libs文件夹,把.so文件复制到libs下
    
    QQ截图20161211220537.png
        用android studio的朋友们要记得在build.gradle  文件中添加这段  jniLibs.srcDirs = ['libs']  ,我有一次看见别人的代码里面可以不加这段,照样能运行,有知道的可以和大家分享一下。不过这些都不重要,只要能开串口就行。然后,在java的根目录下建一个包,注意是根目录,包名为:android_serialport_api,这个包名是固定的,不能少也不能多。然后把类SerialPort复制到包下面。
    
    // JNI
    private native static FileDescriptor open(String path, int baudrate, int flags);
    public native void close();
    static {   System.loadLibrary("serial_port");   }
    
     上面的第一个函数open是调用jni打开串口的方法,调用该方法的时候会返回一个FileDescriptor对象,通过该对象可以获取输入输出流。第二个close函数是关闭串口的方法,可以通过此方法关闭串口。这两个函数最好是能成对出现,在程序打开的时候把串口打开,程序退出了就把串口关闭,这样可以避免一些问题出现。第三个是加载.so文件里面的代码的,加载了之后串口才能用。
    

    ···
    public SerialPort(File device, int baudrate, int flags) throws SecurityException, IOException {
    System.out.println("device======"+device.getAbsolutePath());
    /* Check access permission /
    if (!device.canRead() || !device.canWrite()) {
    try {
    /
    Missing read/write permission, trying to chmod the file */
    Process 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();
    }
    }

        mFd = open(device.getAbsolutePath(), baudrate, flags);
        if (mFd == null) {
            Log.e(TAG, "native open returns null");
            throw new IOException();
        }
        mFileInputStream = new FileInputStream(mFd);
        mFileOutputStream = new FileOutputStream(mFd);
    }
    

    ···
    上面的这段代码中,su.getOutputStream().write(cmd.getBytes());这行是获取root权限的,打开串口是需要root权限的,如果不能获取root权限,串口也是打不开的,其他的就是一些判断了,在这就不做详细讲解了。
    上面这些是开串口之前的准备,准备完毕后,我们来打开串口,打开串口就是调用open函数,调用open函数需要传三个参数,第一个参数path是串口名,比如:”/dev/ttyS0“,这些是根据实际接口来定的,第二个参数baudrate是波特率,一般都是9600,15200,这个需要根据硬件来定,第三个我就不清楚了,我都是传0,有知道的可以和大家分享一下。
    ···
    /**
    * 初始化串口
    * @param lockerPortInterface
    /
    private void setSerialPort(LockerPortInterface lockerPortInterface){
    this.sportInterface = lockerPortInterface;
    try {
    /
    Check parameters /
    if ((path.length() == 0) || (baudrate == -1)) {
    throw new InvalidParameterException();
    }
    /
    Open the serial port */
    boxPort = new SerialPort(new File(path), baudrate, 0);

            mOutputStreamBox = boxPort.getOutputStream();
            mInputStreamBox = boxPort.getInputStream();
            /* Create a serial rec buf  thread */
            mReadThreadBox = new ReadThreadBox();
    

    // SerialPortState = true;
    mReadThreadBox.start();
    if (firstRegisterBox) {
    if(mContext == null){
    Log.e(TAG, "mContext nulll");
    }
    m_SerialRecBox = new SerialBroadcastReceiverBox(mContext);
    m_SerialRecBox.registerAction();
    firstRegisterBox = false;
    Log.i(TAG, "----locker port--- 注册完毕");
    }
    lockerPortInterface.onLockerOutputStream(mOutputStreamBox);
    } catch (SecurityException e) {
    e.printStackTrace();
    DisplayError(mContext,R.string.error_security);
    } catch (IOException e) {
    e.printStackTrace();
    DisplayError(mContext,R.string.error_unknown);
    } catch (InvalidParameterException e) {
    e.printStackTrace();
    DisplayError(mContext,R.string.error_configuration);
    }
    }
    ···
    boxPort = new SerialPort(new File(path), baudrate, 0);这行代码是调用SerialPort的构造方法,通过他的构造方法去调用open函数,然后通过SerialPort对象来获取输入输出流。在这里解释一下,输入流是接收串口返回的数据,输出流是向串口发指令。 调用SerialPort的构造方法可能会发生三种异常,第一种异常(SecurityException)是串口无读写权限,抛出这种异常的话就说明你可能没有root权限,第二种异常(IOException )串口不能打开,可能就是你没有这个串口,第三种异常(InvalidParameterException)是传的参数有误,可能是你的波特率不对。我理解的就是这样的,不知道对不对。

    openserialport.gif
    这是我用模拟器测试的,只要有请求root权限的页面,并且抛的是IO异常,打开串口应该就没问题了。
    最后就是向串口发指令,向串口发指令是用输出流向串口写入,至于具体的指令是什么,需要根据协议来定。发完指令之后串口会回数据结果给你,你需要接收这些数据来做业务,硬件不同,回数据结果的方式也不同,有些硬件是发完指令后把结果直接回给你,有些硬件是先给你一小部分,然后等1s再回另外一部分数据。
    在我写的demo里面用的方法是针对硬件一次性把数据结果全部返回的方式,onLockerDataReceived直接用这个方法接收数据,这样就比较简单了。串口通讯说到这里就结束了。
    最后贴上自己写的一个小demo地址:https://github.com/fm183/SerialportDemo.git,以供大家参考。

    相关文章

      网友评论

      • NN又回来了:这个数据是发到哪里去了呢?
      • 刘sir_418e:Command: [/system/bin/su] Working Directory: null Environment: null
      • hahman丶:楼主你好,我碰到一个问题,说我没有读写权限。。。打开APP一直提示这个
      • _懰軓_:想向您请教些问题方便加下扣扣,122549472多谢!
      • ac232e20843b:楼主请问一下 root 也拿不到读写权限怎么办呀 模拟器4.1 5.1 都可以打开串口 但是真机 5.1就不行了 也找过厂家开串号权限 但是还是 不能读写啊
        ac232e20843b:@anddeveloper 谢谢楼主回复 解决啦 去找厂家开权限了 root 权限 串口权限 还防火墙 权限 都去掉 就可以通啦
        anddeveloper:@AnAnswer 你打开串口的时候报的什么错啊,是不是串口被占用了啊
      • b973150428c2:那是不是应该先把c语言搞会了?
      • 如今美好:您好, 关注您好久了, 请问一下,您有认识会串口通讯的朋友不, 介绍认识一下, 我现在遇到了一个很奇怪的问题:我app发命令到模块可以, 模块返回数据也有(我用示波器抓到的),但是在我的app上面获取到的inputstream流就为0 很奇怪 (这些代码我在32bit手机上面是通的, 由于后来换了64bit手机, 我做了适配,然后就获取不到流了). 大神您要是会这个就提个思路, 感谢了
        anddeveloper:@如今美好 94640332 这是串口通讯QQ群,这群应该有专业的,应该知道你的问题,你可以去问问
      • 宝贝双双:小胖子,不错嘛:clap:
      • 江城北望:Android控制硬件,通过tcp/udp 给指定的端口发送指令 不也一样么?
        善笃有余劫:Android控制硬件 就是通过串口来的 这个硬件是外接的设备
      • Hidetag:弱弱问下这个有什么用,只是申请root权限和申请之后?
        anddeveloper:@S_H_I_E_L_D 对
        Hidetag:@anddeveloper 这个要硬件支持吧,也就是说需要那套硬件自己的通信规则,所以一般开发者涉及不到?
        anddeveloper:@S_H_I_E_L_D 申请root权限是为了对串口进行读写操作,然后对串口发送命令,通过串口控制硬件,比如智能快递柜,他就是被安卓终端通过串口控制的,你要开柜门,可以向串口发送指令,让柜门打开。

      本文标题:android 如何打开串口以及与串口通讯

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