Kanał - ATNEL tech-forum
Wszystkie działy
Najnowsze wątki



Teraz jest 20 sty 2022, o 11:14


Strefa czasowa: UTC + 1





Utwórz nowy wątek Odpowiedz w wątku  [ Posty: 7 ] 
Autor Wiadomość
PostNapisane: 9 gru 2021, o 00:12 
Offline
Użytkownik

Dołączył(a): 02 maja 2013
Posty: 111
Pomógł: 0

Witam wszystkich forumowiczów,

Temat postu mniej więcej sugeruje z czym się zmagam. Otóż implementuję obsługę MODBUSa RTU na mikrokontrolerze ATMega 128 (przy czym testuję program również na ATMega 324P). Niestety mimo wielu godzin, zmagam się z jednym problemem. A mianowicie: mój mikrokontroler połączony jest za pośrednictwem RS485 z falownikiem. Zadanie jest proste - wysłać dane, odebrać odpowiedź od falownika. Bazą do komunikacji jest biblioteka MK_USART, obsługująca pojedynczy port UART (w moim przypadku UART0). O ile nie ma żadnych problemów z nadawaniem danych, problem pojawia się z ich odbiorem. Co do idei, zgodnie ze standardem MODBUS, koniec ramki definiowany jest ciszą na magistrali trwającą około 3.5 znaku, co przy prędkości 9600 wynosi około 4ms. Koncepcja jest zatem prosta - utworzyć timer, który będzie się resetował a następnie uruchamiał wraz z każdym odebranych bajtem z portu szeregowego. Przysłanie danych ciągiem będzie resetowało ten timer. Przysłanie ostatniego bajtu uruchomi go, a z powodu braku resetu - wywoła przerwanie. Tak więc przysłanie danych ciągiem powinno wywołać przerwanie tylko raz, na samym końcu. Przynajmniej tyle teorii...

Praktyka niestety daje inne rezultaty. Falownik wysyła do uC ramkę MODBUSa, składającą się z 8 bajtów. Są one wysyłane ciągiem. Niestety mój mikrokontroler, z jakiegoś powodu dwa razy rzuca przerwanie od timera, dzieląc odebrane dane na dwa kawałki 1 i 7 bajtów. Najważniejsze fragmenty kodu wyglądają następująco:

Inicjalizacja UARTu i Timera:
Składnia: [ Pobierz ] [ Ukryj ]
język c
Musisz się zalogować, aby zobaczyć kod źródłowy. Tylko zalogowani użytkownicy mogą widzieć kod.


Przerwanie odbiorcze UARTu:
Składnia: [ Pobierz ] [ Ukryj ]
język c
Musisz się zalogować, aby zobaczyć kod źródłowy. Tylko zalogowani użytkownicy mogą widzieć kod.


Przerwanie od timera:
Składnia: [ Pobierz ] [ Ukryj ]
język c
Musisz się zalogować, aby zobaczyć kod źródłowy. Tylko zalogowani użytkownicy mogą widzieć kod.


Próbowałem chyba już wszystkiego - zmian timera, zmian trybu z CTC na tryb licznika, redukcji kodu do absolutnego minimum, pełnej diagnostyki z wysyłaniem dosłownie wszystkiego przez UART1 do komputera. Skutek zawsze zostawał taki sam - zamiast przerwania i 8 bajtów, dwa przerwania i ramka z podziałem 1-7 bajtów. Dla jasności, po "sklejeniu" tych dwóch kawałków ze sobą, odebrane dane z falownika są w pełni poprawne.

Pojawia się moje pytanie, czy ktoś ma pomysł co może być nie tak w tym przypadku? Podejrzewam, że to może być jakiś idiotyczny błąd, którego nie zauważam przez ilość godzin spędzonych nad problemem. Będę wdzięczny za jakiekolwiek sugestie.

Pozdrawiam!



Góra
 Zobacz profil  
cytowanie selektywne  Cytuj  
PostNapisane: 9 gru 2021, o 08:45 
Offline
Użytkownik

Dołączył(a): 13 lut 2012
Posty: 109
Pomógł: 7

Na bazie biblioteki UART Mirka coś tam jeden kolega na forum skomunikował w modbus:
post231110.html#p231110
Nie patrzyłem na kod, ale może warto sprawdzić: "Powyższe wszystkie obliczenia dotyczą ramki UART 8-N-1 (tzn. długość 10 bitów)"

a na atmega 128 też takie coś znalazłem w necie:
http://sebastianpawlak.com/pl/Informaty ... index.html



Góra
 Zobacz profil  
