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。