5

長さと一緒にパラメーターとして渡されたデータの CCITT 16 ビット チェックサム値を計算する必要があります。配列 TempStr にテスト データ "123456789" を入力し、null 終端文字を除いた長さの多項式 0x8408 を使用すると、結果文字列 6E90(Hex) が得られます。ヌル終了文字とともに、907A を取得します。多項式を 0x1201 に交換すると、29E2(16 進数) と EFE8(16 進数) という結果が得られます。終端文字はありますが、なしです。

私の質問は次のとおりです。正しい値を取得するには、NULL 終端文字の有無にかかわらず CRC を計算する必要がありますか? アルゴリズムで多項式 0x1201 または逆多項式 0x8408 を使用する必要がありますか? 与えられたデータ 0x29B1 の正しい CRC は? 関数が正しく機能しているかどうかを判断するには、正しい値が必要です。この特定の CRC タイプを計算するアルゴリズムは正しいですか? wData=(unsigned int)0xff & *pData++?? 誰かが私に何が間違っているのか、私の問題を解決する方法を説明できれば、とても感謝しています. ありがとうございました

これは、calculate_CRC16 関数を使用して表示するコードです。

CHAR_t TestStr[] = {"123456789"};
unsigned short CrcTest = calculate_CRC16(TestStr,sizeof(TestStr)-1);
QString CrcDisplay = QString("CrcTest : %1").arg(CrcTest);
ui->txtDebug->setText(CrcDisplay);

これは calculate_CRC16 関数です。

UINT16_t MainWindow::calculate_CRC16(CHAR_t* pData, UINT16_t wLength)
{

  UCHAR_t i;
  UINT16_t wData;
  UINT16_t wCrc = 0xffff;

  if (wLength == 0)
    return (~wCrc);

  do
  {
    for (i=0, wData=(unsigned int)0xff & *pData++; i < 8; i++, wData >>= 1)
    {
        if ((wCrc & 0x0001) ^ (wData & 0x0001))
            wCrc = (wCrc >> 1) ^ CRC_POLY;
        else  wCrc >>= 1;
    }
  } while (--wLength);

  wCrc = ~wCrc;
  wData = wCrc;
  wCrc = (wCrc << 8) | (wData >> 8 & 0xff);

  return (wCrc);
}
4

3 に答える 3

4

の結果0x29b1は、「偽」の CCITT CRC-16 (CRC カタログへのリンク) です。これは明らかにあなたが必要とするものです。カタログから:

width=16 poly=0x1021 init=0xffff refin=false refout=false xorout=0x0000 check=0x29b1 name="CRC-16/CCITT-FALSE"

したがって、ビット反転 ( refin, refoutfalse) はありません。CRC は で初期化され0xffff、後処理されません。

最小限の変更でコードを修正するには:

if (wLength == 0)
    return wCrc;

do
{
    for (i=0, wData=((unsigned int)0xff & *pData++) << 8; i < 8; i++, wData <<= 1)
    {

        if ((wCrc & 0x8000) ^ (wData & 0x8000))
            wCrc = (wCrc << 1) ^ 0x1021;
        else  wCrc <<= 1;
    }
} while (--wLength);

return wCrc & 0xffff;

またはより合理的に行うには:

while (wLength--) {
    wCrc ^= *(unsigned char *)pData++ << 8;
    for (i=0; i < 8; i++)
        wCrc = wCrc & 0x8000 ? (wCrc << 1) ^ 0x1021 : wCrc << 1;
}
return wCrc & 0xffff;
于 2014-01-21T16:06:57.337 に答える
2

見てみると、さまざまな文字列(またはNULの有無にかかわらずチェックするための16進シーケンス)のCRCが計算され ます http://www.lammertbies.nl/comm/info/crc-calculation.html

それによると、計算のために 0x29B1 の値を取得するために、終端のゼロを含めて計算するべきではありません。

下位ビットから開始しているため、「非反転」多項式を使用する必要があります。

問題は、計算で「wCrc」をシフトしているときに間違った方向にシフトしていることだと思います。

言い換えると:

wCrc = (wCrc >> 1) ^ CRC_POLY;

次のようにする必要があります。

wCrc = (wCrc << 1) ^ CRC_POLY;

同様に:

wCrc >>= 1;

次のようにする必要があります。

wCrc <<= 1;

ただし、100%確実ではありません。

于 2014-01-21T08:36:10.367 に答える
1

CRC アルゴリズムにはさまざまなバリエーションがあります。

  • ビットごとの計算とルックアップ テーブル
  • 反映されたバイトと反映されていないバイト (MSbit または LSbit が最初)。
  • メッセージの末尾に拡張ビットを追加するかどうか。

その最後の点は混乱の問題です。CRC 理論に戻ると、CRC は GF(2) の長除算と見なすことができ、結果は長除算の余りになります。基本理論に従って正しい計算を行うには、正しい答えを得るためにメッセージの最後にnゼロ ビットを追加する必要があります。この方法で計算を行う CRC アルゴリズムがあります。

ただし、より一般的な CRC アルゴリズムは別の方法で実行されるため、メッセージの末尾にゼロ ビットを追加する必要はありません。この計算は、「直接アルゴリズム」と呼ばれることがよくあります。このバリアント アルゴリズムを考慮して、アルゴリズムの「初期値」を変更する必要があることを除いて、使用するのがより便利で、機能的に同等です。

CRC-16/CCITT の場合、これは正しい初期値に関して混乱を招き0xFFFFます0x1D0F。おそらく、0xFFFF拡張ビットをメッセージに追加するアルゴリズムの正しい初期値です。「直接アルゴリズム」を使用する場合0x1D0F、同じ結果を得るには、初期値を に設定する必要があります。

したがって、この違いを認識し、インターフェースしているプログラム/システムと相互に連携するために必要な方を使用する必要があります。

参考文献:

于 2015-10-22T00:52:54.477 に答える