《硬件接入》耀华XK3190-A9+地磅安卓(java)接入过程分享

最近遇到在安卓上通过串口连接地磅的需求, 基本上实现了读数和判断地磅稳定状态 , 这里分享出来实现过程以方便大家开发.我们开发用的打印机是XK3190-A9+ ,需要这个打印机参数文档的可以耀华官网下载:http://www.yaohua.com.cn/companyfile/16/

地磅是通过串口连接的,连接地磅主要参数有串口名称、波特率、一帧长度、以及是否校验,校验位等其他参数;

我这边做的参数有:串口名称、波特率、一帧长度以及通讯方式;

一、地磅参数

1、串口名称

在我安卓工控机上是已接入是RS232,命名为ttfS1和ttfS3两个串口;

RS232、TTL、COM 是不同电平和逻辑的串口,百度一下大概有常用的电平标准有TTL、CMOS、LVTTL、LVCMOS、ECL、PECL、LVPECL、RS232、RS485等,还有一些速度比较高的 LVDS、GTL、PGTL、CML、HSTL、SSTL等

2、波特率

波特率即调制速率,指的是有效数据讯号调制载波的速率,即单位时间内载波调制状态变化的次数。

XK3910-A9+支持的波特率有:600、1200、2400、4800、9600;我这里统一选择了9600

3、一帧长度

是指一次信号携带的数据长度 ,耀华是8位,其中开后1位是“=”号连接位,后面7位是数据位。

4、通讯方式

意思是说地磅跟其他机器的通讯方式,可以选择连续发数据,但不接收数据、发送一次和等待接收、连续发送8位、连续发送9位这四种;我选择的是连续发送8位。

地磅上相关参数的设置方步骤和方式:
在这里插入图片描述

更多设置可以去下载打印机文档.

二、配置参数

1、外设参数配置,先配置上面的默认参数

String port = “/dev/ttyS1”;//串口名字,默认ttfS1
int baudRate = 9600;//波特率,默认9600
int dateLengthPerFrame = 8;//每一帧的数据长度 ,耀华是8位

2、增加上一些本地的参数配置
int stableTimeMills = 1000;//地磅稳定时间,超过这个时间数据不曾修改则表示地磅稳定,耀华的是1秒
int receiveTimeOut = 1000;//地磅接收超时,一般地磅会毫秒内发送数据,超过这个时间则表示地磅链接失败,默认是1秒没内收到数据就表示地磅链接失败
int receiveTimeCountdownInterval = 500;//地磅接收超时,倒计时 ,默认50毫数一次
double recentlyValidWeightNum = 0.0;//最近一次有效读磅数
3、自定义地磅状态

public enum PoundStatus {
 UN_CONNECTED(-1),//未连接
 UNSTABLE(0),//已连接,不稳定
 STABLE(1);//已连接,已稳定
  int code;
PoundStatus(int code) {
  this.code = code;
}
public String getStatusStr() {
return code == -1 ? "未连接" : (code == 0 ? "不稳定" : "稳定");
  }
}

三、连接地磅代码解析

1、增加一个串口管理依赖

gradle 下添加依赖 implementation 'com.github.547394:SerialPortManager:1.0.10'

2、新建一个PoundManager.java 增加上面的相关配置参数

public class PoundManager {
    static PoundManager instance;//唯一实例
    SerialPortManager serialPort;//端口管理器
    SerialPortProtocol protocol = new SerialPortProtocol();//端口协议
    String port = "/dev/ttyS1";//串口名字,默认ttfS1
    int baudRate = 9600;//波特率,默认9600
    int stableTimeMills = 1000;//地磅稳定时间,超过这个时间数据不曾修改则表示地磅稳定,耀华的是1秒

    CountDownTimer countDownTimer;//地磅信号接收超时倒计时
    int receiveTimeOut = 1000;//地磅接收超时,一般地磅会毫秒内发送数据,超过这个时间则表示地磅链接失败,默认是1秒没内收到数据就表示地磅链接失败
    int receiveTimeCountdownInterval = 500;//地磅接收超时,倒计时 ,默认50毫数一次,
    int dateLengthPerFrame = 8;//每一帧的数据长度 ,耀华是8位

