Modbus软件开发实战指南
上QQ阅读APP看书,第一时间看更新

3.4.1 LRC校验

在ASCII模式中,消息是由特定的字符作为帧头和帧尾来分隔的。

一条消息必须以“冒号”(:)字符(ASCII码为0x3A)开始,以“回车换行”(CRLF)(ASCII码为0x0D和0x0A)结束。LRC校验算法的计算范围为(:)与(CRLF)之间的字符。

从算法本质来说,LRC域自身为1个字节,即包含一个8位二进制数据,由发送设备通过LRC算法计算,并把计算值附到信息末尾。接收设备在接收信息时,通过LRC算法重新计算值,并把计算值与LRC字段中接收的实际值进行比较。若两者不同,则产生一个错误,返回一个异常响应帧。即对报文中的所有相邻2个8位字节相加,丢弃任何进位,然后对结果进行二进制补码,计算出LRC值。

必须注意的是,计算LRC校验码的时机,是在对报文中每个原始字节进行ASCII码编码之前,对每个原始字节进行LRC校验的计算操作。

生成LRC校验值的过程如下:

(1)对消息帧中的全部字节相加(不包括起始“:”和结束符“CR-LF”),并把结果送入8位数据区,舍弃进位。

(2)由0xFF(即全1)减去最终的数据值,产生1的补码(即二进制反码)。

(3)加“1”产生二进制补码。

以上产生的LRC值占用1个字节,但实际上在通过串行链路由ASCII模式传递消息帧的时候,LRC的结果(1个字节)被编码为2个字节的ASCII字符,并将其放置在ASCII模式报文帧的CR-LF字段之前。

Modbus标准协议英文版提供了LRC的算法。其中参数意义如下:

unsigned char * auchMsg;含有生成LRC所使用的二进制数据的报文缓存区指针。

unsigned short usDataLen;报文缓存区中的字节数。

LRC的详细代码如下:

 1  / * 函数返回 unsigned char 类型的LRC值 * /
 2  static unsigned char LRC(unsigned char * auchMsg, unsigned short usDataLen)
 3  {
 4      unsigned char uchLRC =0;                       / * LRC字节初始化 * /
 5
 6      while (usDataLen--)                           / * 遍历报文缓冲区 * /
 7          uchLRC += * auchMsg++; / * 缓冲区字节相加,自动舍弃进位 * /
 8
 9      return ((unsigned char)(-(( char)uchLRC))) ; / * 返回二进制补码 * /
10  }

这里举一个简单的例子。假设从设备地址为1,要求读取输入寄存器地址30001的值,则具体的查询消息帧如下:

“:”,“0”,“1”,“0”,“4”,“0”,“0”,“0”,“0”,“0”,“0”,“0”,“1”,“F”,“A”, CR/LF

其中,“F”、“A”即为LRC值在ASCII模式下的形式,即0xFA。