开发者社区> 问答> 正文

安卓 串口通信,问答模式

问题描述,上位机通过多线程向下位机写命令,下位机根据命令返回数据,在不给串口读写加锁的情况下如何对应命令返回的数据,本人菜鸟。。。

展开
收起
爵霸 2016-03-03 16:38:19 2711 0
1 条回答
写回答
取消 提交回答
  • 一,android串口通信
    串口通信采用一个第三方开源项目,实现串口数据收发。

    1. 使用了 api和jni;
    2. 支持4串口同时收发,有定时自动发送功能,收发模式可选Txt或Hex模式;
    3. n,8,1,没得选;
    4. 为减轻界面卡顿的情况,接收区的刷新采用单独的线程进行定时刷新;
    5. 发送区的数据以及一些设置项,在程序关闭时会自动保存,打开时自动载入;
    6. jni使用最新的NDKr8b重新编译了一下

    简单编写步骤:
    1.新建一个项目,自己起个名字
    2.直接复制serialport api和jni文件夹到新建的工程,如果不想自己编译jni,就连libs文件夹也一起复制
    3.去android官方网站下载NDK,解压,在CMD中转到jni目录,并执行 绝对路径ndk-build
    4.自己再封装一个工具类或直接使用SerialPort类都行,举个直接使用的例:
    直接剽窃原项目的SerialPortActivity.java,并稍微改一下,重点改这里
    mSerialPort = mApplication.getSerialPort();
    这里可以改成
    new SerialPort(new File("/dev/s3c2410_serial0"), 9600, 0);//COM0,波特率9600

    1. SerialPortFinder的使用就没什么好讲的了,实例化后用.getAllDevicesPath()就能获取到所有设备了。
      其它如数据转换等请参考源码

    源码可以参考谷歌android-serialport-api例子

    二,串口通信协议解析
    1.通信基本格式
    字段 描述 长度(字节)
    起始符 0F,十六进制码 1
    信息类型 一个字节,十六进制码(0F,F0,FF等保留码不用)1
    信息长度 是信息内容的长度,ASCII码表示(0~9,A~F,最大长度为256)(例如长为11个,十六进制是0B,则两个字节就写0x30 0x42)。
    注:因为最大长度256不能满足有些指令的要求,所以对长度做了扩展,下面是扩展说明:
    如果第一个字节的最高位为1,则表示扩展长度。在扩展长度状态下,其他15个字节通过16进制大端模式来保存长度。比如:0x80 0x12表示长度为0x001 2,0x81 0x12表示长度为0x0112。2
    信息内容 一组十六进制码 N
    校验 一个字节,十六进制码,是自信息类型起至对象号止所有码的异或。1
    结束符 F0,一个字节,十六进制码 (为了保证可靠性,车机下发的结束符为F0 FF)1

    2.协议解析

    /**
        * 读取终端设备数据
        * @author Administrator
        */
       private class ReadThread extends Thread {
    
           @Override
           public void run() {
               super.run();
    
               // 定义一个包的最大长度
               int maxLength = 2048;
               byte[] buffer = new byte[maxLength];
               // 每次收到实际长度
               int available = 0;
               // 当前已经收到包的总长度
               int currentLength = 0;
               // 协议头长度4个字节(开始符1,类型1,长度2)
               int headerLength = 4;
    
               while (!isInterrupted()) {
                   try {
                       available = mInputStream.available();
                       if (available > 0) {
                           // 防止超出数组最大长度导致溢出
                           if (available > maxLength - currentLength) {
                               available = maxLength - currentLength;
                           }
                           mInputStream.read(buffer, currentLength, available);
                           currentLength += available;
                       }
                       
                   }
                   catch (Exception e) {
                       e.printStackTrace();
                   }
    
                   int cursor = 0;
                   // 如果当前收到包大于头的长度,则解析当前包
                   while (currentLength >= headerLength) {
                       // 取到头部第一个字节
                       if (buffer[cursor] != 0x0F) {
                           --currentLength;
                           ++cursor;
                           continue;
                       }
                       
                       int contentLenght = parseLen(buffer, cursor, headerLength);
                       // 如果内容包的长度大于最大内容长度或者小于等于0,则说明这个包有问题,丢弃
                       if (contentLenght <= 0 || contentLenght > maxLength - 5) {
                           currentLength = 0;
                           break;
                       }
                       // 如果当前获取到长度小于整个包的长度,则跳出循环等待继续接收数据
                       int factPackLen = contentLenght + 5;
                       if (currentLength < contentLenght + 5) {
                           break;
                       }
    
                       // 一个完整包即产生
                       // proceOnePacket(buffer,i,factPackLen);
                       onDataReceived(buffer, cursor, factPackLen);
                       currentLength -= factPackLen;
                       cursor += factPackLen; 
                   }
                   // 残留字节移到缓冲区首
                   if (currentLength > 0 && cursor > 0) {
                       System.arraycopy(buffer, cursor, buffer, 0, currentLength);
                   }
               }
           }
       }
        /**
         * 获取协议内容长度
         * @param header
         * @return
         */
        public int parseLen(byte buffer[], int index, int headerLength) {
    
    //        if (buffer.length - index < headerLength) { return 0; }
            byte a = buffer[index + 2];
            byte b = buffer[index + 3];
            int rlt = 0;
            if (((a >> 7) & 0x1) == 0x1) {
                rlt = (((a & 0x7f) << 8) | b);
            }
            else {
                char[] tmp = new char[2];
                tmp[0] = (char) a;
                tmp[1] = (char) b;
                String s = new String(tmp, 0, 2);
                rlt = Integer.parseInt(s, 16);
            }
    
            return rlt;
        }
    
    protected void onDataReceived(final byte[] buffer, final int index, final int packlen) {
            System.out.println("收到信息");
            byte[] buf = new byte[packlen];
            System.arraycopy(buffer, index, buf, 0, packlen);
            ProtocolAnalyze.getInstance(myHandler).analyze(buf); 
        }
    
     
    2019-07-17 18:51:39
    赞同 展开评论 打赏
问答分类:
问答标签:
问答地址:
问答排行榜
最热
最新

相关电子书

更多
58同城Android客户端Walle框架演进与实践之路 立即下载
Android组件化实现 立即下载
蚂蚁聚宝Android秒级编译——Freeline 立即下载