基于java的串口通信

本文详细介绍了使用Java的RXTX库进行串口通信,结合RFID设备实现UHF电子标签的读取和写入操作。包括环境配置、串口管理类SerialPortManager的实现、数据读写方法、CRC校验以及实际应用中的注意事项。通过实例展示了如何查找串口、打开串口、读写数据、关闭串口以及添加事件监听。此外,还提供了读取EPC号、写入EPC号、读取用户数据、写入用户数据等具体操作的代码实现。
摘要由CSDN通过智能技术生成


前言

因学校实训要求需接触 南京陆加壹智能科技的RFID,查询了许多资料在此记录


一、RXTX是什么?

Fork of the Java RXTX project to primarily provide a compiled native 64-bit package for Windows and Linux. RXTX is a Java native library providing serial and parallel communication for the Java Development Toolkit (JDK). RXTX is licensed under the GNU LGPL license as well as these binary distributions. RXTX is a great package, but it was lacking pre-built binaries for x64 (64-bit) versions of Windows. This project distributes binary builds of RXTX for Windows x64, x86, ia64 and Linux x86, x86_64. These builds are compiled with the latest Microsoft Visual Studio tools. The latest CVS snapshots of RXTX were much better and more stable than the versions on the official rxtx.org website. Therefore, builds for Linux are also included to be consistent with the Windows binaries.

二、环境搭建

引入库

  • 点击官网地址

  • 找到Downloads 选择自己需要的版本(作者下载的是Windows64版本)
    在这里插入图片描述

  • 解压后文件如下
    在这里插入图片描述

  • 拷贝 rxtxSerial.dll 到 JAVA_HOME\bin目录中;

  • 拷贝 rxtxParallel.dll 到 JAVA_HOME\bin目录中;

在这里插入图片描述

  • 打开idea项目在项目下创建lib将 RXTXcomm.jar 放在lib里
    在这里插入图片描述
  • 打开模块设置
    在这里插入图片描述
  • 选择模块 ,勾选RXTX, 点击应用
    在这里插入图片描述
  • 选择 SDK ,点击“+“ 找到RXTX ,点击确定 ,点击应用
    在这里插入图片描述

三、代码实现

SerialPortManager类

package manager;

import gnu.io.*;
import utils.ArrayUtils;
import utils.ByteUtils;
import utils.ShowUtils;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.TooManyListenersException;

/**
 * 串口管理
 *
 * @author yangle
 */
@SuppressWarnings("all")
public class SerialPortManager {

	/**
	 * 查找所有可用端口
	 *
	 * @return 可用端口名称列表
	 */
	public static final ArrayList<String> findPorts() {
		// 获得当前所有可用串口
		Enumeration<CommPortIdentifier> portList = CommPortIdentifier.getPortIdentifiers();
		ArrayList<String> portNameList = new ArrayList<String>();
		// 将可用串口名添加到List并返回该List
		while (portList.hasMoreElements()) {
			String portName = portList.nextElement().getName();
			portNameList.add(portName);
		}
		return portNameList;
	}

	/**
	 * 打开串口
	 *
	 * @param portName
	 *            端口名称
	 * @param baudrate
	 *            波特率
	 * @return 串口对象
	 * @throws PortInUseException
	 *             串口已被占用
	 */
	public static final SerialPort openPort(String portName, int baudrate) throws PortInUseException {
		try {
			// 通过端口名识别端口
			CommPortIdentifier portIdentifier = CommPortIdentifier.getPortIdentifier(portName);
			// 打开端口,并给端口名字和一个timeout(打开操作的超时时间)
			CommPort commPort = portIdentifier.open(portName, 2000);
			// 判断是不是串口
			if (commPort instanceof SerialPort) {
				SerialPort serialPort = (SerialPort) commPort;
				try {
					// 设置一下串口的波特率等参数
					// 数据位:8
					// 停止位:1
					// 校验位:None
					serialPort.setSerialPortParams(baudrate, SerialPort.DATABITS_8, SerialPort.STOPBITS_1,
							SerialPort.PARITY_NONE);
				} catch (UnsupportedCommOperationException e) {
					e.printStackTrace();
				}
				return serialPort;
			}
		} catch (NoSuchPortException e1) {
			e1.printStackTrace();
		}
		return null;
	}