    PoundStatusListener poundStatusListener;//地磅状态监听器
    PoundStatus poundStatus = PoundStatus.UN_CONNECTED;//地磅状态,默认未连接
    double recentlyValidWeightNum = 0.0;//最近一次有效读磅数
    long lastValidWeightNumTimeMills;//最后一次有效读数时间
    long lastDataReceiveTime;//最后一次监听到数据输入的时间

    public static PoundManager getInstance() {
        if (instance == null) {
            instance = new PoundManager();
        }
        return instance;
    }
    /**
     * 地磅信息
     */
    public interface PoundStatusListener {
        void onTick(double lastValidWeightNum, PoundStatus status);
    }

    /**
     * 地磅状态
     */
    public enum PoundStatus {
        UN_CONNECTED(-1),//未连接
        UNSTABLE(0),//已连接,不稳定
        STABLE(1);//已连接,已稳定
        int code;

        PoundStatus(int code) {
            this.code = code;
        }

        public String getStatusStr() {
            return code == -1 ? "未连接" : (code == 0 ? "不稳定" : "稳定");
        }
    }
 }

3、初始化端口连接

 //初始化端口设置
    public void init() {
        outPutInfo("正在初始化地磅设置");
        initSettingFromSP();
        serialPort = new SerialPortManager();
        protocol.setFixedLength(dateLengthPerFrame);
        serialPort.setBufferSize(1024);
        serialPort.setProtocol(protocol);
        serialPort.setReceivedTimeout(receiveTimeOut);
        serialPort.enableDebug(true);//是否开启日志
        serialPort.setOnDataListener(new OnDataListener() {
            @Override
            public void onDataReceived(byte[] bytes) {
//             dealReceiveDataOld(bytes);
                dealReceiveData(new String(bytes));
            }

            @Override
            public void onDataSend(byte[] bytes) {
                super.onDataSend(bytes);
            }
        });
        serialPort.setOnOpenListener(new OnOpenListener() {
            @Override
            public void onSuccess(File device) {
                super.onSuccess(device);
//                poundStatus = PoundStatus.UNSTABLE;
//                outPutInfo("地磅连接成功,开始监听数据返回");
                startListeningPortCountDown();
            }

            @Override
            public void onFailure(File device, SerialPortError error) {
                super.onFailure(device, error);
                outPutInfo("地磅连接失败:" + error.toString());
                startListeningPortCountDown();
            }
        });
        outPutInfo("正在链接地磅");
        serialPort.open(port, baudRate);
    }

4、处理接受到的数据

 StringBuilder tempReceiveStr;//为了防止重复new,定义一个自由成员变量
    private void dealReceiveData(String bytes) {
        try {
            if (bytes.length() <= 1) return;
            tempReceiveStr = new StringBuilder(bytes).delete(0,1).reverse();
            Log.v("wztest", "tempStr=" +tempReceiveStr.toString());
            try {
                if (tempReceiveStr.length() != 0) {
                    //有数据
                    if (Double.parseDouble(tempReceiveStr.toString()) != recentlyValidWeightNum) {
                        //数据不同,表示数据有变动,不稳定
                        recentlyValidWeightNum = Double.parseDouble(tempReceiveStr.toString());
                        lastValidWeightNumTimeMills = System.currentTimeMillis();
                        poundStatus = PoundStatus.UNSTABLE;
                    } else {
                        //数据不变,判断是否稳定
                        poundStatus = System.currentTimeMillis() - lastValidWeightNumTimeMills > stableTimeMills ? PoundStatus.STABLE : PoundStatus.UNSTABLE;

                    }
                }
            } catch (Exception e) {
                e.printStackTrace();
                recentlyValidWeightNum = 0.0;
                poundStatus = PoundStatus.UNSTABLE;
                //  Log.v("wztest", "数据中包含了无效数字");
            }

            lastDataReceiveTime = System.currentTimeMillis();
            //输入日志和回调
            outPutInfo("收到地磅数据,最近一条有效数据为:" + recentlyValidWeightNum);
        } catch (Exception e) {
            outPutInfo("地磅信息解析错误:" + new String(bytes));
            e.printStackTrace();
            lastValidWeightNumTimeMills = System.currentTimeMillis();
            poundStatus = PoundStatus.UNSTABLE;
        }
    }

