CRC-16(迴圈冗餘錯誤校正)
CRC-16錯誤檢查器如下:報文(此處只涉及資料位元,不指起始位、停止位和任選的同位位元)被看作是一個連續的二進位,其最高有效位(MSB)首選發送。報文先與X↑16相乘(左移16位),然後除X↑16+X↑15+X↑2+1,X↑16+X↑15+X↑2+1可以表示為位元11000000000000101。整數商位忽略不記,16位餘數加入該報文(MSB先發送),成為2個CRC校正位元組。餘數中的1全部初始化,以免所有的零成為一條報文被接收。經上述處理而含有CRC位元組的報文,若無錯誤,到接收裝置後再被同一多項式(X↑16+X↑15+X↑2+1)除,會得到一個零餘數(接收裝置核驗這個CRC位元組,並將其與被傳送的CRC比較)。全部運算以2為模(無進位)。
習慣於成串發送資料的裝置會首選送出字元的最右位(LSB-最低有效位)。而在產生CRC情況下,發送首位應是被除數的最高有效位MSB。由於在運算中不用進位,為便於操作起見,計算CRC時設MSB在最右位。產生多項式的位序也必須反過來,以保持一致。多項式的MSB略去不記,因其只對商有影響而不影響餘數。
產生CRC-16校正位元組的步驟如下:
①如裝一個16位寄存器,所有數位均為1。
②該16位寄存器的高位位元組與開始8位位元組進行“異或”運算。運算結果放入這個16位寄存器。
③把這個16位寄存器向右移一位。
④若向右(標記位)移出的數位是1,則產生多項式1010000000000001和這個寄存器進行“異或”運算;若向右移出的數位是0,則返回③。
⑤重複③和④,直至移出8位。
⑥另外8位與該十六位寄存器進行“異或”運算。
⑦重複③~⑥,直至該報文所有位元組均與16位寄存器進行“異或”運算,並移位8次。
⑧這個16位寄存器的內容即2位元組CRC錯誤校正,被加到報文的最高有效位。
另外,在某些非ModBus通訊協定中也經常使用CRC16作為校正手段,而且產生了一些CRC16的變種,他們是使用CRC16多項式X↑16+X↑15+X↑2+1,首次裝入的16位寄存器為0000;使用CRC16的反序X↑16+X↑14+X↑1+1,首次裝入寄存器值為0000或FFFFH。
CRC簡單函數如下:
unsigned short CRC16(puchMsg, usDataLen)
unsigned char *puchMsg ; /* 要進行CRC校正的訊息 */
unsigned short usDataLen ; /* 訊息中位元組數 */
{
unsigned char uchCRCHi = 0xFF ; /* 高CRC位元組初始化 */
unsigned char uchCRCLo = 0xFF ; /* 低CRC 位元組初始化 */
unsigned uIndex ; /* CRC迴圈中的索引 */
while (usDataLen--) /* 傳輸訊息緩衝區 */
{
uIndex = uchCRCHi ^ *puchMsgg++ ; /* 計算CRC */
uchCRCHi = uchCRCLo ^ auchCRCHi[uIndex} ;
uchCRCLo = auchCRCLo[uIndex] ;
}
return (uchCRCHi << 8 | uchCRCLo) ;
}
LRC(縱向冗餘錯誤校正)
LRC錯誤校正用於ASCII模式。這個錯誤校正是一個8位位元,可作為2個ASCII十六進位位元組傳送。把十六進位字元轉換成二進位,加上無迴圈進位的二進位字元和二進位補碼結果產生LRC錯誤校正(參見圖)。這個LRC在接收裝置進行核驗,並與被傳送的LRC進行比較,冒號(:)、斷行符號符號(CR)、換行字元(LF)和置入的其他任何非ASCII十六進位字元在運算時忽略不計。LRC方法是將訊息中的8Bit的位元組連續累加,丟棄了進位。
LRC簡單函數如下:
static unsigned char LRC(auchMsg,usDataLen)
unsigned char *auchMsg ; /* 要進行計算的訊息 */
unsigned short usDataLen ; /* LRC 要處理的位元組的數量*/
{ unsigned char uchLRC = 0 ; /* LRC 位元組初始化 */
while (usDataLen--) /* 傳送訊息 */
uchLRC += *auchMsg++ ; /* 累加*/
return ((unsigned char)(-((char_uchLRC))) ;
}