首頁 > 軟體

CRC校驗原理及其C語言實現詳解

2023-03-11 06:02:10

前言

最近的工作中,要實現對通訊資料的CRC計算,所以花了兩天的時間好好研究了一下,週末有時間整理了一下筆記。

一個完整的資料框通常由以下部分構成:

校驗位是為了保證資料在傳輸過程中的完整性,採用一種指定的演演算法對原始資料進行計算,得出的一個校驗值。接收方接收到資料時,採用同樣的校驗演演算法對原始資料進行計算,如果計算結果和接收到的校驗值一致,說明資料校驗正確,這一幀資料可以使用,如果不一致,說明傳輸過程中出現了差錯,這一幀資料丟棄,請求重發。

常用的校驗演演算法有奇偶校驗、校驗和、CRC,還有LRC、BCC等不常用的校驗演演算法。

以串列埠通訊中的奇校驗為例,如果資料中1的個數為奇數,則奇校驗位0,否則為1。

例如原始資料為:0001 0011,資料中1的個數(或各位相加)為3,所以奇校驗位為0。這種校驗方法很簡單,但這種校驗方法有很大的誤位元速率。假設由於傳輸過程中的干擾,接收端接收到的資料是0010 0011,通過奇校驗運算,得到奇校驗位的值為0,雖然校驗通過,但是資料已經發生了錯誤。

校驗和同理也會有類似的錯誤:

一個好的校驗校驗方法,配合數位訊號編碼方式,如(差分)曼徹斯特編碼,(不)歸零碼等對資料進行編碼,可大大提高通訊的健壯性和穩定性。例如乙太網中使用的是CRC-32校驗,曼徹斯特編碼方式。本篇文章介紹CRC校驗的原理和實現方法。

CRC演演算法簡介

迴圈冗餘校驗(Cyclic Redundancy Check, CRC)是一種根據網路封包或計算機檔案等資料產生簡短固定位數校驗碼的一種通道編碼技術,主要用來檢測或校驗資料傳輸或者儲存後可能出現的錯誤。它是利用除法及餘數的原理來作錯誤偵測的。

CRC校驗計算速度快,檢錯能力強,易於用編碼器等硬體電路實現。從檢錯的正確率與速度、成本等方面,都比奇偶校驗等校驗方式具有優勢。因而,CRC 成為計算機資訊通訊領域最為普遍的校驗方式。常見應用有乙太網/USB通訊,壓縮解壓,視訊編碼,影象儲存,磁碟讀寫等。

CRC引數模型

不知道你是否遇到過這種情況,同樣的CRC多項式,呼叫不同的CRC計算函數,得到的結果卻不一樣,而且和手算的結果也不一樣,這就涉及到CRC的引數模型了。計算一個正確的CRC值,需要知道CRC的引數模型。

一個完整的CRC引數模型應該包含以下資訊:WIDTH,POLY,INIT,REFIN,REFOUT,XOROUT。

NAME:引數模型名稱。

WIDTH:寬度,即生成的CRC資料位寬,如CRC-8,生成的CRC為8位元

POLY:十六進位制多項式,省略最高位1,如 x8 + x2 + x + 1,二進位制為1 0000 0111,省略最高位1,轉換為十六進位製為0x07。

INIT:CRC初始值,和WIDTH位寬一致。

REFIN:true或false,在進行計算之前,原始資料是否翻轉,如原始資料:0x34 = 0011 0100,如果REFIN為true,進行翻轉之後為0010 1100 = 0x2c

REFOUT:true或false,運算完成之後,得到的CRC值是否進行翻轉,如計算得到的CRC值:0x97 = 1001 0111,如果REFOUT為true,進行翻轉之後為11101001 = 0xE9。

XOROUT:計算結果與此引數進行互斥或運算後得到最終的CRC值,和WIDTH位寬一致。

通常如果只給了一個多項式,其他的沒有說明則:INIT=0x00,REFIN=false,REFOUT=false,XOROUT=0x00。

常用的21個標準CRC引數模型:

CRC校驗在電子通訊領域非常常用,可以說有通訊存在的地方,就有CRC校驗:

  • 美信(MAXIM)的晶片DS2401/DS18B20,都是使用的CRC-8/MAXIM模型
  • SD卡或MMC使用的是CRC-7/MMC模型
  • Modbus通訊使用的是CRC-16/MODBUS引數模型
  • USB協定中使用的CRC-5/USB和CRC-16/USB模型
  • STM32自帶的硬體CRC計算模組使用的是CRC-32模型

至於多項式的選擇,初始值和互斥或值的選擇,輸入輸出是否翻轉,這就涉及到一定的編碼和數學知識了。感興趣的朋友,可以瞭解一下每個CRC模型各個引數的來源。至於每種引數模型的檢錯能力、重複率,需要專業的數學計算了,不在本文討論的範疇內。