cytowanie selektywne  Cytuj  
PostNapisane: 9 gru 2021, o 11:18 
Offline
Użytkownik
Avatar użytkownika

Dołączył(a): 29 lis 2019
Posty: 148
Pomógł: 37

Z tych fragmentów kodu niewiele można wywnioskować.
Ja bym szedł w trochę innym kierunku. Zbocze opadające na lini RX startuje timer i się wyłącza (albo i nie, sprawa do przemyślenia). Przerwanie RX resetuje timer tj. ustawia licznik na wartość początkową. Przerwanie OVF albo COMP "zamyka ramkę" i się wyłącza oraz włącza przerwanie INT włączające timer (albo i nie, jw.). "Zamknięcie" ramki zrobił bym przez wstawienie do bufora Rx jakiegoś kodu (zakładając, że są jakieś kody nie pojawiające się w strumieniu Rx). Trzeba przemyśleć czy w warunkach brzegowych to zagra (np. przy jednoczesnym pojawieniu się przerwania INT i OVF). To tak na szybkiego.
Albo może na odwrót - przerwanie UART Rx startuje timer a zbocze opadające go resetuje?

_________________
Think for yourself and question authority.



Góra
 Zobacz profil  
cytowanie selektywne  Cytuj  
PostNapisane: 9 gru 2021, o 12:01 
Offline
Użytkownik

Dołączył(a): 02 maja 2013
Posty: 111
Pomógł: 0

JarekK napisał(a):
a na atmega 128 też takie coś znalazłem w necie:
http://sebastianpawlak.com/pl/Informaty ... index.html


Obejrzałem dokładnie to co znajduje się pod tym linkiem. Zastanowiło mnie to, że autor tego kodu chcąc zresetować wartość timera czyli ustawić TCNT = 0, robi coś takiego:
Składnia: [ Pobierz ] [ Ukryj ]
język c
Musisz się zalogować, aby zobaczyć kod źródłowy. Tylko zalogowani użytkownicy mogą widzieć kod.


Czyli mniej więcej: ubija timer przez odcięcie go od clocka, resetuje wartość TCNT, resetuje flagę przerwania TOV3, ponownie ustawia OCR i finalnie ponownie ustawia preskaler, tym samym uruchamiając timer. W całym kodzie nie ma praktycznie wykorzystanego bitu OCIE3A, za wyjątkiem jednokrotnego ustawienia go na wartość '1' w celu uruchomienia timera. Muszę sprawdzić takie rozwiązanie, dam znać czy coś to pomogło.

fofex napisał(a):
Z tych fragmentów kodu niewiele można wywnioskować.
Ja bym szedł w trochę innym kierunku. Zbocze opadające na lini RX startuje timer i się wyłącza (albo i nie, sprawa do przemyślenia). Przerwanie RX resetuje timer tj. ustawia licznik na wartość początkową. Przerwanie OVF albo COMP "zamyka ramkę" i się wyłącza oraz włącza przerwanie INT włączające timer (albo i nie, jw.). "Zamknięcie" ramki zrobił bym przez wstawienie do bufora Rx jakiegoś kodu (zakładając, że są jakieś kody nie pojawiające się w strumieniu Rx). Trzeba przemyśleć czy w warunkach brzegowych to zagra (np. przy jednoczesnym pojawieniu się przerwania INT i OVF). To tak na szybkiego.
Albo może na odwrót - przerwanie UART Rx startuje timer a zbocze opadające go resetuje?


Pomysł ze zboczem opadającym jako trigger resetu timera też jest ciekawy. Teoretycznie wielkiej różnicy to nie zrobi, bo albo zareagujemy na zbocze opadające, albo kilka "bitów dalej" na przerwanie od RXa. Ale racjonalne pomysły przestały już działać, może to coś pomoże. Dam znać jak sprawdzę.

Z jedną i drugą odpowiedź już teraz dziękuję.



Góra
 Zobacz profil  
cytowanie selektywne  Cytuj  
PostNapisane: 9 gru 2021, o 13:21 
Offline
Użytkownik
Avatar użytkownika

Dołączył(a): 29 lis 2019
Posty: 148
Pomógł: 37

slawus1998 napisał(a):
resetuje flagę przerwania TOV3

Przypuszczam, że przypisanie do licznika wartości zero może generować przerwanie więc gaszenie flagi jest jak najbardziej uzasadnione, natomiast manewry z preskalerem wydają mi się "nadmiarowe". Ale może się mylę.
Twoje rozwiązanie może też by zgrało gdybyś gasił flagę przerwania przed wystartowaniem timera (albo po) . Może spróbuj tego na początek?

