android串口通信——电子扫描枪 
我们这里开始介绍电子扫描枪(串口的),在开发中我们可能用到电子扫描枪这么一个玩意。比如,我们在做一个可以说扫描条码的app的时候,就会用到,这种情况一般都是运行在终端上,往往不是我们手机上,那么我们来看看扫描枪这个玩意吧。串口的调用我们是基于android-serialport-api的,如有疑问,请看 android串口通信——android-serialport-api

一、扫描枪基础

1.基础指令

下面介绍的只是其中一种,具体使用的是哪一种看具体的文档。

指令    说明
02820383    扫描指令
06    成功的标志(这个是一个坑,实际在用的时候,有可能只返回06,就不返回数据了,所以不能把它当做唯一成功的标志)
15    失败的标志
0d0a    结束标志,如果一个返回的数据中,是个字符串结尾,那么说明数据读取结束
2.基本操作说明

当我们需要扫描条码时候,发送 02820383 指令即可启动扫描枪扫描条码,然后我们根据上面的状态说明,来操作放回的数据。特此说明,串口的数据可能不是一次读完的,有时一个数据可能分好几次来读才读完,有时候一次就读完了,由此应该知道我们结束标志是多么的重要了。 所以我们在读完时,需要不数据先保存下来,等到读取完了了,再返回数据。

二、扫描工具类的实现

主要说明: 
1.读取数据的线程我们必须只能使用一个线程,不然会造成数据读取不正确。 
2.我们发送和读取到得数据都是十六进制。 
3.读取到数据是ascii值,我们需要自己转换为对应的值。

package com.qiwenming.scandemo.utils;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.security.InvalidParameterException;

import android.content.Context;
import android.util.Log;
import android.widget.Toast;
import android_serialport_api.SerialPort;
import android_serialport_api.SerialPortFinder;

import com.qiwenming.scandemo.MainActivity;
import com.qiwenming.scandemo.bean.SerialPortSendData;

/**
 * @author qiwenming
 * @date 2015-11-2 下午2:00:12 
 * @ClassName ScanUtils 
 * @Package com.qiwenming.scandemo.utils 
 * @Description: 串口工作类
 */
