android串口通信——电子锁

android串口通信——电子锁

本文解决的问题

1.如何打开电子锁

2.如何判断电子锁是否关闭

一、锁孔板基础

锁孔板的图
锁孔板的图

锁孔板中主要说一哈图示中的1和2两个部分:

图中编号说明
1拨码开关(设置板地址)
2锁的接口,这个是确定锁的地址的

1.拨码开关(设置板地址)

板地址的设置:拨码开关从 8 到 1 表示从高位到低位,拨到数字端为 1,另一端为 0。 00000001 表示板地址为 1,00000010 表示板地址为 2,00000011 表示板子地址为 3,依次类推。

3.锁地址

图中2的,每个接口都会有对应的编号,这个就做锁的编号。
那么我们想要操作一把锁,需要知道的是:板编号和锁编号。因为我们是可以接入多个板的。
例如:现在板的的编号是:00000001,锁的编号是 1 ,那么我们想要操作这个锁,就需要使用到 板1锁1来控制。

二、锁孔板的基本指令

1、板地址查询0x80:

命令头 板地址 状态 校验码 (异或)
0X80 0X01 0X00 0X99 0X18
返回:
命令头 固定 从机板地址 固定 校验位
0X80 0X01 0X010X40 0X99 XXXX

2、开锁命令如下0x8A:

命令 板地址 锁地址 状态 校验码 (异或)
0X8A 0X01-0XC8 0X0118 0X11 xx

如:上位机发 0X8A 0X01 0X01 0X11 0X9B16 进制), 1 秒后返回
命令 板地址 锁地址 状态 校验码
0X8A 0X01 0X01 0X11 0X9B (锁为开)
0X8A 0X01 0X01 0X00 0X8A (锁为关)

如:上位机发 0X8A 0X02 0X01 0X11 0X9816 进制),开从控制柜柜门, 1 秒后返回: 
命令 板地址 锁地址 状态 校验码
0X8A 0X02 0X01 0X11 0X98 (锁为开)
0X8A 0X02 0X01 0X00 0X89 (锁为关)

3、读锁状态命令 0X80(门开关状态反馈):

起始 板地址 锁地址 命令 校验码 (异或)
0X80 0X01-0XC8 0X0018 0X33 XX

如:上位机发 0X80 0X01 0X01 0X33 0XB316 进制),返回
命令 板地址 锁地址 状态 校验码
0X80 0X01 0X01 0X11 0X91 (锁为开)
0X80 0X01 0X01 0X00 0X80 (锁为关)

如:上位机发 0X80 0X01 0X00 0X33 0XB216 进制),返回
起始 板地址 状态 1 状态 2 状态 3 状态 4 命令 校验码
0X80 0X01 0XFF 0XFF 0XFF 0XFF 0X33 0XB2
状态:从状态 4 开始到状态 1 低位到高位对应的锁为 132.

如:上位机发 0X80 0X02 0X01 0X33 0XB016 进制),读从控制柜柜门,返回
命令 板地址 锁地址 状态 校验码
0X80 0X02 0X01 0X11 0X92 (锁为开)
0X80 0X02 0X01 0X00 0X83 (锁为关)

如:上位机发 0X80 0X02 0X00 0X33 0XB116 进制),读取从控制柜所有柜门,返回 
起始 板地址 状态 1 状态 2 状态 3 状态 4 命令 校验码
0X80 0X02 0XFF 0XFF 0XFF 0XFF 0X33 0XB1
状态:从状态 4 开始到状态 1 低位到高位对应的锁为 132.

三、开锁的控制和关锁的监听

波特率默认是:9600

1.DevicesUtils 硬件操作类的github地址

硬件的操作类和前面的几篇文章所描述的是一样,获取可以查看项目中的 DevicesUtils:
https://github.com/qiwenming/QwmLockDemo/blob/master/app/src/main/java/com/qwm/qwmlockdemo/utils/DevicesUtils.java

2.StringUtils 字符串的工具类

package com.qwm.qwmlockdemo.utils;

import android.util.Log;

import java.text.SimpleDateFormat;
import java.util.Date;

