java实现上位机与下位机串口通信实例(含java串口通信jar包下载及代码)

step 4:实现实时系统时间的数据包传输至下位机

这一步可以分为以下两个步骤:首先实现获取系统时间,将时间进行封装成帧;另外就是通过RS485串口将时间数据包发送至单板机系统进行解析。

1) 系统时间的获取

根据java面对对象设计思想,这里将有关系统时间的方法归为一类。
以下是获取当前系统时间代码:

public static String getCurrentDateTime()
    {
        //单例模式
         Calendar calendar=Calendar.getInstance();
         int year = calendar.get(Calendar.YEAR);//获取年份  
         int month=calendar.get(Calendar.MONTH);//获取月份   
         int day=calendar.get(Calendar.DATE);//获取日期  
         int minute=calendar.get(Calendar.MINUTE);//分   
         int hour=calendar.get(Calendar.HOUR);//小时   
         int second=calendar.get(Calendar.SECOND);//秒  
         String curerentDateTime = year + " " + (month + 1 )+ " " + day + " "+ (hour+12) + " " + minute + " " + second + " ";
         timeCheckSum=year+(month+1)+day+(hour+12)+minute+second;
         return curerentDateTime;  
    }

java 提供了calender类,该类提供了一些与时间有关方法。至于Calendar.getInstance()使用单例模式获取一个Calendar实例对象,单例模式就是一个类在任何时候只允许有一个实例化对象。获取系统时间除了使用Calendar还可以使用Date类,通过创建对象也可以实现系统当前时间的获取。timeCheckSum作为时间数据的校验和发送至单板机作为自定义协议的一部分。
由于发送的数据包通常是以字节(byte)为单位进行发送和传输的,因此需要将int型的时间转换为byte使用byte[]进行存储,作为一个数据包发送。

/*
 * 将以上时间字符串进行隔开用byte[]保存
 */
public static byte[] dateTimeBytesGet(String currenDateTime)
{
    //对当前时间参数进行格式判断
    //对格式进行判断
    int rawDataSize=6;
    byte[] dateTimeBytes=new byte[rawDataSize+1];
    String[] currentDateTimeSplit=currenDateTime.split(" ");
    if(currentDateTimeSplit.length==rawDataSize)
    {
        //时间数据格式正确
        //eg 2016 12 23 22 18 26
        //使用byte[]进行存储时需要 -128~+127
        //对于年份使用两个byte存储
        for(int dataIndex=0;dataIndex<rawDataSize;dataIndex++)
        {
            int dateTemp=Integer.parseInt(currentDateTimeSplit[dataIndex]);
            if(dataIndex==0)
            {
                byte H8bits=(byte)((dateTemp)>>8);
                byte L8bits=(byte)((dateTemp)&0xff);
                dateTimeBytes[dataIndex]= H8bits;
                dateTimeBytes[dataIndex+1]= L8bits;
            }
            dateTimeBytes[dataIndex+1]=(byte)dateTemp;
        }
    }else
    {
        System.out.println("当前时间获取出现异常数据");
        System.exit(-1);
        dateTimeBytes=null;
    }
    return dateTimeBytes;
}

以上数据可以使用7个byte对时间数据进行存储,因为年份需要使用两个字节来存储,格式为高字节在前,低字节在后,之后依次存放。

将时间数据存放在byte[]数组以后接下来就是添加自己的协议部分了。该部分具有较大的随意性,因为该协议可以根据不同的风格有不同的形式。为了简单起见,只需要在时间数据byte[]之前添加head、CMD、时间数据长度length这三个字节进行补充,时间数据byte[]后面依次添加校验和的高低字节以及tail指令即可。以上基本实现了一个简单的时间数据package。

以下是本模块的代码:

