因为在做项目的时候,遇到过一种情况 站号为0 ,如果用modbus协议的时候。无法正常发收数据,所以自己做了个对类似modbus发送的报文拼接,由于在网上找的相关LRC的校验,很多有算出来的数据对应不上,然后自己写了一个,如有不足,后续进行修改
3A 30 30 30 36 31 30 30 43 30 30 30 31 44 44 0D 0A
红色部分为站号
绿色部分为功能码
蓝色部分为地址码
紫色部分为数据
import purejavacomm.NoSuchPortException;
import purejavacomm.PortInUseException;
import purejavacomm.SerialPort;
import purejavacomm.UnsupportedCommOperationException;
import java.io.ByteArrayOutputStream;
import java.util.Scanner;
/**
* @author
* @title:
* @projectName
* @description: TODO
* @date 2021/06/15 001515:07
*/
public class Util {
//地址码的长度
private static int ADDRESS_DIGITS = 4;
//数据位的长度
private static int DATA_DIGITS = 4;
private static int SLAVE_DIGITS = 3;
private static int CODE = 6;
private static int CODE_DIGITS = 1;
public static void main(String[] args) {
//
byte[] sendbytes=sendData(0,1,4180);
}
/**
*
* 站号 支持 如30 30 30 三位
* 数据位 30 30 30 31 四位 如果想修改支持的数据位 在代码里面相关数组容量进行修改
*
* @param slave
* @param datanum
* @return
*/
public static byte[] sendData(int slave, int datanum, int address) {
//---------------地址处理
String addressStr = intToHexStr(address, ADDRESS_DIGITS);
byte[] addressByte = hexStrToBytes(addressStr, ADDRESS_DIGITS);
//---------------站号的处理
String slaveStr = intToHexStr(slave, SLAVE_DIGITS);
byte[] slaveByte = hexStrToBytes(slaveStr, SLAVE_DIGITS);
//----------------数据的处理
String dataStr = intToHexStr(datanum, DATA_DIGITS);
byte[] dataByte = hexStrToBytes(dataStr, DATA_DIGITS);
//3A 30 30 30 36 31 30 30 43 30 30 30 31 44 44 0D 0A
//36->rtu 的 06功能码
//31 30 30 43 ——>rtu 100C ——>地址码 4180(des)
//----------------------------功能码
String codeStr = intToHexStr(CODE, CODE_DIGITS);
byte[] code = hexStrToBytes(codeStr, CODE_DIGITS);
byte[] codeAndAddress = merge(code, addressByte);
byte[] start = new byte[]{0x3A};
byte[] openByte = merge(start, merge(slaveByte, codeAndAddress));
//--------------------------------lrc
String hex = slaveStr + codeStr + addressStr + dataStr;
byte[] dataLrc = getLrc(decode(hex));
byte[] startDataBytes = merge(openByte, dataByte);
//开头+lrc
byte[] dataAndLrc = merge(startDataBytes, dataLrc);
//加上结尾
byte[] endbytes = new byte[]{0x0D, 0x0A};
byte[] sendBytes = merge(dataAndLrc, endbytes);
return sendBytes;
}
/**
* 把字符串转换成字节数组
*
* @param hexString
* @return
*/
public static byte[] hexString2Bytes(String hexString) {
if (hexString == null || hexString.equals("")) {
return null;
}
hexString = hexString.toUpperCase();
int length = hexString.length() / 2;
char[] hexChars = hexString.toCharArray();
byte[] d = new byte[length];
for (int i = 0; i < length; i++) {
int pos = i * 2;
d[i] = (byte) (char2Byte(hexChars[pos]) << 4 | char2Byte(hexChars[pos + 1]));
}
return d;
}
private static byte char2Byte(char c) {
return (byte) "0123456789ABCDEF".indexOf(c);
}
public static final String toHex(byte b) {
return ("0x" + "0123456789ABCDEF".charAt(0xf & b >> 4) + "0123456789ABCDEF".charAt(b & 0xf));
}
/**
* 把byte[]转成char[]
*
* @param bytes
* @return
*/
public static char[] bytesToChars(byte[] bytes) {
String s = new String(bytes);
char chars[] = s.toCharArray();
return chars;
}
public static int parse(String str) {
//32位 为负数
if (32 == str.length()) {
str = "-" + str.substring(1);
return -(Integer.parseInt(str, 2) + Integer.MAX_VALUE + 1);
}
return Integer.parseInt(str, 2);
}
/**
* 字符串转二进制数组
*
* @param str
* @return
*/
public static byte[] lrcStrToBytes(String str) {
byte[] bytes1 = str.getBytes();
StringBuilder binary1 = new StringBuilder();
for (byte b : bytes1) {
int val = b;
for (int i = 0; i < 8; i++) {
binary1.append((val & 128) == 0 ? 0 : 1);
val <<= 1;
}
// binary.append(' ');
}
String[] binaryStr1 = binary1.toString().split(",");
byte[] byteArray1 = new byte[binaryStr1.length];
for (int i = 0; i < byteArray1.length; i++) {
byteArray1[i] = (byte) parse(binaryStr1[i]);
}
return byteArray1;
}
/**
* 字符串转16进制字符串
*
* @param str
* @return
*/
public static String convertStringToHex(String str) {
char[] chars = str.toCharArray();
StringBuffer hex = new StringBuffer();
for (int i = 0; i < chars.length; i++) {
hex.append(Integer.toHexString((int) chars[i]));
}
return hex.toString();
}
/**
* str 转strLength位字符串 不足补0
*
* @param str
* @param strLength
* @return
*/
public static String strtoLengthstr(String str, int strLength) {
int strLen = str.length();
if (strLen < strLength) {
while (strLen < strLength) {
StringBuffer sb = new StringBuffer();
sb.append("0").append(str);//左补0
// sb.append(str).append("0");//右补0
str = sb.toString();
strLen = str.length();
}
}
return str;
}
/**
* 合并数组
*
* @param startbytes
* @param endbytes
* @return
*/
public static byte[] merge(byte[] startbytes, byte[] endbytes) {
ByteArrayOutputStream sendData = new ByteArrayOutputStream();
sendData.write(startbytes, 0, startbytes.length);
sendData.write(endbytes, 0, endbytes.length);
byte[] bytes = sendData.toByteArray();
return bytes;
}
/**
* 获取lrc校验
*
* @param hex 3030.....的数据
* @return
*/
public static byte[] getLrc(String hex) {
String javaStr = makeChecksum(hex);
byte[] bytes = parseHexStr2Byte(javaStr);
byte temp;
for (int i = 0; i < bytes.length; i++) {
temp = bytes[i];
bytes[i] = (byte) (~temp);
}
String bths = parseByte2HexStr(bytes);
String lrc = makeChecksum(bths + "01").toUpperCase();
String lrc1 = lrc.substring(0, 1).toUpperCase();
String lrc2 = lrc.substring(1, 2).toUpperCase();
byte[] byteArray1 = lrcStrToBytes(lrc1);
byte[] byteArray2 = lrcStrToBytes(lrc2);
//lrc 校验数组
byte[] dataLrc = merge(byteArray1, byteArray2);
return dataLrc;
}
/**
* 十六进制字符串 -----》10进制字符串
*
* @param bytes
* @return
*/
public static String decode(String bytes) {
String hexString = "0123456789ABCDEF";
ByteArrayOutputStream baos = new ByteArrayOutputStream(
bytes.length() / 2);
// 将每2位16进制整数组装成一个字节
for (int i = 0; i < bytes.length(); i += 2)
baos.write((hexString.indexOf(bytes.charAt(i)) << 4 | hexString
.indexOf(bytes.charAt(i + 1))));
return new String(baos.toByteArray());
}
/**
* 16进制求和
*
* @param data
* @return
*/
public static String makeChecksum(String data) {
if (data == null || data.equals("")) {
return "";
}
int total = 0;
int len = data.length();
int num = 0;
while (num < len) {
String s = data.substring(num, num + 2);
total += Integer.parseInt(s, 16);
num = num + 2;
}
/**
* 用256求余最大是255,即16进制的FF
*/
int mod = total % 256;
String hex = Integer.toHexString(mod);
len = hex.length();
// 如果不够校验位的长度,补0,这里用的是两位校验
if (len < 2) {
hex = "0" + hex;
}
return hex.toUpperCase();
}
/**
* 将二进制转换成16进制
*
* @param buf
* @return
*/
public static String parseByte2HexStr(byte buf[]) {
StringBuffer sb = new StringBuffer();
for (int i = 0; i < buf.length; i++) {
String hex = Integer.toHexString(buf[i] & 0xFF);
if (hex.length() == 1) {
hex = '0' + hex;
}
sb.append(hex.toUpperCase());
}
return sb.toString();
}
/**
* 将16进制转换为二进制
*
* @param hexStr
* @return
*/
public static byte[] parseHexStr2Byte(String hexStr) {
if (hexStr.length() < 1)
return null;
byte[] result = new byte[hexStr.length() / 2];
for (int i = 0; i < hexStr.length() / 2; i++) {
int high = Integer.parseInt(hexStr.substring(i * 2, i * 2 + 1), 16);
int low = Integer.parseInt(hexStr.substring(i * 2 + 1, i * 2 + 2),
16);
result[i] = (byte) (high * 16 + low);
}
return result;
}
/**
* int --->16进制字符串
*
* @param num
* @param length
* @return
*/
public static String intToHexStr(int num, int length) {
String hexStr = Integer.toHexString(num).toUpperCase();
String completionStr = strtoLengthstr(hexStr, length);
String dataStr = "";
for (int i = 0; i < length; i++) {
dataStr += convertStringToHex(completionStr.substring(i, i + 1));
}
return dataStr;
}
/**
* 16进制字符串转byte数组
*
* @param dataStr
* @param length
* @return
*/
public static byte[] hexStrToBytes(String dataStr, int length) {
byte[] bytes = new byte[length];
for (int i = 0; i < length; i++) {
String dataStrPT = decode(dataStr.substring(i * 2, i * 2 + 2));
bytes[i] = lrcStrToBytes(dataStrPT)[0];
}
return bytes;
}
}
还有不足 后续还会继续修改