CRC計算

好了,瞭解了CRC引數模型知識,下面手算一個CRC值,來了解CRC計算的原理。

問:原始資料:0x34,使用CRC-8/MAXIN引數模型,求CRC值?

答:根據CRC引數模型表,得到CRC-8/MAXIN的引數如下:

POLY = 0x31 = 0011 0001(最高位1已經省略)
INIT = 0x00
XOROUT = 0x00
REFIN = TRUE
REFOUT = TRUE

有了上面的引數,這樣計算條件才算完整,下面來實際計算:

0.原始資料 = 0x34 = 0011 0100,多項式 = 0x31 = 1 0011 0001
1.INIT = 00,原始資料高8位元和初始值進行互斥或運算保持不變。
2.REFIN為TRUE,需要先對原始資料進行翻轉:0011 0100 > 0010 1100
3.原始資料左移8位元,即後面補8個0:0010 1100 0000 0000
4.把處理之後的資料和多項式進行模2除法,求得餘數:
原始資料:0010 1100 0000 0000 = 10 1100 0000 0000
多項式:1 0011 0001
模2除法取餘數低8位元:1111 1011
5.與XOROUT進行互斥或,1111 1011 xor 0000 0000 = 1111 1011 
6.因為REFOUT為TRUE,對結果進行翻轉得到最終的CRC-8值:1101 1111 = 0xDF
7.資料+CRC:0011 0100 1101 1111 = 34DF,相當於原始資料左移8位元+餘數。

模2除法求餘數:

驗證手算結果:

可以看出是一致的,當你手算的結果和工具計算結果不一致時,可以看看INIT,XOROUT,REFINT,REFOUT這些引數是否一致,有1個引數不對,計算出的CRC結果都不一樣。

CRC校驗

上面通過筆算的方式,講解了CRC計算的原理,下面來介紹一下如何進行校驗。

按照上面CRC計算的結果,最終的資料框:0011 0100 1101 1111 = 34DF,前8位元0011 0100是原始資料,後8位元1101 1111 是 CRC結果。

接收端的校驗有兩種方式,一種是和CRC計算一樣,在本地把接收到的資料和CRC分離,然後在本地對資料進行CRC運算,得到的CRC值和接收到的CRC進行比較,如果一致,說明資料接收正確,如果不一致,說明資料有錯誤。

另一種方法是把整個資料框進行CRC運算,因為是資料框相當於把原始資料左移8位元,然後加上餘數,如果直接對整個資料框進行CRC運算(除以多項式),那麼餘數應該為0,如果不為0說明資料出錯。

而且,不同位出錯,餘數也不同,可以證明,餘數與出錯位數的對應關係只與CRC引數模型有關,而與原始資料無關。

CRC計算的C語言實現

無論是用C還是其他語言,實現方法網上很多,這裡我找了一個基於C語言的CRC計算庫,裡面包含了常用的21個CRC引數模型計算函數,可以直接使用,只有crcLib.ccrcLib.h兩個檔案。

GitHub地址:https://github.com/whik/crc-lib-c

Gitee地址:https://gitee.com/whik/crc-lib-c

使用方法非常簡單:

#include <stdio.h>
#include <stdlib.h>
#include "crcLib.h"

int main()
{
    uint8_t LENGTH = 10;
    uint8_t data[LENGTH];
    uint8_t crc;

    for(int i = 0; i < LENGTH; i++)
    {
        data[i] = i*5;
        printf("%02x ", data[i]);
    }
    printf("n");

    crc = crc8_maxim(data, LENGTH);

    printf("CRC-8/MAXIM:%02xn", crc);
    return 0;
}

計算結果:

CRC計算工具

下面這幾款工具都可以自定義CRC演演算法模型,而且都有標準CRC模型可供選擇。如果自己用C語言或者Verilog實現校驗演演算法時,非常適合作為標準答案進行驗證。

線上計算:www.ip33.com/crc.html

離線計算工具:CRC_Calc v0.1.exe或者GCRC.exe

格西CRC計算器:

總結

CRC校驗並不能100%的檢查出資料的錯誤,非常低的概率會出現CRC校驗正確但資料中有錯誤位的情況。這和CRC的位數,多項式的選擇等等有很大的關係,所以在實際使用中儘量選擇標準CRC引數模型,這些多項式引數都是經過理論計算得出的,可以提高CRC的檢錯能力。CRC校驗可以檢錯,也可以糾正單一位元的錯誤,你知道糾錯的原理嗎?

以上就是CRC校驗原理及其C語言實現詳解的詳細內容,更多關於C語言 CRC校驗的資料請關注it145.com其它相關文章!


IT145.com E-mail:sddin#qq.com