Elektroda.pl
Elektroda.pl
X
Elektroda.pl
Proszę, dodaj wyjątek dla www.elektroda.pl do Adblock.
Dzięki temu, że oglądasz reklamy, wspierasz portal i użytkowników.
itemscope itemtype="https://schema.org/QAPage"

[atmega][c winavr] freemodbus modbus

baxter007 21 Lut 2010 15:35 8040 18
  • [atmega][c winavr] freemodbus modbus

    #1
    Poziom 10  

    Witam,

    Jako że rozpoczynam przygodę z implementacją protokołu modbus na uC atmega potrzebuję pomocy przy próbie kompilacji przykładu udostępnionego przez freemodbus http://freemodbus.berlios.de/ dla kostki atmega168 przy pomocy Winavr. Docelowo chciałbym uruchomić tę aplikację na atmega8 jednakże już przy próbie kompilacji z ustawieniami ze źródła pod atmega168 otrzymałem taki komunikat od kompilatora :

    avr-objcopy --debugging \
    --change-section-address .data-0x800000 \
    --change-section-address .bss-0x800000 \
    --change-section-address .noinit-0x800000 \
    --change-section-address .eeprom-0x810000 -O coff-avr demo.elf demo.cof
    int constant type not supported in coff-avr
    avr-objcopy: --change-section-vma .eeprom+0xff7f0000 never used
    avr-objcopy: --change-section-lma .eeprom+0xff7f0000 never used
    avr-objcopy: --change-section-vma .noinit+0xff800000 never used
    avr-objcopy: --change-section-lma .noinit+0xff800000 never used
    make.exe: *** [demo.cof] Error 1

    czy jest ktoś w stanie pomóc w rozwiazaniu tego problemu oraz w rozwinięciu tematu zwiazanego ze źródłami freemodbus?

    0 18
  • Pomocny post
    #2
    Poziom 11  

    Witam

    Sam próbuję rozgryźć tą bibliotekę, ale teraz już nie wiem czy warto. Być może przydatna informacja z forum BerliOS:

    Code:

    By: zmu ( Zhen Mu )
     multi-slaves [ reply ]   
    2008-Apr-21 06:09
    Hi,

    does this code support multi-slaves application? I had troble to run this code with more than one slave.

    By: wolti ( Christian Walter )
     RE: multi-slaves [ reply ]   
    2008-Apr-21 08:09
    Hello,

    No - But our commercial MODBUS stack does. You can request more information at http://www.embedded-solutions.at.

    Regards,
    Christian



    wolti to ichniejszy admin od freemodbusa :/

    1
  • #3
    Poziom 10  

    Witam,

    faktycznie też odpuszczam sobie tego freemodbusa, jednakże próbuję teraz napisać własną bibliotekę opartą ściśle na zasadach komunikacji Modbus czyli tak jakby własny modbus. Nie wiem jak poradzić sobie z odbiorem ramki po stronie slave, a dokładnie z detekcją faktycznego pierwszego znaku z nadanej ramki, tzn jak wykryć że odebrany znak jest faktycznie pierwszym znakiem a nie np. znakiem z wnętrza ramki o tej samej wartości. Gdzieś przeczytałem, że można to wykonać na przerwaniu od licznika i zliczać kolejne ramki do odpowiedniej wartości potem resetować licznik, ale nie bardzo mi cokolwiek do głowy przychodzi. Jeśli jest ktoś w stanie pomóc to bardzo bym prosił. Zamieszczam fragment moich dotychczasowych wypocin może jest ktoś w stanie powiedzieć czy myślę chociaż w dobrym kierunku.

    master nadaje np. takie dwie ramki oczywiście do każdej z nich na koniec dodawane są dwa znaki z sumą kontrolną:

    Code:

    unsigned char frame0[]={0x80, 0x11, 0x80, 0x80, 0x80, 0x80};// właściwa z adresem 0x80

    unsigned char frame1[]={0x12, 0x80, 0x80, 0x80, 0x80, 0x80};


    a to fragment odbioru
    Code:

    #define adres 0x80

    ISR(USART_RXC_vect)
    {
    unsigned char buf[8];
    buf[0] = UART_Receive();      // funkcja odbioru znaku

    if (buf[0]==adres)
       {
       buf[1] = UART_Receive();
       buf[2] = UART_Receive();
       buf[3] = UART_Receive();
       buf[4] = UART_Receive();
       buf[5] = UART_Receive();
       buf[6] = UART_Receive();
       buf[7] = UART_Receive();
       unsigned short frame_crc = CRC16( buf,6); // CRC16 -funkcja spr.
       unsigned char crc1=(frame_crc>>8);         // podział crc na dwa znaki
       unsigned char crc0=frame_crc;                //
       
       if ((buf[6]==crc0) & (buf[7]==crc1))         // porównanie crc
          {
          lcd_clrscr();
          lcd_puts( "ok!" );
          }
       else
          {
          lcd_clrscr();
          lcd_puts_P( "frame no match!" );
          }
       }
    else
       {
       lcd_clrscr();
       lcd_puts_P( "address error!" );
       }


    }


    w trm przypadku slave na zmianę raz wykrywa właściwą ramkę ok! a raz address error!, więc tak jakby wszystko ok jednakże w przypadku gdy master wyśle np takie ramki :
    Code:


       unsigned char frame0[]={0x80, 0x11, 0x80, 0x80, 0x80, 0x80};
       unsigned char frame1[]={0x12, 0x80, 0x80, 0x80, 0x80, 0x80};
       unsigned char frame2[]={0x14, 0x80, 0x80, 0x80, 0x80, 0x80};
       unsigned char frame3[]={0x22, 0x80, 0x80, 0x80, 0x80, 0x80};
       unsigned char frame4[]={0x72, 0x80, 0x80, 0x80, 0x80, 0x80};
       unsigned char frame5[]={0x54, 0x80, 0x80, 0x80, 0x80, 0x80};



    slave ma małe prawdopodobieństwo wykrycia właściwej ramki, a ona jest przecież nadawana, no i w tym przypadku stale komunikat frame no match! jakiś pomysł a może ktoś podsunie własne rozwiązanie ?? :D z góry dzięki za odpowiedź.

    0
  • Pomocny post
    #4
    Specjalista - Mikrokontrolery

    Nie własne rozwiązanie tylko wszystko zgodnie ze standardem. Źle podszedłeś do odbioru danych. Musisz stworzyć sobie bufor który zgodnie ze standardem MODBUS musi zmieścić jedną cała ramkę która może mieć 256B. Ramki oddzielone są miedzy sobą przerwą trwającą co najmniej - i tu nie pamiętam 1,5 lub 3,5 znaku. Więc po odebraniu każdego znaku czekasz ten czas i jeśli ten czas zostanie osiągnięty przystępujesz do jej przetwarzania. Potem możesz oczekiwać na następną ramkę. Wszystko najlepiej jakbyś oparł na przerwaniach, no ale implementacja tego to już twoja sprawa.

    1
  • #5
    Poziom 10  

    michalko12 napisał:
    Ramki oddzielone są miedzy sobą przerwą trwającą co najmniej - i tu nie pamiętam 1,5 lub 3,5 znaku.

    Ramki oddzielone są od siebie na przynajmniej 3,5 *czas nadania znaku i znaki w ramce na nie więcej niż 1,5 *czas nadania znaku. Właśnie nie wiem jak odbierać te ramki w tym wyznaczonym czasie, proszę o jakąś podpowiedz co do tego buforu i sposobu odliczani tych czasów?

    0
  • Pomocny post
    #6
    Specjalista - Mikrokontrolery

    Odbiór znaków rób w przerwaniu i zapisuj je kolejno do bufora. W przerwaniu tym włączaj lub resetuj przerwanie timera tak, aby przerwanie timera było wyzwolone dokładnie 3,5 znaku później. Jeśli w tym czasie przyjdzie jakiś znak resetuj timer i cykl będzie mógł powtórzyć się, jesli jednak znak nie zostanie odebrany w tym czasie przerwanie timera wyzwoli się i będzie możliwe przetworzenie ramki. W przerwaniu timera wyłącz odbiornik UARTA ( nie przerwanie), zablokuj przerwanie timera i ustaw jakąś flagę dla pętli main informującą, że jest odebrana ramka. W pętli main sprawdzaj tę flagę i w razie czego obsłuż te dane . Po przetworzeniu danych wyzeruj wszystkie wskaźniki i flagi oraz włącz UART . Są jeszcze inne metody, ale ta jest chyba najprostsza i w miarę pewna.

    1
  • #7
    Poziom 1  

    Witam,
    również pracuje nad modbusem i avr-em... powiedz baxter007 czy Ci wszystko działa tak jak byś już chciał ??

    0
  • #8
    Poziom 11  

    I ja mam pytanie :)
    Jeżeli przerwa między ramkami (która jest stanem wysokim na linii) wynosi minimum 3.5T to jak ja odróżnić od 4 (i więcej) jedynek??
    Druga sprawa .. Czy najpierw należy odebrać cała ramkę, a dopiero później ją obsłużyć? Czy na bieżąco powinienem sprawdzać 2 pierwsze bajty, choćby po to żeby wiedzieć czy informacja jest wysłana do danego czy do innego slave.
    No i wreszcie jak odebrać cała ramkę skoro w zasadzie tylko kod funkcji może mi podpowiedzieć jaka będzie długość ramki?
    |adres|funkcja|dane|crc| --> z tym, że dane mogą zawierać od jednego do 256 bajtów.
    Pomocy :)

    0
  • #9
    Poziom 33  

    broda997 napisał:
    Jeżeli przerwa między ramkami (która jest stanem wysokim na linii) wynosi minimum 3.5T to jak ja odróżnić od 4 (i więcej) jedynek??


    3.5T to czas gdzie T to czas przesłania jednego bajtu więc nie trzeba nic odróżniać :wink:.
    Dobrym rozwiązaniem jest sprawdzanie za każdym odebranym bajtem CRC wstecz tzn. czy odebrane dwa bajty są sumą kontrolną wcześniejszych. Ten algorytm trwa do momentu wykrycia czasu 3.5T. Jeżeli czas zostanie wykryty nie należy wyłączać UARTA (czasami Master nadaje ramkę czeka 100-200ms na odpowiedź i nie retransmituje jej w przypadku braku odpowiedzi).
    Jeżeli to możliwe lepiej zastosować MODBUS ASCII, jeżeli jest mało danych do przesłania ramkę w tym standardzie łatwiej analizować.

    0
  • #10
    Poziom 11  

    Czyli zakładamy, że nie ma takiej możliwości żeby pojawiło się 3.5 bajta samych jedynek na linii.
    A co do obliczania CRC:
    Odbieram bajty nr: 1|2|3|4, sprawdzam czy CRC(1,2)=3,4 ->jeżeli tak - koniec.
    Jeżeli nie: 1|2|3|4|5, sprawdzam czy CRC(1,2,3)=4,5 -> jeżeli tak - koniec.
    Przy czym cały czas kontroluje długość trwania stanu wysokiego na linii i w momencie kiedy jedynka trwała 3.5T i nie napotkaliśmy 2 bajtów będących suma kontrolna poprzednich stwierdzamy błąd transmisji.

    Dobrze zrozumiałem?

    0
  • #11
    Poziom 33  

    broda997 napisał:
    Czyli zakładamy, że nie ma takiej możliwości żeby pojawiło się 3.5 bajta samych jedynek na linii.


    Ale jak?..każdy bajt ma tzw. bit startu.
    Z CRC jest tak jak piszesz.
    Co do czasu to przy każdym bajcie ustawiasz timer na 3.5T i jeżeli nastąpi przerwanie od tego timera to znaczy że cała ramka została wysłana.

    0
  • #12
    Poziom 11  

    Wszystko zaczyna się łączyć w jedną całość kiedy "odkryłem" USART w atmedze. Początkowo niemądry chciałem sam stworzyć cała transmisje szeregową zwyczajnie zmieniając stan jednego z pinów na porcie.

    Mam w związku z tym pytanie:
    Czy jeżeli ustawiłem długość słowa na 8bitów to bufor UDR przyjmie każda 8bitową liczbę? Powiedzmy coś w tym stylu:

    Code:

    int dana;
    int ramka[]={128, 30, 50}
    for (int i=0; i=3, ++i)
    {
    dana=ramka[i];
    loop_until_bit_is_set(UCSRA,TXC);
    UDR=dana;
    }

    Nie mam jeszcze urządzenia odbiorczego wiec nie mogę sprawdzić co w rezultacie tego zostanie przesłane. Chyba żeby nadawać do samego siebie?

    0
  • #13
    Poziom 33  

    broda997 napisał:
    Czy jeżeli ustawiłem długość słowa na 8bitów to bufor UDR przyjmie każda 8bitową liczbę?


    Każdą poprawną z bitem startu i stopu. Są symulatory MODBUS'a działające jako master lub slave.

    0
  • #14
    Poziom 11  

    To znaczy, że ja sam muszę zadbać o to, żeby dołożyć do przesyłanych danych bit startu i stopu?
    Mówiąc przyjmie miałem na myśli to czy da się to do niego wpisać (tak żeby poprawnie nadał), nie chodziło mi o odbiór.

    I jeszcze jedna sprawa: jak najlepiej sprawdzić wartość jednego bitu w rejestrze? Można go pobrać i wyświetlić jako int w postaci 0 lub 1?

    0
  • #15
    Poziom 33  

    broda997 napisał:
    To znaczy, że ja sam muszę zadbać o to, żeby dołożyć do przesyłanych danych bit startu i stopu?

    Nie, bo sprzętowy UART sam o to zadba.

    broda997 napisał:
    jak najlepiej sprawdzić wartość jednego bitu w rejestrze? Można go pobrać i wyświetlić jako int w postaci 0 lub 1?

    Nie do końca rozumiem pytanie, którego bitu, na jakiejś konkretnej pozycji w bajcie?

    0
  • #16
    Poziom 11  

    Chciałem obserwować stan bitu TXC w rejestrze UCSRA, ponieważ program zatrzymywał mi się na:

    Code:
    loop_until_bit_is_set(UCSRA,TXC);

    ale właśnie do mnie dotarło, że ten warunek powinien być sprawdzany po wysłaniu, a nie przed.

    Chociaż i tak dobrze było by móc sprawdzić stan dowolnego bitu w dowolnym rejestrze i wyświetlić go na LCD.

    0
  • #17
    Poziom 13  

    Witam,
    na początku tego wątku zacytowano wypowiedź, że FreeModbus nie obsługuje >1 slave'a. Planuję uruchomienie MODBUSa/RTU via RS-485, póki co dla 1 mastera i 1 slave'a, ale w niedalekiej przyszłości pojawi się więcej slave'ów.

    Niestety, aktualnie nie mam możliwości sprawdzenia tego, więc chciałbym się zapytać, czy ktoś z powodzeniem korzysta z biblioteki FreeModbusa dla większej ilości slave'ów?

    Chyba nie ma to większego znaczenia, ale dodam że master'em ma być PC (inna implementacja niż FreeModbus), a slave'y zbudowane na avr'ach.

    0
  • #18
    Poziom 16  

    Hej, Nie wiem dlaczego doszliście do wniosku, że Freemodbus nie obsługuje więcej niż jednego slave, ja używam tego od dłuższego czasu, nie tylko na AVR i spokojnie może być master i kilkanaście slave'ów. Freemodbus jest duży objętościowo, ale działa od kopa.

    0
  • #19
    Poziom 11  

    Witam,

    Biblioteka FreeModbus obsługuje tylko jedną instancję protokołu Modbus Slave. Jeśli mikrokontroler lub inne urządzenia posiada więcej niż tylko jeden port szeregowy można uruchomić nową instancję protokołu Modbus Slave. Instrukcja jak to wykonać znajduje się w dokumentacji do tej biblioteki. http://freemodbus.berlios.de/api/sec_porting_serial.html Sam jeszcze tego nie wykonałem. Zamierzam to uruchomić dla mikrokontrolera ATmega2560.

    pozdrawiam

    Sławek

    0