5、监听者模式+倒计时返回设备实时状态

 //监听串口数据读入倒计时
    //50年有效
    private void startListeningPortCountDown() {
        countDownTimer = new CountDownTimer(1000 * 60 * 60 * 24 * 365 * 50, 500) {
            @Override
            public void onTick(long millisUntilFinished) {
                if (System.currentTimeMillis() - lastDataReceiveTime > receiveTimeOut) {
                    poundStatus = PoundStatus.UN_CONNECTED;
                    recentlyValidWeightNum = 0.0;
                    outPutInfo("地磅连接超时");
                }
            }

            @Override
            public void onFinish() {
                //50年未关机?
            }
        }.start();
    }

    public void onDestroy() {
        if (countDownTimer != null) countDownTimer.cancel();
        if (instance != null) instance = null;
    }

    public PoundStatusListener getPoundStatusListener() {
        return poundStatusListener;
    }

    public PoundManager setPoundStatusListener(PoundStatusListener poundStatusListener) {
        this.poundStatusListener = poundStatusListener;
        return this;
    }

    /**
     * 输出日志和回调
     *
     * @param message
     */
    void outPutInfo(String message) {
        Log.v("PoundManager", message == null ? "" : message);
        if (poundStatusListener != null) {
            poundStatusListener.onTick(recentlyValidWeightNum, poundStatus);
        }
    }

6、最后调用使用

        PoundManager.getInstance().setPoundStatusListener(new PoundManager.PoundStatusListener() {
            @Override
            public void onTick(double lastValidWeightNum, PoundManager.PoundStatus status) {
                runOnUiThread(new Runnable() {
                    @Override
                    public void run() {
                        tv_num.setText(String.valueOf(lastValidWeightNum));
                        tv_hint.setText(status.getStatusStr());
                        tv_num.setTextColor(status == PoundManager.PoundStatus.STABLE ? Color.rgb(0, 255, 0) : Color.rgb(255, 0, 0));
                        tv_hint.setTextColor(status == PoundManager.PoundStatus.STABLE ? Color.rgb(0, 255, 0) : Color.rgb(255, 0, 0));
                    }
                });
            }
        }).init();

这样就正常接入了.

四、过程中遇到的问题和解决方案

1、第一个问题是地磅连接电脑可以互相接收数据,工控机连接电脑可以互相接收数据,但是地磅连接工控机就无法接收数据。

这个问题造成的原因是工控机串口线接错了 ,RS232串口线一般2是输出信号,3是输入信号,工控机那边接错线,把输入和输出接错了。

按道理工控机接错了,则工控机的输出变成了输入,那么连接到电脑,应该是无法互相接收数据的(电脑端的输入没信号了)

但是非常非常巧合的是,我买了一条双目数据线正好也是接错的,结果负负得正,反而把数据转换过来了!!!

最后拆了三个串口线发现了上面的原理,改一下针口解决了。

2、数据一次性接收的不是8位 , 而是多串数据在一次接收中

这个主要是因为没有在协议上设置一次接收数据长度,

protocol.setFixedLength(dateLengthPerFrame);

完整代码:

package com.jda.app.main.utils;

import android.content.Context;
import android.os.CountDownTimer;
import android.util.Log;

import com.tim.serialportlib.OnDataListener;
import com.tim.serialportlib.OnOpenListener;
import com.tim.serialportlib.SerialPortError;
import com.tim.serialportlib.SerialPortManager;
import com.tim.serialportlib.SerialPortProtocol;

import java.io.File;

/**
 * CreateInfo:
 * wz created on 2021/1/27;
 * Email 37717239@qq.com.
 * <p>
 * Description:
 * gradle 下添加依赖 implementation 'com.github.547394:SerialPortManager:1.0.10'
 * 耀华地磅管理工具
 */
public class PoundManager {
    static PoundManager instance;//唯一实例
    SerialPortManager serialPort;//端口管理器
    SerialPortProtocol protocol = new SerialPortProtocol();//端口协议
    String port = "/dev/ttyS1";//串口名字,默认ttfS1
    int baudRate = 9600;//波特率,默认9600
    int stableTimeMills = 1000;//地磅稳定时间,超过这个时间数据不曾修改则表示地磅稳定,耀华的是1秒

    CountDownTimer countDownTimer;//地磅信号接收超时倒计时
    int receiveTimeOut = 1000;//地磅接收超时,一般地磅会毫秒内发送数据,超过这个时间则表示地磅链接失败,默认是1秒没内收到数据就表示地磅链接失败
    int receiveTimeCountdownInterval = 500;//地磅接收超时,倒计时 ,默认50毫数一次,
    int dateLengthPerFrame = 8;//每一帧的数据长度 ,耀华是8位

