Elektroda.pl
Elektroda.pl
X
Proszę, dodaj wyjątek dla www.elektroda.pl do Adblock.
Dzięki temu, że oglądasz reklamy, wspierasz portal i użytkowników.

CRC 16 Modbus - sprawdzenie algorytmu

30 Maj 2013 20:24 2673 5
  • Poziom 12  
    Witam,

    Analizując generowanie kodu CRC16 dla protokołu Modbus natknąłem się na powszechnie znany i sprawdzony algorytm, który nawet po próbach "ręcznego" rozwiązywania przynosi rezultaty inne od sprawdzonych wyników. Mniemam, że którąś czynność wykonuje źle, przez co wyniki są niepoprawne.

    Korzystam z przedstawionego poniżej algorytmu wyrażonego w funkcji, która korzysta dodatkowo z dwóch tablic zawierających kombinacje dla starszego i młodszego bajtu.

    Kod: cpp
    Zaloguj się, aby zobaczyć kod


    Tablice:

    Kod: cpp
    Zaloguj się, aby zobaczyć kod


    Nie analizując szczególnie kodu, chciałbym przedstawić swój sposób pojmowania powyższego algorytmu. Obliczyłem ręcznie kod CRC dla liczby 0x22, jej wynik powinien wynosić 0x3f59. Jednakowoż u mnie wynosi on 0x8111. Chciałbym jedynie porady, w którym momencie wkrada się do moich obliczeń błąd.

    Obliczenia:

    while (NumberOfBytes--)
    {
    Index = HiByte ^ (FromAsciitoHexValue(pMessage));
    pMessage+=1;
    HiByte = LoByte ^ aCRCHi[Index];
    LoByte = aCRCLo[Index];
    };

    index = 0xFF xor 0x2,//wyznaczamy indeks wartości z tablicy na podstawie pierwszego bajtu wiadomości, dla której obliczamy CRC

    index=0xfD, czyli 253dec
    HiByte=0xff xor aCRCHi[253], czyli 0xff xor 0xc1=0x3e

    LoByte=aCRCLo[253], czyli 0x81

    Następnie liczymy to samo dla drugiego bajtu wiadomości, czyli dla wartości 0x2(badaną wartością jej 0x22).

    index=0x3e xor 0x2=0x3c,czyli 60dec
    HiByte=0x81 xor aCRCHi[60], czyli 0x81 xor 0x00=0x81
    LoByte=aCRCLo[60]=0x11

    (HiByte << 8) | LoByte = 0x8111
  • Poziom 17  
    main88 napisał:
    Obliczyłem ręcznie kod CRC dla liczby 0x22, jej wynik powinien wynosić 0x3f59. Jednakowoż u mnie wynosi on 0x8111

    Mi wyszlo: 0x1181 :)

    A tak na serio:
    akurat dla liczy 0x22 wynik powinien byc 0x593f (ale to pewnie kwestia reprezentacji).

    Użyłem tego kodu:
    Kod: cpp
    Zaloguj się, aby zobaczyć kod
  • Poziom 12  
    Odwróciłeś bajty wyniku, do tego też była jakaś reguła. Ale według wszystkich kalkulatorów CRC wynik powinien wynosić 3F59. Być może algorytm jest źle skonstruowany.
  • Pomocny post
    Poziom 17  
    Patrz wyżej, zamieściłem kod, który daje poprawny wynik (z dokładnością do endianessu).

    Dodano po 6 [minuty]:

    Bład masz logiczny...
    0x22 to jeden bajt a ty rozpisałeś to tak jakby były dwa bajty 0x2 czyli 0x0202. Badaną wartościa jest 0x22 i jest to jeden bajt.
  • Poziom 12  
    Dzięki za programik, który wrzuciłeś. Ma inną tablicę bajtów, a algorytm podobny. Dobrze wylicza wartości typu 0x0, 0x22, ale z większą ilością bajtów nie radzi sobie i wynik oblicza źle , np. 0x3567 wynik powinien wynosić 0x570a a wg tego programu jest to 0x802b. Wobec tego, nie wiem czy algorytm jest poprawny.

    Dodano po 1 [godziny] 39 [minuty]:

    Kod poprawiony, działa dobrze. Problem był tak jak kolega wspomniał, jeden bajt traktowany był jak dwa osobne. Dodatkowo trzeba było dopisać składanie dwóch char-ów w jeden hex. Tablice pozostały te same.

    Kod: cpp
    Zaloguj się, aby zobaczyć kod
  • Poziom 17  
    main88 napisał:
    z większą ilością bajtów nie radzi sobie i wynik oblicza źle , np. 0x3567 wynik powinien wynosić 0x570a a wg tego programu jest to 0x802b. Wobec tego, nie wiem czy algorytm jest poprawny.

    Oczywiście, że sobie radzi, musisz coś źle robić:
    Zmieniłem main na coś takiego:
    Kod: cpp
    Zaloguj się, aby zobaczyć kod


    I policzył dobrze dla 0x3567 czyli 0x0a57. Więc znów błąd gdzieś u Ciebie był!