/*
* 将数组封装成帧
* 每一个数据帧由以下几个部分组成
* 1)数据包头部 head 0X2F
* 2)数据包命令 CMD  0X5A
* 3)数据个数     length of data 7
* 4)校验和         H8/L8 byte of  check sum(高字节在前 低字节在后)
* 5)数据结尾标志 tail OX30
* 6)可采用线程进行获取当前时间
*/
public static byte[] makeCurrentDateTimefromStringtoFramePackage(byte[] dateTimeBytes)
{
    //在时间byte[]前后添加一些package校验信息
    int dataLength=13;
    byte[] terimalTimePackage=new byte[dataLength];
    //装填信息
    //时间数据包之前的信息
    terimalTimePackage[0]=0x2F;
    terimalTimePackage[1]=0X5A;
    terimalTimePackage[2]=7;
    //计算校验和
    //转化为无符号进行校验
    for(int dataIndex=0;dataIndex<dateTimeBytes.length;dataIndex++)
    {
        terimalTimePackage[dataIndex+3]=dateTimeBytes[dataIndex];
    }
    //将校验和分为高低字节
    byte sumH8bits=(byte)((timeCheckSum)>>8);
    byte sumL8bits=(byte)((timeCheckSum)&0xff);
    terimalTimePackage[10]=sumH8bits;//高字节在前
    terimalTimePackage[11]=sumL8bits;//低字节在后
    //数据包结尾
    terimalTimePackage[12]=0X30;
    return terimalTimePackage;
}

下面给出了将时间数据byte数组进行解析的debug代码,一方面是确定上位机本部分模块的程序可靠性,另外也可以直接移植到下位机对数据包的解析之中。

在下位机解析过程中需要注意一点:因为在java中8大基本类型都是带符号,年份时间和时间校验和拆分为高低字节时,低字节是二进制无符号的,但是计算机却是按照有符号数(补码方式)进行读取,例如在2016年转换为二进制数为:11111100000,那么高字节为00000111,低字节为11100000。计算机读取为:高字节为7,低字节为-32。其实由两个byte真实还原的过程应为:7<<8+(低字节二进制数字)=7*256+224=2016,因此在debug解析时间数据包时需要将有符号数字转换为无符号数字。

 /*
 * 对时间格式进行解析并还原原来的时间格式
 * 对数据进行还原
 * 仅限于debug使用
 */
public static String dateTimeBytesfromTostring(byte[] currentDateTime)
{
    String string="";
    if(currentDateTime.length==7)
    {
      string=((currentDateTime[0]<<8)+bytetoUnsigendInt(currentDateTime[1]))+" "+currentDateTime[2]+" "+
      currentDateTime[3]+" "+currentDateTime[4]+" "+currentDateTime[5]+" "+
      currentDateTime[6];
    }

    return string;
}

/*
 * 将byte转化为字符串
 * 将有符号byte转化为无符号数字
 * debug使用
 */
public  static int bytetoUnsigendInt(byte aByte)
{
    String s=String.valueOf(aByte);
    //System.out.println(s);
    int bytetoUnsigendInt=0;
    for(int i=0;i<s.length();i++)
    {
        if(s.charAt(i)!='0')
        {
            bytetoUnsigendInt+=1<<(7-i);
        }
    }
    return bytetoUnsigendInt;
}

2)将最后的时间数据包通过RS485串口发送至下位机
结合前面的串口程序就可以使用串口发送程序了。在程序debug的前期可以在程序的关键位置输出日志就是打印log的方法可以提高程序调试的效率。以下是主类的测试代码:

//取出第一个COM端口进行测试
            SerialPort serialPort=UARTParameterSetup.portParameterOpen(arraylist.get(0), 57600);
            //退出程序 后续不需要监测 因为transimit一直需要保证连接状态
            //System.exit(0);
            DataTransimit.uartSendDatatoSerialPort(serialPort, dataFrame);
            String currentDateTime=SystemDateTimeGet.getCurrentDateTime();
            System.out.println(currentDateTime);
            byte[] bytes=SystemDateTimeGet.dateTimeBytesGet(currentDateTime);
            //System.out.println(Arrays.toString(bytes));
            String str=SystemDateTimeGet.dateTimeBytesfromTostring(bytes);
            System.out.println(str);
            //System.out.println(SystemDateTimeGet.bytetoUnsigendInt((byte) -32));
            byte[] terimalTimeByte=SystemDateTimeGet.makeCurrentDateTimefromStringtoFramePackage(bytes);
            System.out.println(Arrays.toString(terimalTimeByte));
            DataTransimit.uartSendDatatoSerialPort(serialPort, terimalTimeByte);