public class ScanUtils {
    protected static OutputStream mOutputStream=null;
    private static InputStream mInputStream = null;
    private ReadThread mReadThread;
    public SerialPortFinder mSerialPortFinder = new SerialPortFinder();
    private SerialPort mSerialPort;
    private Context context;
    public static ReadThread thread = null;
    /**
     * @author qiwenming
     * @creation 2015-6-18 下午4:38:54
     * @instruction 读取类
     */
    private class ReadThread extends Thread {
        private ScanReciverListener listener;
        private SerialPortSendData sendData;
        public ReadThread() {
        }

public void setDataListener(SerialPortSendData sendData, ScanReciverListener listener) {
            this.listener = listener;
            this.sendData = sendData;
        }

@Override
        public void run() {
            thread = this;
            StringBuffer sb = new StringBuffer();
            super.run();
            while (!isInterrupted()) {
                int size;
                try {
                    byte[] buffer = new byte[64];
                    if (mInputStream == null)
                        return;
                    size = mInputStream.read(buffer);
                    if (size > 0) { // 读取数据 数据c
                        //str 就是我们读取到数据
                        String str = StringUtils.bytesToHexString(buffer, size).trim().toLowerCase();
                        sb.append(str);
                        String msg = sb.toString();
                        //如果我们存储的数据,也就是读取到得数据包含了 结束的标志,那么进入这个if
                        if (msg.contains(sendData.stopStr)) {
                            //把成功的标志替换为 ""
                            msg = msg.replaceFirst("("+sendData.okStr+")+", "");
                            //查找到结束位标志的位置  然后窃取我们的数据(不包含结束位)
                            int end1 = msg.indexOf(sendData.stopStr);
                            if (end1 > 0) msg = msg.substring(0, end1 + 1);

//查找到结束位标志的位置  然后窃取我们的数据(不包含结束位)有的时候我们可能出现两种结束位
                            int end2 = msg.indexOf(sendData.stopStr1);
                            if (end2 > 0) msg = msg.substring(0, end2 + 1);

final String data = msg;
                            Log.i("onDataReceived_stop", data);
                            Log.i("onDataReceived_stop_ascii",StringUtils.convertHexToString(data)+"--------"+Thread.currentThread().getId());
                            closeDevice();
                            if (null == context)
                                return;
                            ((MainActivity) context)
                                    .runOnUiThread(new Runnable() {
                                        @Override
                                        public void run() {
                                            thread = null;
                                            listener.onReceived(data);
                                        }
                                    });
                        }
                        //包含了 失败的字符标志
                        if (sb.toString().matches("\\w+" + sendData.failStr + "\\w+")) {
                            closeDevice();
                            if (null == context)
                                return;
                            ((MainActivity) context)
                                    .runOnUiThread(new Runnable() {
                                        @Override
                                        public void run() {
                                            thread = null;
                                            listener.onFail(sendData.failStr);
                                        }
                                    });
                        }
                    }
                } catch (Exception e) {
                    listener.onErr(e);
                    return;
                }
            }
        }
    }

/**
     * 发送数据
     * 
     * @param context
     * @param devStr
     *            地址
     * @param baudRate
     *            波特率
     * @param msg
     *            发送的消息
     */
    public void toSend(Context context, SerialPortSendData sendData,
            ScanReciverListener listener) {
        this.context = context;
        //检查设备地址
        if ("".equals(sendData.path) || "/dev/tty".equals(sendData.path)) {
            Toast.makeText(context, "设备地址不能为空", 0).show();
            return;
        }
        //检查指令
        if ("".equals(sendData.commandStr)) {
            Toast.makeText(context, "指令不能为空", 0).show();
            return;
        }
        //获取输入输出流
        try {
            mSerialPort = getSerialPort(sendData.path, sendData.baudRate);
            mOutputStream = mSerialPort.getOutputStream();
            mInputStream = mSerialPort.getInputStream();
            //使用一个线程来读取数据
            if(thread==null){
                thread = new ReadThread();
                thread.setDataListener(sendData, listener);
                thread.start();
            }
            else{
                thread.setDataListener(sendData, listener);
            }

} catch (SecurityException e) {
        } catch (IOException e) {
        } catch (InvalidParameterException e) {
        }

// 上面是获取设置而已 下面这个才是发送指令
        byte[] text = StringUtils.hexStringToBytes(sendData.commandStr);
        try {
            mOutputStream.write(text);
            mOutputStream.flush();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

/**
     * 获取到串口通信的一个实例
     * 
     * @param path
     * @param baudrate
     * @return
     * @throws SecurityException
     * @throws IOException
     * @throws InvalidParameterException
     */
    public SerialPort getSerialPort(String path, int baudrate)
            throws SecurityException, IOException, InvalidParameterException {
        /* Check parameters */
        if ((path.length() == 0) || (baudrate == -1)) {
            throw new InvalidParameterException();
        }
        /* Open the serial port */
        mSerialPort = new SerialPort(new File(path), baudrate, 0);// 打开这个串口
        return mSerialPort;
    }

/**
     * 关闭设备
     */
    public void closeDevice() {
        if (mReadThread != null)
            mReadThread.interrupt();
        closeSerialPort();
        // mSerialPort = null;
    }

/**
     * 关闭串口
     */
    public void closeSerialPort() {// 关闭窗口
        if (mSerialPort != null) {
            mSerialPort.close();
            mSerialPort = null;
        }
        try {
            if(mInputStream!=null){
                mInputStream.close();
                mInputStream = null;
            }
            if(mOutputStream !=null){
                mOutputStream.close();
                mOutputStream.close();
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

/**
     * @author qiwenming
     * @creation 2015-7-20 上午10:16:54
     * @instruction 接受回调类
     */
    public interface ScanReciverListener {

/**
         * 接受以后的处理方法
         * 
         * @param string
         */
        public abstract void onReceived(String receviceStr);

/**
         * 出错
         * 
         * @param string
         */
        public abstract void onFail(String fialStr);

/**
         * 出现异常
         * 
         * @param e
         */
        public abstract void onErr(Exception e);

}

/**
     * @author qiwenming
     * @creation 2015-7-20 下午2:34:28
     * @instruction 这个是我们用于存储读取的数据
     */
    public class RecevedData {
        public ReturnType returnType;
        /**
         * 数据
         */
        public String receviedData;
    }

/**
     * @author qiwenming
     * @creation 2015-7-20 下午2:36:21
     * @instruction 使用辨识返回的数据的
     */
    public enum ReturnType {
        ERR, // 错误
        OK, // OK
        Exception
    }

}

三、发送数据和接受数据的处理

package com.qiwenming.scandemo;

import java.util.Arrays;
import java.util.List;

import android.app.Activity;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.TextView;
import android.widget.Toast;
import android_serialport_api.SerialPortFinder;

import com.qiwenming.scandemo.bean.SerialPortSendData;
import com.qiwenming.scandemo.constant.CommandConstants;
import com.qiwenming.scandemo.dialog.OneColumDialog;
import com.qiwenming.scandemo.dialog.OneColumDialog.SelectListener;
import com.qiwenming.scandemo.utils.ScanUtils;
import com.qiwenming.scandemo.utils.ScanUtils.ScanReciverListener;
import com.qiwenming.scandemo.utils.StringUtils;

/**
 * @author qiwenming
 * @date 2015-11-2 下午1:38:37 
 * @ClassName MainActivity 
 * @Package com.qiwenming.scandemo 
 * @Description:   扫描
 */
public class MainActivity extends Activity {

/**
     * 内容
     */
    private TextView contentTv;
    /**
     * 硬件地址
     */
    private String address = "";
   /**
    * 波特率
    */
    private int baudRate = 0;
    private SerialPortFinder serailFinder;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        contentTv = (TextView)findViewById(R.id.tv_content);
        serailFinder = new SerialPortFinder();
    }

/**
     * 扫描
     * @param view
     */
    public void toScan(View view){
        //1.判断有没有硬件地址
        //2.判断有木有波特率
        //3.组装指令
        //4.发送指令
        //5.数据处理

//1.判断有没有硬件地址
        if("".equals(address)){
            setDeviceAddress();
            return;
        }
        //2.判断有木有波特率
        if(baudRate==0){
            setDeviceBautRate();
            return;
        }

//3.组装指令
        //4.发送指令
        SerialPortSendData sendData = new SerialPortSendData(address, baudRate, CommandConstants.SCAN_START,
                CommandConstants.SCAN_RSP_OK, CommandConstants.SCAN_RSP_FAIL,
                CommandConstants.SCAN_STOP, true);
        ScanUtils scanDevice = new ScanUtils();
        scanDevice.toSend(this, sendData, new ScanReciverListener() {
            //5.数据处理

@Override
            public void onReceived(String receviceStr) {
                String scanNo = StringUtils.convertHexToString(receviceStr);
                contentTv.setText(scanNo);
                Log.i("toScan_recevied", scanNo);
            }

@Override
            public void onFail(String string) {
                Toast.makeText(MainActivity.this, "扫描失败,请重新扫描", 0).show();
            }

@Override
            public void onErr(Exception e) {
                Toast.makeText(MainActivity.this, "扫描失败,请重新扫描", 0).show();
            }

});
    }

/**
     * 显示地址
     * @param v
     */
    public void setDeviceAddress(){
        OneColumDialog dialog = new OneColumDialog(this, getAllDevicesPath(),new SelectListener() {
            @Override
            public void selected(int position, String value) {
                address = value;
                toScan(null);
            }
        });
        dialog.show();
        dialog.setTile("设置硬件地址");
    }

/**
     * 获取全部窗口地址
     * 
     * @return
     */
    public List<String> getAllDevicesPath() {
        return Arrays.asList(serailFinder.getAllDevicesPath());
    }

/**
     * 设置波特率
     */
    public void setDeviceBautRate(){
        OneColumDialog dialog = new OneColumDialog(this, getAllBautRate(),new SelectListener() {
            @Override
            public void selected(int position, String value) {
                baudRate = Integer.parseInt(value);
                toScan(null);
            }
        });
        dialog.show();
        dialog.setTile("设置波特率");
    }

/**
     * 获取全部 波特率
     * 
     * @return
     */
    public List<String> getAllBautRate() {
        return Arrays.asList(getResources().getStringArray(R.array.baudrates));
    }
}
--------------------- 
作者:愤怒的小明 
来源:CSDN 
原文:https://blog.csdn.net/qiwenmingshiwo/article/details/49649111?utm_source=copy 
版权声明:本文为博主原创文章,转载请附上博文链接!

android串口通信——电子扫描枪相关推荐

  1. Android串口通信实例分析【附源码】

    Android 串口通信实例分析,用的时开源的android-serialport-api 这个是用android ndk实现的串口通信,我把他做了一个简化,适合于一般的程序的串口通信移植,欢迎拍砖- ...

  2. Android串口通信apk源码

    1.SerialPortHelper「Android串口通信」介绍 原项目地址 https://github.com/freyskill/SerialPortHelper Android串口通讯助手可 ...

  3. 串口通信工具android,Android串口通信工具

    Android串口通信简单封装,可以用于和连接串口的硬件通信或者进行硬件调试 集成方法: Step 1. Add the JitPack repository to your build file / ...

  4. CH340与Android串口通信

    CH340与Android串口通信 为何要将CH340的ATD+Eclipse上的安卓工程移植到AndroidStudio 移植的具体步骤 CH340串口通信驱动函数 通信过程中重难点 还存在的问题 ...

  5. android串口通信——身份证识别器

    android串口通信身份证识别器 一身份证识别器基础 调用身份证识别器的步骤 波特率 基本指令 身份证信息结构 文字结构说明 民族代码对照表 性别代码对照表 二身份证的读取 读取的方法调用 身份证的 ...

  6. modbus协议使用【android串口通信】

    modbus协议使用[android串口通信] 本文的目的是android端与上位机之间使用modbus协议进行串口通信.通过串口与其他设备进行通信,传递数据.可以理解为电脑和键盘.鼠标通信. 关于m ...

  7. Android串口通信-AndroidStudio

    用到谷歌开源serialPort api  下载链接:serialPort-api 以下项目用的so库是谷歌原库,没有做修改 新建项目: 1.先把下载的api中这些文件拷进项目的相应位置 Serial ...

  8. Android串口通信:串口读写

    FROM:http://blog.csdn.net/burly/article/details/50512379 公司有个项目要用到串口通信,同事有写好一个DEMO,用的时候发现会有问题,从jni读串 ...

  9. android串口通信——android-serialport-api

    一.串口通信原理 串口通信(Serial Communications)的概念非常简单,串口按位(bit)发送和接收字节.尽管比按字节(byte)的并行通信慢,但是串口可以在使用一根线发送数据的同时用 ...

最新文章

  1. 36 张图详解 ARP :网络世界没有我,你哪也别想去
  2. c++深拷贝和浅拷贝
  3. Android第三十四期 - 极光推送
  4. 【c++】【转】如何只在heap上创建对象,如何只在stack上建立对象?
  5. 在windows下安装python包管理器pip及使用
  6. iphone7像素_iPhone 7能否再战三年?这几点因素你得考虑到!
  7. frps与frpc的区别
  8. qdu_ACM集训队3月5号组队训练
  9. SPU、SKU、ARPU
  10. centos配置网络笔记
  11. 11,外观模式(Facade Pattern)是为子系统中的一组接口提供一个一致的界面,此模式定义了一个高层接口,这个接口使得这一子系统更加容易使用。...
  12. Centos6.7安装Apache2.4+Mysql5.6+Apache2.4
  13. 类k-均值算法无法解决非簇状分布的数据聚类问题_无监督机器学习中,有哪些最常见的聚类算法?...
  14. 用计算机弹清明上河图谱,一篇文章让你看懂《清明上河图》中的所有细节
  15. zsh compinit: insecure directories, run compaudit for list.Ignore insecure directories and continue
  16. openGL实现太阳系行星系统
  17. 编程篇(002)-js实现一个打点计时器
  18. Synology-群晖(一)移动大内网使用 IPv6 + DDNS 实现公网访问
  19. java 批量设置单元格边框,VC下设置Excel单元格的边框 (转)
  20. C语言小案例_小程序学习(三)

热门文章

  1. 电感啸叫和LDO啸叫
  2. RTA OS系列介绍05-调度表
  3. PhoneGap(Cordova)通过插件读取android配置信息
  4. 投入Java开发实习生工作的第4天
  5. 从阿尔法磁谱仪在国际空间站的最新结果
  6. HCIP-H12-223多选题库
  7. 常用 flash CPU占用和内存问题优化
  8. 51单片机8255扩展c语言,51单片机8255之PC口控制
  9. 梯度下降的三种形式,BGD,SGD与MGD
  10. mfc 对话框 全屏_Web开发人员阅读列表:全屏对话框Web存储和语音API