Android与52832之间串口协议开发详解

1.概述
    串口主要用于一些系统之间的轻量级数据传递,比如android系统与功能机系统直接两块板子需要传递一些数
据,类似下面说到的,心率,血压血氧,房颤,运动睡眠相关的一些传感器数据通常没有Android平台驱动和算法,经常需要在52832这样的系统里集成,再将需要的数据传递到android平台去。由于是两个独立的系统,52832系统与android系统本身毫无关联,所以没有其他办法可使用,只能通过串口。特别是当前物联网盛行的传感器时代,各种各样的传感器数据,那些没有兼容到android系统的传感器想要在android上应用,就只能采取这样的方式,才比较简单易开发。    
1.1串口和波特率
    想要通过串口读取和写入数据进行传递,首先需要驱动断提供一个可读写的串口,如/dev/ttyMT1,ttyMT2等。
并设置一个固定的波特率如115200,9600等。下面说到的使用的是串口/dev/ttyMT1 和 115200 。

1.2串口库和jar包开发
    这里已经有一个开发好的串口libserialportJni.so和serialport.jar,我们直接导入
androidStudio,目录如下:
 app/libs/serialport.jar     app/libs/armeabi-v7a/libserialportJni.so
app/build.grade 配置:
android {
    ...
 ndk {
            //选择要添加的对应cpu类型的.so库(不需要的删除即可)。
            abiFilters 'armeabi-v7a'
 }
  sourceSets {
        main {
            jniLibs.srcDirs = ['libs']          
        }
    }
}
dependencies {
    ...
compile files('libs/serialport.jar')
}

1.3SerialPortMananger.java类的开发
   这里我们封装一个管理类来统一写入和发送协议字串,这个管理类需要一个发送线程和一个写入线程循环写入
和接收数据;
内容如下:
public class SerialPortMananger {
    //定义一个字节数组临时存放读取内容
    private byte[] mReadBuffer =new byte[2048];
    //定义一个监听器,一个接收到字串内容的方法和一个接收内容的方法
    OnSerialPortDataListener onSerialPortDataListener;
    SerialPort serialPort;
    ReadDataThread mReadDataThread;
    SendDataThread mSendDataThread;
    private LinkedBlockingQueue<String> msgQueue;
    public SerialPortMananger(){
    }
    public void setOnSerialPortDataListener(OnSerialPortDataListener onSerialPortDataListener){
        this.onSerialPortDataListener = onSerialPortDataListener;
    }
    //打开串口节点方法 
    public void operSerialPort(){
        serialPort = new SerialPort(new File(SerialPortConfig.SERIALPORT),SerialPortConfig.BAUDRATE,0);
        startThread(getSendThread());
    }
    public SendDataThread getSendThread(){
        if(mSendDataThread == null || mSendDataThread.isInterrupted() ||
                mSendDataThread.getState() == Thread.State.TERMINATED){
            mSendDataThread = new SendDataThread();
        }
        return mSendDataThread;
    }

    public ReadDataThread getReadThread(){
        if(mReadDataThread == null || mReadDataThread.isInterrupted() ||
                mReadDataThread.getState() == Thread.State.TERMINATED){
            mReadDataThread = new ReadDataThread();
        }
        return mReadDataThread;
    }
    private void startThread(Thread thread) {
        boolean isInterrupted = thread.isInterrupted();
        LogUtils.e("SERIALPORT.startThread isInterrupted " + isInterrupted);
        Thread.State state = thread.getState();
        LogUtils.e("SERIALPORT.startThread state " + state.toString());
        if (!isInterrupted && state == Thread.State.RUNNABLE) {
            //do nothing
        } else {
            thread.start();
        }
    }
    public void stopSendThread(){
        if(mSendDataThread != null){
            mSendDataThread.interrupt();
            mSendDataThread =null;
        }
        LogUtils.e("SERIALPORT stopSendThread 停止发送线程");
    }
    public void stopReadThread(){
        if(mReadDataThread != null){
            mReadDataThread.interrupt();
            mReadDataThread = null;
        }
        LogUtils.e("SERIALPORT stopReadThread 停止接收线程");
    }
    //开启接收数据线程
    public void startReceiveData(){
        startThread(getReadThread());
    }
    //关闭串口
    public void closePort(){
        stopSendThread();
        stopReadThread();
        if(serialPort != null){
            serialPort.SerialClose();
            serialPort = null;
        }
    }
    //发送方法(封装为字串方便处理)
    public void sendBytes(String command){
       boolean result = enqueueTcpMsg(command);
       LogUtils.e("SERIALPORT result =" + result);
    }

    protected LinkedBlockingQueue<String> getMsgQueue() {
        if (msgQueue == null) {
            msgQueue = new LinkedBlockingQueue<>();
        }
        return msgQueue;
    }
    //消息轮询队列
    public boolean enqueueTcpMsg(final String command) {
        if (command == null || getMsgQueue().contains(command)) {
            return false;
        }
        try {
            getMsgQueue().put(command);
            return true;
        } catch (InterruptedException e) {
            LogUtils.e("SERIALPORT enqueueSerialPort InterruptedException " + e);
        }
        return false;
    }
    //发送线程 
    class SendDataThread extends Thread{