_________________
Think for yourself and question authority.



Góra
 Zobacz profil  
cytowanie selektywne  Cytuj  
PostNapisane: 9 gru 2021, o 13:38 
Offline
Użytkownik

Dołączył(a): 13 maja 2014
Posty: 133
Pomógł: 11

Witam

Może spróbuj skorzystać z tego, że w MODBUS-ie wiesz jaka długa będzie ramka i że na końcu jest suma kontrolna. Jeżeli twój uC to Master, to na magistrali jest cisza, potem ty "coś" wysyłasz i potem falownik odpowiada. Wiedząc dokładnie co wysłałeś, wiesz dokładnie ile bajtów oczekujesz w odpowiedzi. Po zakończeniu wysłania zapytania odczytujesz w przerwaniu bajty, założoną ich ilość łączysz w całość i sprawdzasz czy mają strukturę ramki (adres:funkcja:ilość:dane:CRC) i czy zgadza się suma kontrolna. Jeżeli jest dobrze to koniec tej transmisji, jeżeli nie, to odczekujesz maksymalny czas trwania transmisji i ponawiasz zapytanie. Nie jest to może optymalne czasowo, ale nie podejrzewam abyś wymieniał dużo/szybko dane z falownikiem, a tak może być prościej.

Pozdrawiam
Janusz



Góra
 Zobacz profil  
cytowanie selektywne  Cytuj  
PostNapisane: 9 gru 2021, o 21:30 
Offline
Użytkownik

Dołączył(a): 02 maja 2013
Posty: 111
Pomógł: 0

JanuszT napisał(a):
Może spróbuj skorzystać z tego, że w MODBUS-ie wiesz jaka długa będzie ramka i że na końcu jest suma kontrolna. Jeżeli twój uC to Master, to na magistrali jest cisza, potem ty "coś" wysyłasz i potem falownik odpowiada. Wiedząc dokładnie co wysłałeś, wiesz dokładnie ile bajtów oczekujesz w odpowiedzi. Po zakończeniu wysłania zapytania odczytujesz w przerwaniu bajty, założoną ich ilość łączysz w całość i sprawdzasz czy mają strukturę ramki (adres:funkcja:ilość:dane:CRC) i czy zgadza się suma kontrolna. Jeżeli jest dobrze to koniec tej transmisji, jeżeli nie, to odczekujesz maksymalny czas trwania transmisji i ponawiasz zapytanie. Nie jest to może optymalne czasowo, ale nie podejrzewam abyś wymieniał dużo/szybko dane z falownikiem, a tak może być prościej.


Niestety nie mogę sobie na coś takiego pozwolić, bo na magistrali docelowo będą się znajdować trzy falowniki.

Tak czy tak, problem udało się rozwiązać. Rozwiązania nie do końca rozumiem, ale działa. Musiałem pozbyć się manewrowania bitem OCIE w rejestrze TIMSK, jako sposobem na włączenie/wyłączenie przerwania. Zastosowałem włączanie i odłączanie preskalera (TCCR0B = 0) w celu uruchamiania i zatrzymywania timera.

Otwieram teraz dyskusję, dlaczego to rozwiązanie działa. W tej chwili operuję na całym timerze, wcześniej jedynie na aktywacji/deaktywacji przerwania. Dodatkowo wcześniej przed każdym ustawienie OCIE na 1, ustawiałem TCNT na 0, tak żeby mieć pewność, że timer zawsze zaczyna liczenie od początku, a nie gdzieś w środku. Skąd w takim razie może wynikać różnica w działaniu tych dwóch rozwiązań?

JarekK, przede wszystkim Tobie dziękuję za podesłane linki z bibliotekami, których mi się nie udało w sieci znaleźć, a w których podpatrzyłem rozwiązanie finalnie sprawne. Dziękuję jednocześnie za rady i sugestie od wszystkich pozostałych.



Góra
 Zobacz profil  
cytowanie selektywne  Cytuj  
Wyświetl posty nie starsze niż:  Sortuj wg  
Utwórz nowy wątek Odpowiedz w wątku  [ Posty: 7 ] 

Strefa czasowa: UTC + 1


Kto przegląda forum

Użytkownicy przeglądający ten dział: Brak zidentyfikowanych użytkowników i 1 gość


Nie możesz rozpoczynać nowych wątków
Nie możesz odpowiadać w wątkach
Nie możesz edytować swoich postów
Nie możesz usuwać swoich postów
Nie możesz dodawać załączników

Szukaj:
Skocz do:  
Sitemap
Technologię dostarcza phpBB® Forum Software © phpBB Group phpBB3.PL
phpBB SEO