/**
 * @author qiwenming
 * @creation 2015-6-18 下午5:27:20
 * @instruction 字符串工具
 */
public class StringUtils {

    /**
     * byte数组转为对应的16进制字符串
     * 
     * @param src
     * @return
     */
    public static String bytesToHexString(byte[] src) {
        StringBuilder stringBuilder = new StringBuilder("");
        if (src == null || src.length <= 0) {
            return null;
        }
        for (int i = 0; i < src.length; i++) {
            int v = src[i] & 0xFF;
            String hv = Integer.toHexString(v);
            if (hv.length() < 2) {
                stringBuilder.append(0);
            }
            stringBuilder.append(hv);
        }
        return stringBuilder.toString();
    }

    /**
     * byte数组转为对应的16进制字符串
     * 
     * @param src
     * @return
     */
    public static String bytesToHexString(byte[] src, int length) {
        StringBuilder stringBuilder = new StringBuilder("");
        if (src == null || length <= 0) {
            return null;
        }
        for (int i = 0; i < length; i++) {
            int v = src[i] & 0xFF;
            String hv = Integer.toHexString(v);
            if (hv.length() < 2) {
                stringBuilder.append(0);
            }
            stringBuilder.append(hv);
        }
        return stringBuilder.toString();
    }

    /**
     * 十六进制编码字符串转为对应的二进制数组
     * 
     * @param s
     * @return
     */
    public static byte[] hexStringToBytes(String s) {
        byte[] baKeyword = new byte[s.length() / 2];
        for (int i = 0; i < baKeyword.length; i++) {
            try {

                baKeyword[i] = (byte) (Integer.parseInt(
                        s.substring(i * 2, i * 2 + 2), 16));
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        return baKeyword;
    }

    /**
     * 十六进制转ascii
     * 
     * @param hex
     * @return
     */
    public static String convertHexToString(String hex) {

        StringBuilder sb = new StringBuilder();
        StringBuilder temp = new StringBuilder();

        // 49204c6f7665204a617661 split into two characters 49, 20, 4c...
        for (int i = 0; i < hex.length() - 1; i += 2) {

            // grab the hex in pairs
            String output = hex.substring(i, (i + 2));
            // convert hex to decimal
            int decimal = Integer.parseInt(output, 16);
            // convert the decimal to character
            sb.append((char) decimal);

            temp.append(decimal);
        }

        return sb.toString();
    }

    /**
     * 10进制字符串 转为16进制字符串
     * @param dec
     * @return
     */
    public static String convertDecToHexString(String s) {
        Log.i("", s);
        String str = Integer.toHexString(Integer.parseInt(s));
        if(str.length()%2==1){
            str = "0"+str;
        }
        return str;
    }

    /**
     * 通过做异或运算,求出校验码
     * @param cmd
     * @return
     */
    public static String xor(String cmd)
    {
        if(cmd.length()%2!=0){
            cmd = "0"+cmd;
        }
        int result = 0;
        for (int i = 0; i < cmd.length()-1; i=i+2) {
            //System.out.println(cmd.substring(i,i+2));
            result ^= Integer.valueOf(cmd.substring(i, i + 2), 16);
            System.out.println("16-->"+ Integer.valueOf(cmd.substring(i, i + 2), 16));
            System.out.println("result:"+result);
        }
        return Integer.toHexString(result);
    }

    /**
     * 以"-"拆分字符串
     * @param str
     * @return
     */
    public static String[] splitString(String str){
        return str.split("-");
    }

    public static String takeCity(String str){
        String nstr = null;
        if(str!=null){
            nstr=str.substring(0, str.length()-1);
        }
        return nstr;
    }

    /**
     * 时间戳转为日期
     * @param datestr
     * @return
     */
    public static String getSimpDate(String datestr){
        SimpleDateFormat sdf = new SimpleDateFormat("MM-dd HH:mm");
        String date = sdf.format(new Date(Long.parseLong(datestr) ));
        return date;
    }
    /**
     * 时间戳转为日期
     * @param smdateint
     * @return
     */
    public static String getSimpDate(long smdateint){
        SimpleDateFormat sdf = new SimpleDateFormat("MM-dd HH:mm");
        String date = sdf.format(new Date(smdateint));
        System.out.println(date);
        return date;
    }
}

3.OpenLockActivity 开锁和关锁监听的操作类

package com.qwm.qwmlockdemo;

import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.view.View;
import android.widget.TextView;

import com.qwm.qwmlockdemo.bean.LockBean;
import com.qwm.qwmlockdemo.bean.SerialPortSendData;
import com.qwm.qwmlockdemo.utils.DevicesUtils;
import com.qwm.qwmlockdemo.utils.StringUtils;

import java.util.TimerTask;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

/**
 * @author qiwenming
 * @date 2016/2/22 0022 下午 1:48
 * @ClassName: OpenLockActivity
 * @ProjectName: 
 * @PackageName: com.qwm.qwmlockdemo
 * @Description: 开锁和关锁的界面
 * 开锁的步骤阐述:
 * 1.获取到需要打开的锁
 * 2.打开锁
 * 3.打开关锁的监听
 */
public class OpenLockActivity  extends AppCompatActivity {
    /**
     * 标题
     */
    private TextView titleTv;
    /**
     * 倒计时
     */
    private TextView timeTv;
    private LockBean lockBean;
    /**
     * 关闭的查询指令
     */
    public String closecmd = "";
    /**
     * 关闭的标志
     */
    private String closeStopStr1;
    private String openStopStr2;
    /**
     * 检查所状态
     */
    private SerialPortSendData data;
    /**
     * 硬件操作类
     */
    private DevicesUtils device;
    /**
     * 倒计时的时间 s
     */
    private int second = 300;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.open_lock_layout);
//        setContentView(R.layout.open_lock_layout);
        titleTv = (TextView)findViewById(R.id.tv_title);
        timeTv = (TextView)findViewById(R.id.tv_time);
        //获取传递过来的bean
        lockBean = (LockBean) getIntent().getSerializableExtra("lockBean");
        titleTv.setText("板"+lockBean.boardAddStr+"锁"+lockBean.lockAddStr+"打开");
        openBox();
    }

