安卓串口通信

1 引言

  串行接口是一种可以将接受来自CPU的并行数据字符转换为连续的串行数据流发送出去,同时可将接受的串行数据流转换为并行的数据字符供给CPU的器件。
  串口通信(Serial Communications)是指外设和计算机间,通过数据信号线 、地线、控制线等,按位进行传输数据的一种通讯方式。

2 串口参数

  串口中有五个重要的参数:串口设备名称、波特率、奇偶校验位、数据位、停止位。
  设备名称:串口的名称。Linux下查看串口名称使用 ls -l /dev/ttyS*。
  波特率:传输速率的参数。波特率表示每秒钟传送的二进制位数。常用的有115200、9600。
  校验位:在串口通信中一种简单的检错方式,有四种检错方式:偶、奇、高和低,允许无校验位。
  数据位:通信中实际数据位的参数
  停止位:用于表示单个包的最后一位。

3 开发流程

  由于串口通信过程处于硬件底层,使用串口通信需要在系统层次进行操作,谷歌官方为解决这种困难,使用JNI封装了SerialPort类来帮助开发者简化串口通信。
下载链接:serialPort-api

3.1 导入SerialPort类

  (1)在工程的java文件夹下创建android_serialport_api包,并将下载的SerialPort.java文件放在此包下。

  (2)在java目录下创建jni目录,并将Android.mk、Application.mk、gen_SerialPort_h.sh、SerialPort.c、SerialPort.h放至此目录下。

  (3)在java目录下创建jnilibs目录,将下载的armeabi、armeabi-v7a、x86拷贝至此目录。

  (4)在项目的bulid.gradle中添加以下代码:

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


SerialPort源代码:

package android_serialport_api;

import android.util.Log;
import java.io.File;
import java.io.FileDescriptor;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;

public class SerialPort {

    private static final String TAG = "SerialPort";
    public FileDescriptor mFd;
    //输入输出数据流
    private FileInputStream mFileInputStream;
    private FileOutputStream mFileOutputStream;

    public SerialPort(File device, int baudrate, int flags) throws SecurityException, IOException {

        //检查访问权限,如果没有读写权限,进行文件操作,修改文件访问权限
        if (!device.canRead() || !device.canWrite()) {

            try {
                //通过挂载到linux的方式,修改文件的操作权限
                Process su = Runtime.getRuntime().exec("/system/xbin/su");
                String cmd = "chmod 777 " + device.getAbsolutePath() + "\n" + "exit\n";
                su.getOutputStream().write(cmd.getBytes());

                if ((su.waitFor() != 0) || !device.canRead() || !device.canWrite()) {
                    Log.e("SerialPort", "SerialPort: 没有权限");
                    throw new SecurityException();
                }
            } catch (Exception e) {
                e.printStackTrace();
                throw new SecurityException();
            }
        }

        //调用本地jni方法打开串口
        mFd = open(device.getAbsolutePath(), baudrate, flags);

        if (mFd == null) {
            //若mFd为空则打开失败 
            Log.e(TAG, "native open returns null");
            throw new IOException();
        }

        mFileInputStream = new FileInputStream(mFd);
        mFileOutputStream = new FileOutputStream(mFd);
    }

    //获取输入输出流
    public InputStream getInputStream() {
        return mFileInputStream;
    }
    public OutputStream getOutputStream() {
        return mFileOutputStream;
    }


    // JNI(调用java本地接口,实现串口的打开和关闭)
    // path参数为串口路径,对应linux系统下串口的描述
    // baudrate 设置的波特率
    private native static FileDescriptor open(String path, int baudrate, int flags);

    //本地jni方法关闭串口
    public native void close();

    //加载jni下的C文件库
    static {
        Log.d(TAG, "本地库加载中");
        System.loadLibrary("serial_port");
    }
}

3.2 打开串口

  打开串口操作在SerialPort的构造函数中完成,只需创建SerrialPort对象即可打开串口。

 private String path = "/dev/ttyMT0";
 private int baudrate = 115200;


 serialPort = new SerialPort(new File(path),baudrate,0);
 if (serialPort == null){
     Log.e(TAG, "串口打开失败");
 }

3.3 发送数据

  若要通过串口发送数据需要获取串口输出流,发送代码如下:

//获取输出数据流
outputStream = serialPort.getOutputStream();
//发送数据sendData,类型为字节数组
outputStream.write(sendData);
//刷新缓冲区
outputStream.flush();

3.4 接收数据

  从串口接收需要获取串口输入流,并且读取数据需要单独开启线程,代码如下:

```

inputStream = serialPort.getInputStream();

/**
* 单开一线程,来读数据
*/
private class ReadThread extends Thread{
@Override
public void run() {
super.run();

top Created with Sketch.