        public SendDataThread( ){
        }
        @Override
        public void run() {
                 String sendCommand = null;
            try {
                 while (!Thread.currentThread().interrupted()) {
                     sendCommand = getMsgQueue().take();
                     if (serialPort != null && !TextUtils.isEmpty(sendCommand) ) {
                         byte[] sendBytes = UnicodeUtils.UnicodetoBytes(sendCommand);
                         LogUtils.e("SERIALPORT 开始写入 sendCommand=" + Arrays.toString(sendBytes));
                         boolean isSuccess = serialPort.SerialSendData(sendBytes);
                         onSerialPortDataListener.onDataSent(sendBytes, isSuccess);
                         try {
                             Thread.sleep(1500);
                         } catch (InterruptedException e) {
                             // TODO Auto-generated catch block
                             e.printStackTrace();
                         }
                     }
                 }
            } catch (Exception e) {
                LogUtils.e("SERIALPORT 发生异常=" + e);
            }
        }
    }
    //读取线程
    class ReadDataThread extends Thread{
        @Override
        public void run() {
            super.run();
             if (serialPort != null) {
                 try {
                     while (!isInterrupted()) {
                         LogUtils.e("SERIALPORT 开始读取");
                         int size = serialPort.SerialReadData(mReadBuffer);
                         LogUtils.e("SERIALPORT 开始读取 size=" + size);
                         if (size > 0) {
                             byte[] readbytes = new byte[size];
                             System.arraycopy(mReadBuffer, 0, readbytes, 0, size);
                             LogUtils.e("SERIALPORT readbytes=" + Arrays.toString(readbytes));
                             onSerialPortDataListener.onDataReceived(readbytes);
                         }
                     }
                 }catch (Exception e){
                     LogUtils.e("SERIALPORT 发生异常 e=" + e);
                 }
             }
        }
    }
}
1.3.1监听器写法:
public interface OnSerialPortDataListener {
    /**
     * 数据接收
     *
     * @param bytes 接收到的数据
     */
    void onDataReceived(byte[] bytes);

    /**
     * 数据发送
     *
     * @param bytes 发送的数据
     */
    void onDataSent(byte[] bytes,boolean isSuccess);
}

1.4调用方法
  实现发送和接收监听器
  xxxxxx  implements OnSerialPortDataListener   
  初始化各个线程(也可将下面方法再封装为一个init方法)
  serialPortMananger = new SerialPortMananger(); //获得管理类对象
  serialPortMananger.setOnSerialPortDataListener(this);//监听串口发送和读取内容
  serialPortMananger.operSerialPort();//打开串口和发送线程
  serialPortMananger.startReceiveData();//开启接收数据线程
  
1.5发送内容和接收内容解析
1.5.1发送的内容,只是打印出来看看,保证自己发送的内容没有错误即可
@Override
    public void onDataSent(byte[] bytes, boolean isSuccess) {
        String sendContent = UnicodeUtils.bytesToHexFun1(bytes);
        LogUtils.e("SERIALPORT onDataSent sendContent=" + sendContent);
    }
1.5.2接收内容解析
发送的内容,最终都是字节数组形式,通常我们都是先使用16进制字符串,再转成字节数据比较方便。这个可以根据
串口协议而定。
@Override
public void onDataReceived(byte[] bytes) {
    String hexContent = UnicodeUtils.bytesToHexFun1(bytes);
    LogUtils.e("SERIALPORT onDataReceived hexContent=" + hexContent);    
}
协议解析示例:
发送以下指令后计步传感器开始工作并返回数据:
-------------------------------------
0        1        2            3
-------------------------------------
数据头    命令    数据长度    结束包尾
0xaa    0xa0    0x04        0x55
-------------------------------------
那么按照管理类封装的方法,发送方法如下:
 SerialPortConfig.MSG_STEP_START = "aaa00455";
 serialPortMananger.sendBytes(SerialPortConfig.MSG_STEP_START);

如计步协议:
接收:
---------------------------------------------------------------------
0         1        2            3        4        5        6        7
---------------------------------------------------------------------
数据头    命令    数据长度    步数    步数    校验    校验    结束包尾
0xaa    0xa0    0x04        低8位    高8位                    0x55
---------------------------------------------------------------------
接收到的步数十六进制字串如下:
//aaa0040A8200ffff55   
isFinisedToRead = true;//保证数据完整性,是否读完
String headCache = "";
@Override
public void onDataReceived(byte[] bytes) {
    String hexContent = UnicodeUtils.bytesToHexFun1(bytes);
    LogUtils.e("SERIALPORT onDataReceived hexContent=" + hexContent);
     if(hexContent.contains("aaa004") && hexContent.length() < 10){//有效数据到第十位,所以判断到第十位即可
            headCache = hexContent;//若数据未读完,现将读取到的暂存
            isFinisedToRead = false;
    }
    if(!isFinisedToRead) {//若数据没读完整,将暂存的字串组装在一起
            hexContent =  headCache + endCache;
    }
   if(hexContent.length()>6){    
   String HEAD = hexContent.substring(0, 6); 
   //判断若头部和计步协议相等,开始解析获取步数的高低位   
   if(HEAD.equalsIgnoreCase("aaa004") && hexContent.length() >= 10){
        String steplow = hexContent.substring(6, 8);//获取低位
        String stepHigh = hexContent.substring(8, 10);//获取高位
        long step = Long.parseLong(stepHigh+steplow,16);//高低位合并并转为10进制步数
        LogUtils.d("SERIALPORT step=" + step);
        isFinisedToRead = true;//还原标志位
    }
   }    
}
其他心率,血压,房颤,血氧等协议类似,不一一详述。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值