	/**
	 * 关闭串口
	 *
	 * @param serialport
	 *            待关闭的串口对象
	 */
	public static void closePort(SerialPort serialPort) {
		if (serialPort != null) {
			serialPort.close();
		}
	}

	/**
	 * 往串口发送数据
	 *
	 * @param serialPort
	 *            串口对象
	 * @param order
	 *            待发送数据
	 */
	public static void sendToPort(SerialPort serialPort, byte[] order) {
		OutputStream out = null;
		try {
			out = serialPort.getOutputStream();
			out.write(order);
			out.flush();
		} catch (IOException e) {
			e.printStackTrace();
		} finally {
			try {
				if (out != null) {
					out.close();
					out = null;
				}
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
	}

	/**
	 * 从串口读取数据
	 *
	 * @param serialPort
	 *            当前已建立连接的SerialPort对象
	 * @return 读取到的数据
	 */
	public static byte[] readFromPort(SerialPort serialPort) {
		InputStream in = null;
		byte[] bytes = {};
		try {
			in = serialPort.getInputStream();
			// 缓冲区大小为一个字节
			byte[] readBuffer = new byte[1];
			int bytesNum = in.read(readBuffer);
			while (bytesNum > 0) {
				bytes = ArrayUtils.concat(bytes, readBuffer);
				bytesNum = in.read(readBuffer);
			}
		} catch (IOException e) {
			e.printStackTrace();
		} finally {
			try {
				if (in != null) {
					in.close();
					in = null;
				}
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
		return bytes;
	}

	/**
	 * 添加监听器
	 *
	 * @param port
	 *            串口对象
	 * @param listener
	 *            串口存在有效数据监听
	 */
	public static void addListener(SerialPort serialPort, DataAvailableListener listener) {
		try {
			// 给串口添加监听器
			serialPort.addEventListener(new SerialPortListener(listener));
			// 设置当有数据到达时唤醒监听接收线程
			serialPort.notifyOnDataAvailable(true);
			// 设置当通信中断时唤醒中断线程
			serialPort.notifyOnBreakInterrupt(true);
		} catch (TooManyListenersException e) {
			e.printStackTrace();
		}
	}

	/**
	 * 串口监听
	 */
	public static class SerialPortListener implements SerialPortEventListener {

		private DataAvailableListener mDataAvailableListener;

		public SerialPortListener(DataAvailableListener mDataAvailableListener) {
			this.mDataAvailableListener = mDataAvailableListener;
		}

		public void serialEvent(SerialPortEvent serialPortEvent) {
			switch (serialPortEvent.getEventType()) {
				case SerialPortEvent.DATA_AVAILABLE: // 1.串口存在有效数据
					if (mDataAvailableListener != null) {
						mDataAvailableListener.dataAvailable();
					}
					break;

				case SerialPortEvent.OUTPUT_BUFFER_EMPTY: // 2.输出缓冲区已清空
					break;

				case SerialPortEvent.CTS: // 3.清除待发送数据
					break;

				case SerialPortEvent.DSR: // 4.待发送数据准备好了
					break;

				case SerialPortEvent.RI: // 5.振铃指示
					break;

				case SerialPortEvent.CD: // 6.载波检测
					break;

				case SerialPortEvent.OE: // 7.溢位(溢出)错误
					break;

				case SerialPortEvent.PE: // 8.奇偶校验错误
					break;

				case SerialPortEvent.FE: // 9.帧错误
					break;

				case SerialPortEvent.BI: // 10.通讯中断
					ShowUtils.errorMessage("与串口设备通讯中断");
					break;

				default:
					break;
			}
		}
	}

	/**
	 * 串口存在有效数据监听
	 */
	public interface DataAvailableListener {
		/**
		 * 串口存在有效数据
		 */
		void dataAvailable();
	}


	public static void getListener(SerialPort port){
		SerialPortManager.addListener(port, new DataAvailableListener() {
			@Override
			public void dataAvailable() {
				byte[] data = null;
				try {
					if (port == null) {
						ShowUtils.errorMessage("串口对象为空,监听失败!");
					} else {

						// 读取串口数据
						data = SerialPortManager.readFromPort(port);
						System.out.println("=============数据"+ByteUtils.byteArrayToHexString(data));
					}
				} catch (Exception e) {
					ShowUtils.errorMessage(e.toString());
					// 发生读取错误时显示错误信息后退出系统
					System.exit(0);
				}
			}
		});
	}
}

Tools类

package utils;

import gnu.io.PortInUseException;
import gnu.io.SerialPort;
import manager.SerialPortManager;

/**
 * @ClassName Tools
 * @Description
 * @Author meng
 * @Date 2021/5/1817:12
 */
public class  Tools {

    public static SerialPort OpenPort(SerialPortManager serialPortManager) throws PortInUseException {
        return SerialPortManager.openPort(SerialPortManager.findPorts().toString().substring(1,5),57600);

    }

    public  static void ClosePort(SerialPortManager serialPortManager,SerialPort serialPort){
        SerialPortManager.closePort(serialPort);
        System.out.println("关闭成功");
    }


    public  static String WRserialPort(SerialPortManager serialPortManager, SerialPort serialPort, String WString){

        byte[] Wbytes = ByteUtils.hexStr2Byte(WString);
        SerialPortManager.sendToPort(serialPort,Wbytes);

        byte[] Rbytes = SerialPortManager.readFromPort(serialPort);

        return ByteUtils.byteArrayToHexString(Rbytes);

    }


    public  static String FindId(SerialPortManager serialPortManager, SerialPort serialPort) throws InterruptedException {

        String x ="04ff0f";
        int [] c =StringUtils.StringToInt(x);
        String WString =x+ CRC16.getCRC2(c);
        System.out.println("Find命令:"+WString);
        return  Tools.getEpc(serialPortManager,serialPort,WRserialPort(serialPortManager,serialPort,WString));
    }


    public  static String getEpc(SerialPortManager serialPortManager, SerialPort serialPort,String x) throws InterruptedException {
        if  (x.substring(6,8).equals("01")){
            x=x.substring(12,x.length()-4);
            System.out.println("EpcId:"+x);
        }else {
            System.out.println("未找到卡:"+x);
            x="";
        }
        return x;
    }

    public  static String FindIdAll(SerialPortManager serialPortManager, SerialPort serialPort){

        String x ="04ff01";
        int [] c =StringUtils.StringToInt(x);
        String WString =x+ CRC16.getCRC2(c);
        System.out.println("命令:"+WString);
        return WRserialPort(serialPortManager,serialPort,WString);
    }


    public  static String ReadCard(SerialPortManager serialPortManager, SerialPort serialPort,String s,int Number){
        if(Number>120){
            Number=120;
        }
        String RNumber = Integer.toHexString(Number).toUpperCase();
        String SLength = Integer.toHexString(14+(s.length()/2)).toUpperCase();
        String EpcLength = Integer.toHexString(s.length()/4).toUpperCase();
        SLength =StringUtils.JLEvennumbers(SLength);
        EpcLength =StringUtils.JLEvennumbers(EpcLength);
        RNumber=StringUtils.JLEvennumbers(RNumber);
        System.out.println("ReadCard======="+SLength + "===="+EpcLength +"==="+RNumber);

        String x =SLength+"0002"+EpcLength+s+"0300"+RNumber+"000000000000";
        int [] c =StringUtils.StringToInt(x);
        String WString =x+ CRC16.getCRC2(c);
        System.out.println("Read命令:"+WString);
        String z = WRserialPort(serialPortManager,serialPort,WString);
//        System.out.println("读取返回数据:"+z);
        if (z.substring(6,8).equals("00")){
           x= z.substring(8, z.length()-4);
        }else {
            System.out.println("数据为空或者读取错误:"+x);
            x="";
        }
        return  x ;
    }

    public  static String WriteCard(SerialPortManager serialPortManager, SerialPort serialPort,String s,String transmitting){

        String SLength = Integer.toHexString(14+(s.length()/2)+(transmitting.length()/2)).toUpperCase();
        String TLength = Integer.toHexString(transmitting.length()/4).toUpperCase();
        String EpcLength = Integer.toHexString(s.length()/4).toUpperCase();

        SLength =StringUtils.JLEvennumbers(SLength);
        TLength =StringUtils.JLEvennumbers(TLength);
        EpcLength =StringUtils.JLEvennumbers(EpcLength);
//        System.out.println("WriteCard======="+SLength + "===="+TLength );

        String x =SLength+"0003"+TLength+EpcLength+s+"0300"+transmitting+"000000000000";
        System.out.println(x.length());
        int [] c =StringUtils.StringToInt(x);
        String WString =x+ CRC16.getCRC2(c);
        System.out.println("Write命令:"+WString);
        return WRserialPort(serialPortManager,serialPort,WString);
    }


    public  static String WriteEPCid(SerialPortManager serialPortManager, SerialPort serialPort,String s){

        String SLength = Integer.toHexString(9+(s.length()/2)).toUpperCase();
        String TLength = Integer.toHexString(s.length()/4).toUpperCase();

        SLength =StringUtils.JLEvennumbers(SLength);
        TLength =StringUtils.JLEvennumbers(TLength);
        System.out.println("WriteCard======="+SLength + "===="+TLength );

        String x =SLength+"0004"+TLength+"00000000"+s;
        System.out.println(x.length());
        int [] c =StringUtils.StringToInt(x);
        String WString =x+ CRC16.getCRC2(c);
        System.out.println("Write命令:"+WString);
        return WRserialPort(serialPortManager,serialPort,WString);
    }



    public  static String  BlockErase(SerialPortManager serialPortManager, SerialPort serialPort,String s){

        String SLength = Integer.toHexString(14+(s.length()/2)).toUpperCase();
        String EpcLength = Integer.toHexString(s.length()/4).toUpperCase();

        SLength =StringUtils.JLEvennumbers(SLength);
        EpcLength =StringUtils.JLEvennumbers(EpcLength);
        System.out.println("WriteCard======="+SLength + "===="+EpcLength );

        String x =SLength+"0007"+EpcLength+s+"030014000000000000";
        System.out.println(x.length());
        int [] c =StringUtils.StringToInt(x);
        String WString =x+ CRC16.getCRC2(c);
        System.out.println("Write命令:"+WString);
        return WRserialPort(serialPortManager,serialPort,WString);
    }

    public  static String  Alert(SerialPortManager serialPortManager, SerialPort serialPort){

        String x ="070033140203";
        System.out.println(x.length());
        int [] c =StringUtils.StringToInt(x);
        String WString =x+ CRC16.getCRC2(c);
        System.out.println("Write命令:"+WString);
        return WRserialPort(serialPortManager,serialPort,WString);
    }
}

重要代码解析

读取数据

在这里插入图片描述

  • 参数解析:
	ENum:EPC号长度,以字为单位。EPC的长度在15个字以内,可以为0。超出范围,将返回参数错误信息。

EPC:要读取数据的标签的EPC号。长度根据所给的EPC号决定,EPC号以字为单位,且必须是整数个长度。高字在前,每个字的高字节在前。这里要求给出的是完整的EPC号。

Mem:一个字节。选择要读取的存储区。0x00:保留区;0x01:EPC存储区;0x02:TID存储区;0x03:用户存储区。其他值保留。若命令中出现了其它值,将返回参数出错的消息。

WordPtr:一个字节。指定要读取的字起始地址。0x00 表示从第一个字(第一个16位存储区)开始读,0x01表示从第2个字开始读,依次类推。

Num:一个字节。要读取的字的个数。不能设置为0x00,否则将返回参数错误信息。Num不能超过120,即最多读取120个字。若Num设置为0或者超过了120,将返回参数出错的消息。

Pwd:四个字节,这四个字节是访问密码。32位的访问密码的最高位在Pwd的第一字节(从左往右)的最高位,访问密码最低位在Pwd第四字节的最低位,Pwd的前两个字节放置访问密码的高字。只有当读保留区,并且相应存储区设置为密码锁、且标签的访问密码为非0的时候,才需要使用正确的访问密码。在其他情况下,Pwd为零或正确的访问密码。

MaskAdr:一个字节,掩模EPC号的起始字节地址。0x00表示从EPC号的最高字节开始掩模,0x01表示从EPC号的第二字节开始掩模,以此类推。

MaskLen:一个字节,掩模的字节数。掩模起始字节地址+掩模字节数不能大于EPC号字节长度,否则返回参数错误信息。

注:当MaskAdrMaskLen为空时表示以完整的EPC号掩模。

在这里插入图片描述

  • 代码实现
  • 此代码在Tools类里
    public  static String ReadCard(SerialPortManager serialPortManager, SerialPort serialPort,String s,int Number){
        if(Number>120){
            Number=120;
        }
        String RNumber = Integer.toHexString(Number).toUpperCase();
        String SLength = Integer.toHexString(14+(s.length()/2)).toUpperCase();
        String EpcLength = Integer.toHexString(s.length()/4).toUpperCase();
        SLength =StringUtils.JLEvennumbers(SLength);
        EpcLength =StringUtils.JLEvennumbers(EpcLength);
        RNumber=StringUtils.JLEvennumbers(RNumber);
        System.out.println("ReadCard======="+SLength + "===="+EpcLength +"==="+RNumber);
        //此处是读取用户的数据的命令
        String x=SLength+"0002"+EpcLength+s+"0300"+RNumber+"000000000000";
        int [] c =StringUtils.StringToInt(x);
        String WString =x+ CRC16.getCRC2(c);
        System.out.println("Read命令:"+WString);
        String z = WRserialPort(serialPortManager,serialPort,WString);
//        System.out.println("读取返回数据:"+z);
        if (z.substring(6,8).equals("00")){
           x= z.substring(8, z.length()-4);
        }else {
            System.out.println("数据为空或者读取错误:"+x);
            x="";
        }
        return  x ;
    }

写数据

在这里插入图片描述

  • 参数解析:
WNum:待写入的字个数,一个字为2个字节。这里字的个数必须和实际待写入的数据个数相等。WNum必须大于0,若上位机给出的WNum0或者WNum和实际字个数不相等,将返回参数错误的消息。

ENum:EPC号长度。以字为单位。EPC的长度在15个字以内,可以为0。否则返回参数错误信息。

EPC:要写入数据的标签的EPC号。长度由所给的EPC号决定,EPC号以字为单位,且必须是整数个长度。高字在前,每个字的高字节在前。这里要求给出的是完整的EPC号。
 
Mem:一个字节,选择要写入的存储区。0x00:保留区;0x02:TID存储区;0x03:用户存储区。其他值保留。若命令中出现了其它值,将返回参数出错的消息。

WordPtr:一个字节,指定要写入数据的起始地址。

Wdt:待写入的字,字的个数必须与WNum指定的一致。这是要写入到存储区的数据。每个字的高字节在前。如果给出的数据不是整数个字长度,Data[]中前面的字写在标签的低地址中,后面的字写在标签的高地址中。比如,WordPtr等于0x02,则Data[]中第一个字(从左边起)写在Mem指定的存储区的地址0x02中,第二个字写在0x03中,依次类推。

Pwd4个字节的访问密码。32位的访问密码的最高位在Pwd的第一字节(从左往右)的最高位,访问密码最低位在Pwd第四字节的最低位,Pwd的前两个字节放置访问密码的高字。在写操作时,应给出正确的访问密码,当相应存储区未设置成密码锁时Pwd可以为零。

MaskAdr:一个字节,掩模EPC号的起始字节地址。0x00表示从EPC号的最高字节开始掩模,0x01表示从EPC号的第二字节开始掩模,以此类推。

MaskLen:一个字节,掩模的字节数。掩模起始字节地址+掩模字节数不能大于EPC号字节长度,否则返回参数错误信息。

注:当MaskAdrMaskLen为空时表示以完整的EPC号掩模。

在这里插入图片描述

  • 代码实现
  • 此代码在Tools类里
 public  static String WriteCard(SerialPortManager serialPortManager, SerialPort serialPort,String s,String transmitting){

        String SLength = Integer.toHexString(14+(s.length()/2)+(transmitting.length()/2)).toUpperCase();
        String TLength = Integer.toHexString(transmitting.length()/4).toUpperCase();
        String EpcLength = Integer.toHexString(s.length()/4).toUpperCase();

        SLength =StringUtils.JLEvennumbers(SLength);
        TLength =StringUtils.JLEvennumbers(TLength);
        EpcLength =StringUtils.JLEvennumbers(EpcLength);
//        System.out.println("WriteCard======="+SLength + "===="+TLength );
//处是写命令(向用户区)
        String x =SLength+"0003"+TLength+EpcLength+s+"0300"+transmitting+"000000000000";
        System.out.println(x.length());
        int [] c =StringUtils.StringToInt(x);
        String WString =x+ CRC16.getCRC2(c);
        System.out.println("Write命令:"+WString);
        return WRserialPort(serialPortManager,serialPort,WString);
    }

写EPC号

在这里插入图片描述

  • 参数解析:
		ENum1个字节。要写入的EPC的长度,以字为单位。可以为0,但不能超过15,否则返回参数错误信息。
		
Pwd4个字节的访问密码。32位的访问密码的最高位在Pwd的第一字节(从左往右)的最高位,访问密码最低位在Pwd第四字节的最低位,Pwd的前两个字节放置访问密码的高字。在本命令中,当EPC区设置为密码锁、且标签访问密码为非0的时候,才需要使用访问密码。在其他情况下,Pwd为零或正确的访问密码。

	WEPC:要写入的EPC号,长度必须和ENum说明的一样。WEPC最小0个字,最多15个字,否则返回参数错误信息。

在这里插入图片描述

  • 代码实现
  • 此代码在Tools类里
    public  static String WriteEPCid(SerialPortManager serialPortManager, SerialPort serialPort,String s){

        String SLength = Integer.toHexString(9+(s.length()/2)).toUpperCase();
        String TLength = Integer.toHexString(s.length()/4).toUpperCase();

        SLength =StringUtils.JLEvennumbers(SLength);
        TLength =StringUtils.JLEvennumbers(TLength);
        System.out.println("WriteCard======="+SLength + "===="+TLength );
//此处为写EPC号命令
        String x =SLength+"0004"+TLength+"00000000"+s;
        System.out.println(x.length());
        int [] c =StringUtils.StringToInt(x);
        String WString =x+ CRC16.getCRC2(c);
        System.out.println("Write命令:"+WString);
        return WRserialPort(serialPortManager,serialPort,WString);
    }

询查单张标签

在这里插入图片描述

  • 参数解析
Num:本条命令中包含的电子标签的EPC的个数。

EPC ID:读到的电子标签的EPC数据,EPC-1是第一张标签的EPC长度+第一张标签的EPC号。电子标签EPC号高字(EPC C1 G2中数据以字为单位)在前,每一个字的高字节在前。EPC长度以一个字节表示。
  • 代码实现
  • 此代码在Tools类里
    public  static String FindId(SerialPortManager serialPortManager, SerialPort serialPort) throws InterruptedException {

        String x ="04ff0f";
        int [] c =StringUtils.StringToInt(x);
        String WString =x+ CRC16.getCRC2(c);
        System.out.println("Find命令:"+WString);
        return  Tools.getEpc(serialPortManager,serialPort,WRserialPort(serialPortManager,serialPort,WString));
    }

CRC校验

-通过看使用说明可知所有的命令都需要CRC(最后两位)

  • 使用手册已给出CRC校验C语言版
    在这里插入图片描述

  • 此处是我写java版

public class CRC16 {
    public static String getCRC2(int [] bytes) {

        int CRC = 0xFFFF;
        int POLYNOMIAL = 0x8408;

        int i, j;
        for (i = 0; i < bytes.length; i++) {
            CRC ^= bytes[i];
            for (j = 0; j < 8; j++) {
                if ((CRC & 0x0001)!=0) {
                    CRC = (CRC >> 1)^POLYNOMIAL;
                } else {
                    CRC= (CRC>>1);
                }
            }
        }
        //高低位转换
         CRC = ( (CRC & 0x0000FF00) >> 8) | ( (CRC & 0x000000FF ) << 8);
        return Integer.toHexString(CRC);
    }
}

测试

  • 展示功能将EPCID改为 201843320,向用户区写入数据 2,2021-05-20
        SerialPortManager serialPortManager = new SerialPortManager();
        SerialPort serialPort = Tools.OpenPort(serialPortManager);


        String a= Tools.FindId(serialPortManager,serialPort);
        System.out.println(a+"========"+a.length());

        Thread.sleep(10);
        String b =Tools.ReadCard(serialPortManager, serialPort, a,12);
        System.out.println("数据:"+b+"长度"+b.length());

        Thread.sleep(10);
        System.out.println(Tools.BlockErase(serialPortManager, serialPort, a));


        Thread.sleep(10);
        String transmitting1 = StringUtils.StringToAscii("201843321");
        transmitting1 =StringUtils.StrTo16(transmitting1);
        System.out.println("transmitting1(16)========"+transmitting1+"====length"+transmitting1.length()/4);
        String q =Tools.WriteEPCid(serialPortManager,serialPort,transmitting1);
        System.out.println(q);



        String transmitting2 = StringUtils.StringToAscii("2,2021-05-20");
        transmitting2 =StringUtils.StrTo16(transmitting2);
        System.out.println("transmitting2(16)========"+transmitting2+"====length"+transmitting2.length()/4);
        String transmitting=transmitting2;
        String c = Tools.WriteCard(serialPortManager,serialPort,transmitting1,transmitting);
        System.out.println("写入返回"+c);
        System.out.println("==================="+c.substring(6,8));



        Thread.sleep(10);
        String d =Tools.ReadCard(serialPortManager, serialPort, transmitting1,12);
        System.out.println("数据:"+d+"长度"+d.length());
        System.out.println(StringUtils.AsciiToString(d));
        
       Tools.ClosePort(serialPortManager,serialPort);
  • 结果
    在这里插入图片描述
  • 展示功能读取卡号,读取卡数据(用户区)
  SerialPortManager serialPortManager = new SerialPortManager();
        SerialPort serialPort = Tools.OpenPort(serialPortManager);
               while (true){
            String a= Tools.FindId(serialPortManager,serialPort);
            Thread.sleep(10);
            if (a.length()>0){
                System.out.println(StringUtils.AsciiToString(a));
                String b = Tools.ReadCard(serialPortManager, serialPort, a, 12);
                Thread.sleep(10);
                if (b.length() > 0) {
                    System.out.println("数据:" + b + "长度" + b.length());
                    System.out.println("Ascii转换后:" + StringUtils.AsciiToString(b));
                    break;
                }
            }
            Thread.sleep(50);
        }


        Tools.ClosePort(serialPortManager,serialPort);
  • 结果
    在这里插入图片描述

四、注意

  1. 读取数据的字不要太长,虽然手册上说可为120个字,但个人建议20字以内(太大会出现意外)
  2. CRC 校验注意高低位问题
  3. 执行每个命令(读卡号,写数据)最好使线程休眠一段时间,太快会造成问题。
  4. 必须使用Java1.8(jdk1.8.0_20)及下

五、参考文献及资源

参考文献

使用Java实现串口通信(二)

RTXT

资源下载

RXTX

java1.8

UHF电子标签读写模块UHFReader09用户手册v1.1

基于java的图书管理系统(RFID)(实训项目)

基于java的图书管理系统(RFID)sql(实训项目)

LJYN-02(端口通信demo)

  • 5
    点赞
  • 23
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值