Modbus ASCII LRC生成

Modbus ASCII的报文生成顺序为:

1、生成PDU

2、生成LRC校验码,将LRC附加到PDU后面

3、将2中的数组转换成HEX格式的文本

4、在HEX格式文本的0位置插入冒号,在HEX格式文本的后面附加Windows换行符

生成LRC的公式为:LRC = - sum(PDU)

以下为LRC校验码生成算法的通用性示范:

/**将HEX格式的数据流包装成字符串对象*/
	public static final int getLRC8FromAscIIBytes(byte[] hex, int first, int last) {
		String hexString = new String(hex, Math.min(first, last), Math.max(first, last) + 1);
		return getLRC8FromAscIIBytes(hexString, 0, hexString.length() - 1);
	}

/**将字符串对象解码为Modbus数据*/
	public static int getLRC8FromAscIIBytes(String hex, int first, int last) {
		if (hex == null || hex.isEmpty()) {
			return 0;
		}
		String subHex = hex.substring(Math.min(first, last), Math.max(first, last) + 1);
		byte[] bytes = convertHexStringToBytes(subHex);
		if (first < last) {
			return getLRC8FromRealBytes(bytes, 0, bytes.length - 1);
		} else {
			return getLRC8FromRealBytes(bytes, bytes.length - 1, 0);
		}
	}

/**将Modbus数据求和,变为负数,返回低字节,即Modbus ASCII LRC8校验码的值*/
	public static final int getLRC8FromRealBytes(byte[] bytes, int first, int last) {
		if (bytes == null) {
			return 0;
		}
		return (-getADD8(bytes, first, last)) & 0xff;
	}

/**求和函数*/
	public static final int getADD8(byte[] bytes, int first, int last) {
		if (bytes == null) {
			return 0;
		}
		byte result = 0;
		int step = (first < last) ? 1 : -1;
		for (int i = first; i != last + step; i += step) {
			result += bytes[i];
		}
		return result & 0xff;
	}

需要注意的是,这里的函数专门用于Modbus ASCII校验,不同的通信规约中对LRC的定义可能不一样。LRC8是对字节统计求和校验的包装,包装的方法不唯一。对Modbus ASCII而言,包装的目的在于使有效报文字节(排除掉首字节和Windows换行符共3个字节的常量部分)的统计和为0。这一点也体现在Modbus RTU的CRC16校验上。

一些相关问题

为什么Modbus TCP不需要这种归零校验码?

归零校验码的作用在于快速确定报文是否结束,而无需等待最后一步超时。Modbus TCP带有报文长度信息,所以不需要归零。另外,TCP层自带通信数据校验,其可靠性强于应用层及会话层的校验,因此Modbus TCP的应用层规约中没有校验的规定。但由于尾部空闲数据区未进行封闭性的定义,开发者也可以自己增加几个字节的校验码,甚至可将MD5放到后面,这样即有校验码又能兼容不做校验的程序。

为什么有了归零校验码,Modbus ASCII仍然需要需要Windows换行符来结尾?

这样可以兼容一些缓冲字符流。比如Java中的BufferedReader就需要这个换行符才能知道这段报文已经结束了。至于为什么是Windows换行符,那是因为Windows换行符可以兼容Linux和iOS,反之则不能通用。另外,几乎所有上位机工业软件都运行于Windows系统,采用Windows换行符是大势所趋。使用Windows换行符来作为结束符无可厚非,但Mosbus ASCII报文的起始符是一个败笔。单一字节的起始符可能无法兼容一些PLC。比如欧姆龙PLC要求起始符必须是两个字节。一种简单粗暴的解决办法是在起始符前面添加一个不同于起始符的字节(比如添加一个空格或空字符)凑成两个字节。

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值