Elektroda.pl
Elektroda.pl
X
Please add exception to AdBlock for elektroda.pl.
If you watch the ads, you support portal and users.

[stm32]Modbus i CRC16. Czujnik nie odpowiada.

dziechu 31 May 2012 00:47 5767 13
  • #1
    dziechu
    Level 27  
    Musze połączyć się z czujnikami pracującymi na magistrali Modbus.
    Ponieważ mam z tym problemy, ominąłem magistralę 485 i połączyłem bezpośrednio USARTy obu urządzeń. Niestety, czujnik nie odpowiada. Wysyłam mu jako pytanie jego nr, kod odczytu rejestrów (0x03), dwa bajty adresu pocz. (00,00,) itd. Na końcu wysyłana jest suma kontrolna, też dwa bajty. W opisie Modbusa znalazłem opis obliczania sumy CRC, wg której zrobiłem funkcję wyliczającą ją. Dla jednego bajtu wygląda tak:

    Code: c
    Log in, to see the code


    dla nastepnych bajtów powtarza się procedurę, podstawiając odpowiednio bajt2, bajt3 itd... Nie wiem czy funkcja jest dobra, czujniki nie odpowiadają. Jeżeli ktoś robił cos z Modbusem może wie jak zrobić odpowiednią funkcję, lub może ta powyżej jest z jakimś błedem?

    Dodano po 15 [minuty]:

    Dla mnie procedura jest trochę bez sansu, bo traci się informacje o wartosci najmłodszego bitu danych - najpierw przesuniecie w prawo, potem sprawdzanie. Opis wygląda tak (i może coś źle rozumię):

    1) załadowanie wartości FFFFh do 16-bitowego rejestru;
    2) pobranie bajtu z bloku danych (zabezpieczana wiadomość) i wykonanie operacji EXOR
    z młodszym bajtem rejestru, umieszczenie rezultatu w rejestrze;
    3) przesunięcie zawartości rejestru w prawo o jeden bit połączone z wpisaniem 0 na
    najbardziej znaczący bit (MSB=0);
    4) sprawdzenie stanu najmłodszego bitu (LSB) w rejestrze, jeżeli jego stan równa się 0, to
    następuje powrót do kroku 3 (kolejne przesunięcie) , jeżeli 1, to wykonywana jest operacja EXOR rejestru ze stałą A00lh;
    5) powtórzenie kroków 3 i 4 osiem razy, co odpowiada przetworzeniu całego bajtu;
    6) powtórzenie sekwencji 2, 3, 4, 5 dla kolejnego bajtu wiadomości, kontynuacja tego
    procesu aż do przetworzenia wszystkich bajtów wiadomości;
    7) zawartość rejestru po wykonaniu wymienionych operacji jest poszukiwaną wartością
    CRC.
  • #2
    User removed account
    User removed account  
  • Helpful post
    #4
    nibbit
    Level 20  
    W stosie, który wykopałem ze źródeł mam:
    Code: c
    Log in, to see the code


    Jak co to sobie porównaj ;]
  • #6
    dziechu
    Level 27  
    nibbit - mój kompilator zbuntował się na takie rzeczy;) Zmieniałem tak i chyba zrobiłem to ok?

    Code: c
    Log in, to see the code

    Ale nie wiem jak tego użyć - jak otrzymać sume CRC z kilku bajtów, nie z jednego?

    Dodano po 2 [minuty]:

    markosik20 = dziekuję, sprawdzę czy zadziała:)
  • #7
    nibbit
    Level 20  
    Code: c
    Log in, to see the code


    To jest już do całej ramki korzystając z wcześniejszego kodu. Aczkolwiek równie dobrze możesz użyć ten wcześniejszy kod markosika. Wtedy nie będziesz musiał liczyć tej tablicy tylko podstawiać odrazu.

    A co do typów, jestem zdecydowanym zwolennikiem standardowych czyli uintXX_t intXX_t
  • #9
    Udios
    Level 12  
    Witam

    W przypadku pracy z MODBUSem gdy są problemy z połączeniem proponuję skorzystać z jakiegoś gotowego programu do komunikacji i sprawdzić czy on się połączy z slavem.
    Programów jest pewno sporo, ja mogę zaproponować Modbus tester z strony http://polish.modbus.pl/node/5
    swojego czasu sporo z niego korzystałem. Ma możliwość podglądnięcia transmisji wychodzącej i przychodzącej.

    Pozdrawiam
  • Helpful post
    #10
    michalko12
    MCUs specialist
    Ta wersja chyba nie powinna ci sprawić problemów?

    Code: c
    Log in, to see the code
  • #11
    dziechu
    Level 27  
    Wielkie dzięki wszystkim za pomoc:) Na razie podglądnąłem transmisję i wpisałem CRC na stałe, bo inne bajty tez się nie zmieniają, transmisja zaskoczyła, choć nie jest zbyt stabilna, tu musze jeszcze powalczyć. Potem dołaczę funkcję rzeczywistego obliczania CRC, bedę miał łatwiej, bo już wiem ile powinna wyjść dla tego konkretnego przypadku.
  • #12
    dziechu
    Level 27  
    Zapytam tu o inną jeszcze sprawę, bo nie chcę dla tego drobiazgu zakładać nowego tematu. Muszę ustawić timeout ramki, jezeli po odpowiednim czasie odbiornik nie odpowie, to transmisja zostaje przerwana z flagą błędu. Chcę do tego użyć timera, np.TIM4. Uruchomiony bedzie w najprostszej konfiguracji zwykłego licznika, ładowanego przed rozpoczeciem transmisji. Będzie np. odliczał w dół, potrzebna mi jest flaga uzyskania przez licznik 0 (underflow). Czytając o rejestrach liczników, jedyną taką flagą (którą znalazłem), jest TIMx_SR_UIF, czyli UpdateInterruptFlag. Co prawda nie będę włączał przerwania, ale jest to chyba jedyna flaga którą mogę w tym celu wykorzystać, czy też jest jakaś inna lepsza do tego celu?
  • Helpful post
    #13
    Freddie Chopin
    MCUs specialist
    dziechu wrote:
    Czytając o rejestrach liczników, jedyną taką flagą (którą znalazłem), jest TIMx_SR_UIF, czyli UpdateInterruptFlag. Co prawda nie będę włączał przerwania, ale jest to chyba jedyna flaga którą mogę w tym celu wykorzystać, czy też jest jakaś inna lepsza do tego celu?

    To jest właśnie flaga która jest Ci potrzebna.

    4\/3!!
  • #14
    dziechu
    Level 27  
    Dziękuję za potwierdzenie:)

    Dodano po 3 [godziny] 3 [minuty]:

    Mam jeszcze takie pytanie - w ramach jednej funkcji, instrukcje warunkowe typu if () nie modyfikują stosu? Chodzi mi konkretnie o cos takiego:

    Code: c
    Log in, to see the code

    Nie powinno być problemu ze stosem przy takim wyjściu z ifa?

    Dodano po 3 [godziny] 46 [minuty]:

    pewnie nie, w asm będą to jakieś krótkie skoki warunkowe...
    Bardzo lubię w C rozkaz goto, łacznie z if skok warunkowy, główna atrakcja z asm:)

    Dodano po 6 [minuty]:

    Ok, Modbus chodzi, CRC16 liczy prawidłowo, timeout też działa, w zasadzie program bliski końca, i tak 90% programu to bajery ekranowe, kolorowy TFT+dotyk wymaga głównie bajerów, Photoshop jest tu koniecznym narzędziem programisty ;)

    Dodano po 4 [minuty]:

    Do obliczania CRC16 skorzytałem z funkcji Michalko12, krótka i działa ok, podobna do tej którą pokazałem na poczatku i oparłem o niepoprawny opis.

    Dodano po 6 [minuty]:

    Choć jak tak sie przygladam, to jakby to samo (tylko moja dla jednego bajtu, trzeba by dodać pętlę ilosci bajtów).... bo to crc>>1; wykonywane jest bez względu na wartość if, więc mozna je wyrzucić poza if do góry i będzie jak moje...