基于串行链路的 Modbus 通信需要进行差错チェック,根据传输モード(ASCII 或 RTU)的不同,差错チェック域采用不同的チェック方法。
- ASCII モード —— チェック字段由2つ文字组成,其值是基于对すべて报文内容执行 LRC check(Longitudinal Redundancy Check,纵向冗余チェック)的計算结果。計算对象不包括起始的冒号(
:)和回车换行符号(CRLF)。 - RTU モード —— チェック字段由 16 个比特位(两バイト単位。)组成,其值是基于对すべて报文内容执行 CRC check(Cyclical Redundancy Check,循环冗余チェック)的計算结果。計算对象包括チェック域之前的すべてのバイト。
LRC check
LRC チェック比较简单,它在 ASCII 协议で使用する。,检测了メッセージ域中除始まりました。冒号及结束的回车换行号外的内容。它仅仅是把每一个需要传输的データ按バイト叠加(丢弃すべての进位),然后对结果进行二进制补码操作。
下面是 LRC チェック的具体代码:
unsigned char LRC(unsigned char *auchMsg, unsigned short usDataLen)
{
unsigned char uchLRC = 0;
while (usDataLen--)
uchLRC += *auchMsg++;
return ((unsigned char)(-((char)uchLRC)));
}从算法本质来说,LRC 域本身仅占 1 バイト単位。,但在 ASCII モード传递メッセージフレーム时,LRC 值被编码为 2 バイト単位。的 ASCII characters。例如,計算得到的 LRC 值为 0xF3,那么在 ASCII メッセージフレーム中表示为 'F' 和 '3' 2つ文字。
CRC verification
CRC 域是两バイト単位。,包含一个 16 位的二进制值。它由传输デバイス計算后加入到メッセージ中。受信デバイス重新計算收到メッセージ的 CRC,并与受信到的 CRC 域中的值比较,もし两值不同,则有误。
CRC 是先调入一值是全“1”的 16 位レジスタ,然后调用一过程将メッセージ中连续的 8 位バイト各当前レジスタ中的值进行処理。仅每个文字中的 8 ビット·データ对 CRC effective,スタート地点。和ストップ·ビット以及パリティ検査位均无效。 CRC 产生过程中,每个 8 位文字都单独和レジスタ内容相或(OR),结果向最低有效位方向移動,最高有效位以 0 填充。LSB 被提取出来检测,もし LSB 为 1,レジスタ单独和预置的值或一下,もし LSB 为 0,则不进行。整个过程要重复 8 次。在最后一位(No. 8 位)完成后,下一个 8 位バイト又单独和レジスタ的当前值相或。最终レジスタ中的值,是メッセージ中すべての的バイト都执行之后的 CRC 值。
下面是 CRC verification的具体代码:
unsigned short CRC16(unsigned char *puchMsg, unsigned short usDataLen)
{
int i, j;
unsigned short usRegCRC = 0xFFFF;
for (i=0; i<usDataLen; i++)
{
usRegCRC ^= *puchMsg++;
for (j=0; j<8; j++)
{
if (usRegCRC & 0x0001)
usRegCRC = usRegCRC >> 1 ^ 0xA001;
else
usRegCRC >>= 1;
}
}
return usRegCRC;
}在 Modbus RTU モード中,规定了在メッセージフレーム传递时 CRC verification值必须按低バイト数前に,ハイバイト在后的顺序。例如,計算得到的 CRC 值为 0xCA31,那么送信顺序为 0x31、0xCA。
上面的 CRC16 計算方法并ではない最优的,因为它需要大量的运算,只適用される对速度不敏感的场合。对运算速度有要求的,可以采用查表法得到チェック值,是一种以空间换时间的策略。
Leave a Reply