以下是测试结果:
当没有串口设备接入计算机时控制台打印一条信息:

没有找到可用的串口端口,请check设备!

当RS485设备接入计算机时,控制台打印消息如下:

java实现上位机与下位机串口通信实例(含java串口通信jar包下载及代码)

通过以上几个步骤基本实现了上位机与下位机串口通信的功能,接下来还可以对程序进行改进:
1)添加界面,可以类比串口助手界面根据自身需要设计独具风格的人机交互界面。
2) 在程序中添加线程,在以上程序中对于系统时间的获取可以通过线程的方式进行获取,这样上位机就可以一直往下位机发送数据包,而不是仅仅发一次。
3)对于上位机数据接收,除了以上最基本的接收功能外,还可以使用JDBC与mysql等数据进行存储,并绘画数据曲线实现特性分析。

125jz网原创文章。发布者:江山如画,转载请注明出处:http://www.125jz.com/11224.html

(0)
江山如画的头像江山如画管理团队
上一篇 2023年1月5日 上午10:19
下一篇 2023年1月13日 下午3:55

99%的人还看了以下文章

  • 一文让你快速理解欠拟合和过拟合,以及解决欠拟合和过拟合的方法?(精)

    前面分享过《深度学习中的激活函数、防止过拟合的方法》、《最清楚的过拟合(Overfitting)、欠拟合讲解》,今天给125建站网再给大家梳理一下,让你快速理解欠拟合和过拟合,以及解决欠拟合和过拟合的方法? 欠拟合与过拟合 欠拟合是指模型在训练集、验证集和测试集上均表现不佳的情况; 过拟合是指模型在训练集上表现很好,到了验证和测试阶段就大不如意了,即模型的泛…

    2023年1月16日
    3.4K0
  • 第一个Spring MVC 项目:Hello World(Eclipse版)

    125建站网前面分享了《Spring框架概述》,新学习的同学可以先阅读引文章,今天给大家分享第一个Spring MVC实战项目:Hello World 目录  一、MVC概要 二、Spring MVC介绍 三、第一个Spring MVC 项目:Hello World(Eclipse版) 3.1、通过Maven新建一个Web项目 3.2、添加依赖的jar包 3…

    2023年1月24日 编程开发
    1.0K0
  • python 初学者练手上机实操四

    1.用*打印一个如下所示的图形。(10分) * * * * * * * * * * print(‘*’) print(‘* *’) print(‘* * *’) print(‘* * * *’) 要求分别使用for和while语句实现 导入turtle包(impo…

    2023年5月5日
    4.5K0
  • 在servlet中输出JS中文乱码,servlet中alert对话框出现中文乱码的解决方法

    一、在servlet中输出JS中文乱码 解决方法 在servlet中添加以下代码:   request.setCharacterEncoding(“UTF-8”);   response.setContentType(“text/html”);   response.setCharacterEncoding(“UTF-8”); 二、servlet中alert…

    2019年11月29日 编程开发
    11.0K0
  • 开发软件,编程语言Java和C++选哪个?

    根据网络调查数据:编程语言排名前三的是Java、C#、C++。 其中Java使用者比例最高,为42.82%,是C#的两倍还要多。 紧跟其后的是C#,比例为17.33%。 排名第三的C++则有14.35%的比例。 JAVA和C++都是面向对象语,都能够实现面向对象思想(封装,继乘,多态)。而由于C++为了照顾大量的C语言使用者,而兼容了C,使得自身仅仅成为了带…

    2021年2月16日
    5.7K0
  • 卷积神经网络 数据维度计算公式:输入输出关系、输出维度

    假设你有 5 个大小为 7×7、边界值为 0 的卷积核,同时卷积神经网络第一层的深度为 1。 此时如果你向这一层传入一个维度为 224x224x3 的数据,那么神经网络下一层所接收到的数据维度是( )。 A.218*218*5 B.217*217*8 C.217*217*3 D.220*220*5 在进行深度学习训练时,优化器会对模型的参数进行优化…

    2022年9月22日 编程开发
    13.8K3

发表回复

登录后才能评论