Android串口通信

1. 解析SerialPort API 串口通信例子  

公司主营业务:网站建设、成都网站设计、移动网站开发等业务。帮助企业客户真正实现互联网宣传,提高企业的竞争能力。成都创新互联是一支青春激扬、勤奋敬业、活力青春激扬、勤奋敬业、活力澎湃、和谐高效的团队。公司秉承以“开放、自由、严谨、自律”为核心的企业文化,感谢他们对我们的高要求,感谢他们从不同领域给我们带来的挑战,让我们激情的团队有机会用头脑与智慧不断的给客户带来惊喜。成都创新互联推出封丘免费做网站回馈大家。

         首先分析一下例子中的类结构 :

         Android串口通信Android串口通信

     通过类结构可知,最主要的还是在SerialPortJNI.java 类 ,该类写了一些Native 方法处理打开与关闭 串口 接收 发送的 

     SerialPort.Java 代码如下 :


package com.dwin.navy.serialportapi;


import java.io.FileDescriptor;


import android.util.Log;


/**

 * 串口JNI

 * 

 * @author dwin

 * 

 */

public class SerialPortJNI {


    static {

        Log.i("NativeClass", "before load library");

        System.loadLibrary("serialport");

        Log.i("NativeClass", "after load library");

    }


    public FileDescriptor mFd;


    public String mDevNum;

    public int mSpeed;

    public int mDataBits;

    public int mStopBits;

    public int mParity;


    public int RS485ModFp = -1;


    public static int RS485Read = 0;

    public static int RS485Write = 1;


    public native int setSpeed(FileDescriptor fd, int speed);


    public native int setParity(FileDescriptor fd, int dataBits, int stopBits,

            int parity);


    public native FileDescriptor openDev(String devNum);


    public native FileDescriptor open485Dev(String devNum);


    public native int closeDev(FileDescriptor fd);


    public native int close485Dev(FileDescriptor fd);


    public native int readBytes(FileDescriptor fd, byte[] buffer, int length);


    public native boolean writeBytes(FileDescriptor fd, byte[] buffer,

            int length);


    public native int set485mod(int mode);

  红色区域 先申明一个static 静态域 加载.so 动态库文件 .so通过JNI方式生成 保存在libs目录下 ,由于本例子使用的cpu为 mips(默认为arm) 所以 .so库文件 将存入mips文件夹下

  还有打开串口,关闭串口,485模式下开关方式 ,接收 与发送 byte 


        1> SerialPort API 处理了接收与发送 文本与十六进制 两种模式下接收与发送数据 

          UI布局如下 :

        Android串口通信Android串口通信

  

         2>在电脑中插入usb转串口工具 ,然后在app中打开串口 

    

      SerialPortOpt.java 继承了 SerialPortJNI.Java 类 调用相应的JNI接口 

 

      SerialPortOpt.java  类大致如下 :


     package com.dwin.navy.serialportapi;


import java.io.FileDescriptor;

import java.io.FileInputStream;

import java.io.FileOutputStream;

import java.io.InputStream;

import java.io.OutputStream;


import android.util.Log;


/**

 * 调用JNI的串口

 * 

 * @author dwin

 * 

 */

public class SerailPortOpt extends SerialPortJNI {


    private static final String TAG = "SerialPort";


    private FileInputStream mFileInputStream;

    private FileOutputStream mFileOutputStream;


    public FileDescriptor openDev(String devNum) {

        super.mFd = super.openDev(devNum);

        if (super.mFd == null) {

            Log.e(TAG, "native open returns null");

            return null;

        }

        mFileInputStream = new FileInputStream(super.mFd);

        mFileOutputStream = new FileOutputStream(super.mFd);

        return super.mFd;

    }


    public FileDescriptor open485Dev(String devNum) {

        super.mFd = super.open485Dev(devNum);

        if (super.mFd == null) {

            Log.e(TAG, "native open returns null");

            return null;

        }

        mFileInputStream = new FileInputStream(super.mFd);

        mFileOutputStream = new FileOutputStream(super.mFd);

        return super.mFd;

    }


    public InputStream getInputStream() {

        return mFileInputStream;

    }


    public OutputStream getOutputStream() {

        return mFileOutputStream;

    }


    public int setSpeed(FileDescriptor optFd, int speed) {

        return super.setSpeed(optFd, speed);

    }


    public int setParity(FileDescriptor optFd, int databits, int stopbits,

            int parity) {

        return super.setParity(optFd, databits, stopbits, parity);

    }


    public int closeDev(FileDescriptor optFd) {

        int retStatus;

        retStatus = super.closeDev(optFd);

        super.mFd = null;

        return retStatus;

    }


    public int close485Dev(FileDescriptor optFd) {

        int retStatus;

        retStatus = super.close485Dev(optFd);

        super.mFd = null;

        return retStatus;

    }


