您的位置:首页 > 移动开发 > Android开发

android串口通信——电子锁

2016-02-22 16:12 591 查看

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 0X01到0X40 0X99 XXXX

    2、开锁命令如下0x8A:

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

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

    起始 板地址 锁地址 命令 校验码 (异或)
    0X80 0X01-0XC8 0X00—18 0X33 XX
    
    如:上位机发 0X80 0X01 0X01 0X33 0XB3 ( 16 进制),返回
    命令 板地址 锁地址 状态 校验码
    0X80 0X01 0X01 0X11 0X91 (锁为开)
    0X80 0X01 0X01 0X00 0X80 (锁为关)
    
    如:上位机发 0X80 0X01 0X00 0X33 0XB2 ( 16 进制),返回
    起始 板地址 状态 1 状态 2 状态 3 状态 4 命令 校验码
    0X80 0X01 0XFF 0XFF 0XFF 0XFF 0X33 0XB2
    状态:从状态 4 开始到状态 1 低位到高位对应的锁为 1—32.
    
    如:上位机发 0X80 0X02 0X01 0X33 0XB0 ( 16 进制),读从控制柜柜门,返回
    命令 板地址 锁地址 状态 校验码
    0X80 0X02 0X01 0X11 0X92 (锁为开)
    0X80 0X02 0X01 0X00 0X83 (锁为关)
    
    如:上位机发 0X80 0X02 0X00 0X33 0XB1 ( 16 进制),读取从控制柜所有柜门,返回
    起始 板地址 状态 1 状态 2 状态 3 状态 4 命令 校验码
    0X80 0X02 0XFF 0XFF 0XFF 0XFF 0X33 0XB1
    状态:从状态 4 开始到状态 1 低位到高位对应的锁为 1—32.

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

    波特率默认是: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> 阅读更多
    内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
    标签: