基于串行链路的 Modbus 통신需要进行差错체크섬,根据传输모드(ASCII 或 RTU)的不同,差错체크섬域采用不同的체크섬方法。
- ASCII 모드 —— 체크섬필드由两个문자组成,其值是基于对전체프레임콘텐츠执行 LRC 체크섬(Longitudinal Redundancy Check,LRC 체크섬)的계산 결과。계산对象不包括시작的콜론(
:)和줄바꿈(CRLF)符号(CRLF)。 - RTU 모드 —— 체크섬필드由 16 个比特位(两个바이트)组成,其值是基于对전체프레임콘텐츠执行 CRC 체크섬(Cyclical Redundancy Check,循环冗余체크섬)的계산 결과。계산对象包括체크섬域之前的所有바이트。
LRC 체크섬
LRC 체크섬比较简单,它在 ASCII 프로토콜中使用,检测了消息域中除开始的콜론及종료的줄바꿈(CRLF)号外的콘텐츠。它仅仅是把每一个需要传输的데이터按바이트叠加(丢弃所有进位),然后对结果进行2진수补码操作。
下面是 LRC 체크섬的具体代码:
unsigned char LRC(unsigned char *auchMsg, unsigned short us데이터Len)
{
unsigned char uchLRC = 0;
while (us데이터Len--)
uchLRC += *auchMsg++;
return ((unsigned char)(-((char)uchLRC)));
}从算法本质来说,LRC 域本身仅占 1 个바이트,但在 ASCII 모드传递消息帧时,LRC 值被编码为 2 个바이트的 ASCII 문자。例如,계산得到的 LRC 值为 0xF3,那么在 ASCII 消息帧中表示为 'F' 和 '3' 两个문자。
CRC 검증
CRC 域是两个바이트,包含一个 16 位的2진수值。它由传输设备계산后加入到消息中。수신设备重新계산收到消息的 CRC,并与수신到的 CRC 域中的值比较,如果两值不同,则有误。
CRC 是先调入一值是全“1”的 16 位레지스터,然后调用一过程将消息中连续的 8 位바이트各当前레지스터中的值进行处理。仅每个문자中的 8 位데이터对 CRC 有效,시작位和정지 비트以及奇偶패리티均无效。 CRC 产生过程中,每个 8 位문자都单独和레지스터콘텐츠相或(OR),结果向最低有效位方向移动,最高有效位以 0 填充。LSB 被提取出来检测,如果 LSB 为 1,레지스터单独和预置的值或一下,如果 LSB 为 0,则不进行。整个过程要重复 8 次。在最后一位(第 8 位)完成后,下一个 8 位바이트又单独和레지스터的当前值相或。最终레지스터中的值,是消息中所有的바이트都执行之后的 CRC 值。
下面是 CRC 검증的具体代码:
unsigned short CRC16(unsigned char *puchMsg, unsigned short us데이터Len)
{
int i, j;
unsigned short usRegCRC = 0xFFFF;
for (i=0; i<us데이터Len; i++)
{
usRegCRC ^= *puchMsg++;
for (j=0; j<8; j++)
{
if (usRegCRC & 0x0001)
usRegCRC = usRegCRC >> 1 ^ 0xA001;
else
usRegCRC >>= 1;
}
}
return usRegCRC;
}在 Modbus RTU 모드中,规定了在消息帧传递时 CRC 검증值必须按低바이트在前,高바이트在后的顺序。例如,계산得到的 CRC 值为 0xCA31,那么보내기顺序为 0x31、0xCA。
上面的 CRC16 계산方法并不是最优的,因为它需要大量的运算,只适用于对速度不敏感的场合。对运算速度有要求的,可以采用查表法得到체크섬值,是一种以空间换时间的策略。
답글 작성