    PoundStatusListener poundStatusListener;//地磅状态监听器
    PoundStatus poundStatus = PoundStatus.UN_CONNECTED;//地磅状态,默认未连接
    double recentlyValidWeightNum = 0.0;//最近一次有效读磅数
    long lastValidWeightNumTimeMills;//最后一次有效读数时间
    long lastDataReceiveTime;//最后一次监听到数据输入的时间

    public static PoundManager getInstance() {
        if (instance == null) {
            instance = new PoundManager();
        }
        return instance;
    }


    //初始化端口设置
    public void init() {
        outPutInfo("正在初始化地磅设置");
        initSettingFromSP();
        serialPort = new SerialPortManager();
        protocol.setFixedLength(dateLengthPerFrame);
        serialPort.setBufferSize(1024);
        serialPort.setProtocol(protocol);
        serialPort.setReceivedTimeout(receiveTimeOut);
        serialPort.enableDebug(true);//是否开启日志
        serialPort.setOnDataListener(new OnDataListener() {
            @Override
            public void onDataReceived(byte[] bytes) {
//             dealReceiveDataOld(bytes);
                dealReceiveData(new String(bytes));
            }

            @Override
            public void onDataSend(byte[] bytes) {
                super.onDataSend(bytes);
            }
        });
        serialPort.setOnOpenListener(new OnOpenListener() {
            @Override
            public void onSuccess(File device) {
                super.onSuccess(device);
//                poundStatus = PoundStatus.UNSTABLE;
//                outPutInfo("地磅连接成功,开始监听数据返回");
                startListeningPortCountDown();
            }

            @Override
            public void onFailure(File device, SerialPortError error) {
                super.onFailure(device, error);
                outPutInfo("地磅连接失败:" + error.toString());
                startListeningPortCountDown();
            }
        });
        outPutInfo("正在链接地磅");
        serialPort.open(port, baudRate);
    }

    StringBuilder tempReceiveStr;//为了防止重复new,定义一个自由成员变量
    private void dealReceiveData(String bytes) {
        try {
            if (bytes.length() <= 1) return;
            tempReceiveStr = new StringBuilder(bytes).delete(0,1).reverse();
            Log.v("wztest", "tempStr=" +tempReceiveStr.toString());
            try {
                if (tempReceiveStr.length() != 0) {
                    //有数据
                    if (Double.parseDouble(tempReceiveStr.toString()) != recentlyValidWeightNum) {
                        //数据不同,表示数据有变动,不稳定
                        recentlyValidWeightNum = Double.parseDouble(tempReceiveStr.toString());
                        lastValidWeightNumTimeMills = System.currentTimeMillis();
                        poundStatus = PoundStatus.UNSTABLE;
                    } else {
                        //数据不变,判断是否稳定
                        poundStatus = System.currentTimeMillis() - lastValidWeightNumTimeMills > stableTimeMills ? PoundStatus.STABLE : PoundStatus.UNSTABLE;

                    }
                }
            } catch (Exception e) {
                e.printStackTrace();
                recentlyValidWeightNum = 0.0;
                poundStatus = PoundStatus.UNSTABLE;
                //  Log.v("wztest", "数据中包含了无效数字");
            }

            lastDataReceiveTime = System.currentTimeMillis();
            //输入日志和回调
            outPutInfo("收到地磅数据,最近一条有效数据为:" + recentlyValidWeightNum);
        } catch (Exception e) {
            outPutInfo("地磅信息解析错误:" + new String(bytes));
            e.printStackTrace();
            lastValidWeightNumTimeMills = System.currentTimeMillis();
            poundStatus = PoundStatus.UNSTABLE;
        }
    }