    /**
     * 放回
     * @param view
     */
    public void black(View view){
        finish();
    }


    /**
     * 开锁
     * 读取数据时候  开头的8a 有时候会有 时候没有  这样的处理 我们只能根据结尾的  9b来判断了
     */
    private void openBox() {
        String opencmd = "";
        String comCloseStr = "";
        //拼接指令: 8a(80) + 板编号 + 锁编号 + 11(00)+亦或值
        opencmd = "8a"+StringUtils.convertDecToHexString(lockBean.boardAddStr)+ StringUtils.convertDecToHexString(lockBean.lockAddStr);
        comCloseStr = "80"+StringUtils.convertDecToHexString(lockBean.boardAddStr)+StringUtils.convertDecToHexString(lockBean.lockAddStr);
        closecmd = comCloseStr+"33";

        //计算关闭的校验码
        closeStopStr1 = "00"+StringUtils.xor(comCloseStr+"00");
        openStopStr2 = "11"+StringUtils.xor(comCloseStr+"11");
        Log.i("closeStopStr1------", closeStopStr1);
        Log.i("closeStopStr2------", openStopStr2);
        closecmd+=StringUtils.xor(closecmd);

        //开锁的数据封装
        final String openStopstr = "11"+StringUtils.xor(opencmd+"11");
        final String stopstr1 = "00"+StringUtils.xor(opencmd+"00");
        opencmd+=openStopstr;
        SerialPortSendData sendData = new SerialPortSendData(lockBean.addressStr, Integer.parseInt(lockBean.bauteRateStr), opencmd, "", "",openStopstr, false);
        sendData.stopStr = openStopstr;
        sendData.stopStr1 = stopstr1;

        //检查锁状态的数据封装
        data = new SerialPortSendData(lockBean.addressStr, Integer.parseInt(lockBean.bauteRateStr), closecmd, "", "", closeStopStr1, false);
        data.stopStr = closeStopStr1;
        data.stopStr1 = openStopStr2;
        device = new DevicesUtils();
        //发送指令AAA
        device.toSend(this, sendData, new DevicesUtils.ReciverListener() {
            @Override
            public void onReceived(String receviceStr) {
                Log.i("onReceived_receviceStr", receviceStr);
                countdown();
                if(receviceStr.length()<4){//代表开锁失败
                    mHandler.sendEmptyMessageDelayed(CLOSEBOX, 1000);
                    return;
                }
                String stop = receviceStr.substring(receviceStr.length()-4, receviceStr.length());
                if(stop.equals(openStopstr)){
                    mHandler.sendEmptyMessageDelayed(CLOSEBOX, 1000);
                }
            }

            @Override
            public void onFail(String fialStr) {
            }
            @Override
            public void onErr(Exception e) {
            }

        });
    }