    public int readBytes(FileDescriptor fd, byte[] buffer, int length) {

        return super.readBytes(fd, buffer, length);

    }


    public boolean writeBytes(FileDescriptor fd, byte[] buffer, int length) {

        return super.writeBytes(fd, buffer, length);

    }


    public int readBytes(FileDescriptor fd, byte[] buffer) {

        return super.readBytes(fd, buffer, buffer.length);

    }


    public boolean writeBytes(FileDescriptor fd, byte[] buffer) {

        return super.writeBytes(fd, buffer, buffer.length);

    }


    public int readBytes(byte[] buffer) {

        return super.readBytes(mFd, buffer, buffer.length);

    }


    public boolean writeBytes(byte[] buffer) {

        return super.writeBytes(mFd, buffer, buffer.length);

    }


    public int read485Bytes(FileDescriptor fd, byte[] buffer, int length) {

        return super.readBytes(fd, buffer, length);

    }


    public boolean write485Bytes(FileDescriptor fd, byte[] buffer, int length) {

        boolean ret;

        super.set485mod(RS485Write);

        ret = super.writeBytes(fd, buffer, length);

        super.set485mod(RS485Read);

        return ret;

    }


    public int read485Bytes(FileDescriptor fd, byte[] buffer) {

        return super.readBytes(fd, buffer, buffer.length);

    }


    public boolean write485Bytes(FileDescriptor fd, byte[] buffer) {

        boolean ret;

        super.set485mod(RS485Write);

        ret = super.writeBytes(fd, buffer, buffer.length);

        super.set485mod(RS485Read);

        return ret;

    }


    public int read485Bytes(byte[] buffer) {

        return super.readBytes(mFd, buffer, buffer.length);

    }


    public boolean write485Bytes(byte[] buffer) {

        boolean ret;

        super.set485mod(RS485Write);

        ret = super.writeBytes(mFd, buffer, buffer.length);

        super.set485mod(RS485Read);

        return ret;

    }


}


在openDev(String str)方法中调用父类的方法 ,将返回一个文件描述对象FileDescriptor ,然后初始化 FileInputStream,FileOutputStream 输入输出IO流对象 ,

还有读写byte字节数组的方法 


 3>申明或者实例化一个类用来调用和实现 这些方法 前两个类只是申明 相应的方法并没有实现相应的方法体 

  定义一个SerialPort 类

  

SerialPort.Java :


package com.dwin.dwinapi;


import java.io.FileDescriptor;

import java.io.IOException;

import java.io.InputStream;

import java.io.UnsupportedEncodingException;


import com.dwin.navy.serialportapi.SerailPortOpt;


import android.content.Context;

import android.util.Log;


/**

 * 自定义串口对象

 * 

 * @author F

 * 

 */

public class SerialPort {

    Context context;


    /**

     * 自定义串口对象

     */

    private static SerialPort serialPort;


    /**

     * 调用JNI的串口

     */

    private SerailPortOpt serialportopt;


    /**

     * 读取数据线程

     */


    /**

     * 串口接收到的流

     */

    private InputStream mInputStream;


    /**

     * 用来判断串口是否已打开

     */

    public boolean isOpen = false;


    /*

     * 接收到的数据

     */

    String data;


    /**

     * 实例化并打开串口对象

     * 

     * @param devNum

     *            串口号 S0,S1,S2,S3,S4

     * @param dataBits

     *            数据位

     * @param speed

     *            波特率

     * @param stopBits

     *            停止位

     * @param parity

     *            校验位

     */

    public SerialPort(String devNum, int speed, int dataBits, int stopBits,

            int parity) {

        serialportopt = new SerailPortOpt();

        openSerial(devNum, speed, dataBits, stopBits, parity);

    }


    /**

     * 打开串口时传入参数,可以指定打开某个串口,并设置相应的参数

     * 

     * @param devNum

     *            串口号 COM0,COM1,COM2,COM3,COM4

     * @param dataBits

     *            数据位

     * @param speed

     *            波特率

     * @param stopBits

     *            停止位

     * @param parity

     *            校验位

     * @return

     */

    private boolean openSerial(String devNum, int speed, int dataBits,

            int stopBits, int parity) {

        serialportopt.mDevNum = devNum;

        serialportopt.mDataBits = dataBits;

        serialportopt.mSpeed = speed;

        serialportopt.mStopBits = stopBits;

        serialportopt.mParity = parity;


        // 打开串口

        FileDescriptor fd = serialportopt.openDev(serialportopt.mDevNum);

        if (fd == null) {

            return false;// 串口打开失败

        } else {

            // 设置串口参数

            serialportopt.setSpeed(fd, speed);

            serialportopt.setParity(fd, dataBits, stopBits, parity);

            mInputStream = serialportopt.getInputStream();

            isOpen = true;

            return true;

        }

    }