    /****
     * 第一版处理数据方式 ,通过=号分割处理,
     * 临时备份, 准备第二个更加有效率的方式处理
     * @param bytes
     */
    private void dealReceiveDataOld(byte[] bytes) {
        try {
            if (bytes.length == 0) return;
            String[] splitList = new String(bytes).split("=");//耀华的称重数据解析
//                    Log.v("wztest", "收到消息" + new String(bytes) + " 分割数组长度" + splitList.length);
            boolean containsDifferentNum = false;//数据段是否包含与最近称重不同数据
            for (int i = 0; i < splitList.length; i++) {
//                        Log.v("wztest", "第" + i + "个数据" + splitList[i]);
                try {
                    if (!splitList[i].equals("")) {
                        if (Double.parseDouble(splitList[i]) != recentlyValidWeightNum) {//发现不同数据,表示数据有变动
                            containsDifferentNum = true;
                            break;
//                                    Log.v("wztest", "数据中发现了不同数字");
                        }
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                    containsDifferentNum = true;
//                            Log.v("wztest", "数据中包含了无效数字");
                }
            }
            if (containsDifferentNum) {//如果数据不一致,则刷新最近一条有效信息的时间为当前时间,并且将数据置为不稳定
                lastValidWeightNumTimeMills = System.currentTimeMillis();
                poundStatus = PoundStatus.UNSTABLE;
                try {
                    recentlyValidWeightNum = Double.parseDouble(splitList[splitList.length - 1]);
//                                Log.v("wztest", "设置有效数据为最后一个数据" + recentlyValidWeightNum);
                } catch (Exception e) {
                    e.printStackTrace();
                    recentlyValidWeightNum = 0.0;
//                                Log.v("wztest", "最后一个数据不是有效数字");
                }
            } else {
                //数据与以前一致,则判断最近一次时间与当前时间是否超过了稳定期,超过则表示稳定,未超过则表示不稳定
                poundStatus = System.currentTimeMillis() - lastValidWeightNumTimeMills > stableTimeMills ? PoundStatus.STABLE : PoundStatus.UNSTABLE;
            }
            lastDataReceiveTime = System.currentTimeMillis();
            //输入日志和回调
            outPutInfo("收到地磅数据,最近一条有效数据为:" + recentlyValidWeightNum);
        } catch (Exception e) {
            outPutInfo("地磅信息解析错误:" + new String(bytes));
            e.printStackTrace();
            lastValidWeightNumTimeMills = System.currentTimeMillis();
            poundStatus = PoundStatus.UNSTABLE;
        }
    }

    //监听串口数据读入倒计时
    //50年有效
    private void startListeningPortCountDown() {
        countDownTimer = new CountDownTimer(1000 * 60 * 60 * 24 * 365 * 50, 500) {
            @Override
            public void onTick(long millisUntilFinished) {
                if (System.currentTimeMillis() - lastDataReceiveTime > receiveTimeOut) {
                    poundStatus = PoundStatus.UN_CONNECTED;
                    recentlyValidWeightNum = 0.0;
                    outPutInfo("地磅连接超时");
                }
            }

            @Override
            public void onFinish() {
                //50年未关机?
            }
        }.start();
    }

    public void onDestroy() {
        if (countDownTimer != null) countDownTimer.cancel();
        if (instance != null) instance = null;
    }

    public PoundStatusListener getPoundStatusListener() {
        return poundStatusListener;
    }

    public PoundManager setPoundStatusListener(PoundStatusListener poundStatusListener) {
        this.poundStatusListener = poundStatusListener;
        return this;
    }

    /**
     * 输出日志和回调
     *
     * @param message
     */
    void outPutInfo(String message) {
        Log.v("PoundManager", message == null ? "" : message);
        if (poundStatusListener != null) {
            poundStatusListener.onTick(recentlyValidWeightNum, poundStatus);
        }
    }


    //这里执行一些地磅设置缓存读取,比如波特率修改、端口修改
    private void initSettingFromSP() {

    }


    public boolean checkPoundEnvironment(Context context) {
        return false;
    }

    public void setBaudRate(int baudRate) {
        this.baudRate = baudRate;
    }

    public int getBaudRate() {
        return this.baudRate;
    }

    public void setPort(String port) {
        this.port = port;
    }

    public String getPort() {
        return this.port;
    }

    /**
     * 地磅信息
     */
    public interface PoundStatusListener {
        void onTick(double lastValidWeightNum, PoundStatus status);
    }

    /**
     * 地磅状态
     */
    public enum PoundStatus {
        UN_CONNECTED(-1),//未连接
        UNSTABLE(0),//已连接,不稳定
        STABLE(1);//已连接,已稳定
        int code;

        PoundStatus(int code) {
            this.code = code;
        }

        public String getStatusStr() {
            return code == -1 ? "未连接" : (code == 0 ? "不稳定" : "稳定");
        }
    }
}


  • 3
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值