    public final int CLOSEBOX = 101;
    public final int COUNTDOWN = 102;
    /**
     * 用户动态监听
     */
    private Handler mHandler = new Handler(){
        public void handleMessage(Message msg) {
            switch (msg.what) {
                case CLOSEBOX:
                    if(second>1){//去监听锁的状态
                        closeLock();
                    }else{
                        mHandler.removeMessages(CLOSEBOX);
                        mHandler.removeMessages(COUNTDOWN);
                        finish();
                    }
                    break;
                case COUNTDOWN:
                    second--;
                    timeTv.setText(second+"s");
                    if(second<=0&& this!=null){
                        finish();
                    }else{
                        mHandler.sendEmptyMessageDelayed(COUNTDOWN, 1000);
                    }
                    break;
                default:
                    break;
            }
        };
    };

    /**
     * 倒计时
     */
    private void countdown(){
        final Handler handler=new Handler(){
            public void handleMessage(Message msg) {
                timeTv.setText(second+"s");
            };
        };
        final ScheduledExecutorService ses= Executors.newScheduledThreadPool(1);
        ses.scheduleAtFixedRate(new TimerTask() {
            @Override
            public void run() {
                second-=1;
                handler.sendEmptyMessage(second);
                if(second==0){
                    ses.shutdown();
                    finish();
                }
            }
        }, 0, 1, TimeUnit.SECONDS);
    }


    /**
     * 关锁检测
     *    1.创建一个 handler 来发送数据 读取锁的状态
     *    2.app关箱子
     *    3.后台
     *
     */
    public void closeLock() {
        Log.i("closeBox", "closeBox--------");
        device = new DevicesUtils();
        device.toSend(this, data, new DevicesUtils.ReciverListener() {
            @Override
            public void onReceived(String receviceStr) {
                Log.i("closeBox_receviceStr", receviceStr);
                if (receviceStr.length() < 4) {
                    mHandler.sendEmptyMessageDelayed(CLOSEBOX, 1000);
                    return;
                }
                String stop = receviceStr.substring(receviceStr.length() - 4, receviceStr.length());
                if (stop.equals(closeStopStr1)) {
                    mHandler.removeMessages(CLOSEBOX);
                    mHandler.removeMessages(COUNTDOWN);
                    finish();
                } else {
                    mHandler.sendEmptyMessageDelayed(CLOSEBOX, 1000);
                }
            }

            @Override
            public void onFail(String fialStr) {
                mHandler.sendEmptyMessageDelayed(CLOSEBOX, 1000);
            }

            @Override
            public void onErr(Exception e) {
                mHandler.sendEmptyMessageDelayed(CLOSEBOX, 1000);
            }
        });
    }

    @Override
    protected void onDestroy() {
        mHandler.removeMessages(CLOSEBOX);
        mHandler.removeMessages(COUNTDOWN);
        super.onDestroy();
    }
}

四、图示

这里写图片描述
这里写图片描述
这里写图片描述

五、源码下载

<script type="text/javascript"> $(function () { $('pre.prettyprint code').each(function () { var lines = $(this).text().split('\n').length; var $numbering = $('<ul/>').addClass('pre-numbering').hide(); $(this).addClass('has-numbering').parent().append($numbering); for (i = 1; i <= lines; i++) { $numbering.append($('<li/>').text(i)); }; $numbering.fadeIn(1700); }); }); </script>
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值