    /**

     * 关闭串口

     */

    public void closeSerial() {

        if (serialportopt.mFd != null) {

            serialportopt.closeDev(serialportopt.mFd);

            isOpen = false;

        }

    }


    /**

     * 发送数据

     * 

     * @param data

     *            数据内容

     */

    public void sendData(String data, String type) {

        try {

            serialportopt.writeBytes(type.equals("HEX") ? HexString2Bytes(data

                    .length() % 2 == 1 ? data += "0" : data.replace(" ", ""))

                    : HexString2Bytes(toHexString(data)));

        } catch (Exception e) {


        }

    }


    /**

     * 接收数据

     * 

     * @param 收发数据类型

     * @return 接收到的字符串

     */

    public String receiveData(String type) {

        byte[] buf = new byte[1024];

        int size;

        if (mInputStream == null) {

            return null;

        }

        size = serialportopt.readBytes(buf);

        if (size > 0) {

            try {

                data = type.equals("HEX") ? bytesToHexString(buf, size)

                        : new String(buf, 0, size, "gb2312").trim().toString();

            } catch (UnsupportedEncodingException e) {

                e.printStackTrace();

            }

            return data;

        } else {

            return null;

        }

    }


    /**

     * 转化字符串为十六进制编码

     * 

     * @param s

     * @return

     */

    private String toHexString(String s) {

        String str = "";

        for (int i = 0; i < s.length(); i++) {

            int ch = (int) s.charAt(i);

            String s4 = Integer.toHexString(ch);

            str = str + s4;

        }

        return str;

    }


    /**

     * 将指定字符串src,以每两个字符分割转换为16进制形式 如:"2B44EFD9" --> byte[]{0x2B, 0x44, 0xEF,

     * 0xD9}

     * 

     * @param src

     *            String

     * @return byte[]

     */

    private static byte[] HexString2Bytes(String src) {

        byte[] ret = new byte[src.length() / 2];

        byte[] tmp = src.getBytes();

        for (int i = 0; i < tmp.length / 2; i++) {

            ret[i] = uniteBytes(tmp[i * 2], tmp[i * 2 + 1]);

        }

        return ret;

    }


    /**

     * 将Hex数组转换为Hex字符串

     * 

     * @param src

     * @param size

     * @return

     */

    public static String bytesToHexString(byte[] src, int size) {

        String ret = "";

        if (src == null || size <= 0) {

            return null;

        }

        for (int i = 0; i < size; i++) {

            String hex = Integer.toHexString(src[i] & 0xFF);

            if (hex.length() < 2) {

                hex = "0" + hex;

            }

            hex += " ";

            ret += hex;

        }

        return ret.toUpperCase();

    }


    /**

     * 将两个ASCII字符合成一个字节; 如:"EF"--> 0xEF

     * 

     * @param src0

     *            byte

     * @param src1

     *            byte

     * @return byte

     */

    private static byte uniteBytes(byte src0, byte src1) {

        byte _b0 = Byte.decode("0x" + new String(new byte[] { src0 }))

                .byteValue();

        _b0 = (byte) (_b0 << 4);

        byte _b1 = Byte.decode("0x" + new String(new byte[] { src1 }))

                .byteValue();

        byte ret = (byte) (_b0 ^ _b1);

        return ret;

    }


}


剩下的就是MainActivty中 ,打开串口 创建两个线程,ReceiverThread,SendThread 先 ,Handler 异步更新UI

private Handler mHandler = new Handler() {

        public void handleMessage(android.os.Message msg) {

            switch (msg.what) {

            case 1:

                Date date = new Date();

                eTextShowMsg.append("[" + date.getMinutes() + ":"

                        + date.getSeconds() + "] " + (CharSequence) msg.obj);

                break;

            default:

                break;

            }

        };

    };


    /**

     * 接收数据线程

     */

    class ReceiveThread extends Thread {

        public void run() {


            while (serialPort.isOpen) {

                if (isReceive) {

                    String type = togBtnShowDataType.getText().toString()

                            .trim();

                    String data = serialPort.receiveData(type);

                    if (data != null) {

                        Message msg = new Message();

                        msg.what = 1;

                        msg.obj = data;

                        System.out.println(data + "<<<<<<<<==========data");

                        mHandler.sendMessage(msg);

                    }

                }

                try {

                    Thread.sleep(1000);

                } catch (InterruptedException e) {

                    e.printStackTrace();

                }

            }

        }

    }


当串口接收到数据 每一秒更新一次UI,根据需求可转换为十六进制与字符

          

   


标题名称:Android串口通信
本文链接:http://ybzwz.com/article/iheesi.html