Skocz do zawartości

RS458 i znikający ostatni znak


Pomocna odpowiedź

5 godzin temu, jand napisał:

Nie jest też dla mnie całkiem jasne, czy żeby te błędy zanikły to trzeba zastosować naraz oba te rozwiązania, czy też wystarczy dowolne z nich?

wystarczy zastosować 2. czyli przejście z wysyłania stringa / tablicy znakowej na znak po znaku. 

Pkt 1. natomiast utrudnił mi (na równi z nocnymi godzinami :)) dojście do rozwiązania. Przez wysyłanie w dwóch prędkościach działy się inne nieoczekiwane rzeczy - np. po RS485 wysyłały się różnej długości paczki danych mimo że ponawiałem wysłanie tego samego ciągu znaków. Raz poszedł cały ciąg, raz 7 znaków z 14 a potem kolejne 7, a kolejnym razem innych proporcjach... 

@jand porobiłem trochę testów. Poniżej opis tego co mi wyszło. 

 

Po obu stronach były używane:

·         Serial – komunikacja via USB do wyświetlania znaków w monitorze portu szeregowego z IDE. Prędkość komunikacji zmienna

·         Serial1 – komunikacja UART / RS485 pomiędzy dwoma Arduino. Prędkość komunikacji stała: 115200

 

Kod po stronie odbiorcy (nie manipulowałem w nim w żadnym przypadku):

message = "";

   Serial.println(Serial1.available()); //tutaj czasami wyświetli inną liczbę znaków niż tą którą potem faktycznie odczyta

   while (Serial1.available() > 0) {

character = Serial1.read();

Serial.println(character);

   }

  Serial.println("Wiadomość: ");

  Serial.println(message);

 

Trochę się pobawiłem tymi prędkościami i zaobserwowałem następujące anomalie:

  1. Po stronie nadawcy zmieniam Serial (USB), Serial1 stałe na 115200. Odbiorca oba tj Serial i Serial1 stałe na 115200
    1. Zmiana prędkości na Serial (USB) nie wpływa na to jak odbiera odbiorca;
  2. Po stronie odbiorcy zmieniam prędkości Serial, Serial1 stałe na 115200. Nadawca Serial na 9600, Serial1 na 115200.
    1. Gdy prędkość komunikacji 1200 – nie udało mi się połączyć i odczytać znakow;
    2. Gdy prędkość komunikacji 4800 – jeden odczytany komunikat z RS485 jest w rzeczywistości składakiem z kilku (często wielu) komunikatów wysłanych przez nadawcę. Tak jakby nie odróżniał oddzielnych komunikatów.
    3. Gdy prędkość komunikacji 9600 – jw. ale na mniejszą skalę. Czasami odbieram poprawnie pojedynczy komunikat, czasami podwójny.
    4. Gdy prędkość komunikacji 115200 (czyli taka sama jak RS485) – wszystko jest OK;
    5. Gdy prędkość komunikacji 250000 – wszystko jest OK;
  3. 3.       Po stronie nadawcy manipuluję przerwami (delay()) pomiędzy kolejnymi wysyłkami komunikatów.
    1. Gdy przerwy bardzo krótkie rzędu 25 lub 50 ms. – problemy po stronie odbiorcy z powielonymi wiadomościami w ramach jednego komunikatu nasilają się wraz z zmniejszeniem czasu przerwy; Wstawienie Serial1.flush() po wysłaniu komunikatu nic nie zmienia w sytuacji po stronie odbiorcy;
    2. Gdy przerwy długie rzędu 500 ms – nie ma problemów z powielonymi odbiorami komunikatów.

 

Inne obserwacje i wnioski:

  • Serial1.available() nie zawsze zwraca poprawną liczbę odebranych znaków – nie polecam opierać się na tych liczbach. Czasami zwraca wartość (nadal dodatnią) mniejszą niż faktyczna długość przychodzącego komunikatu. W takich wypadkach komunikat zawsze odbierałem w całości (czyli było więcej znaków niż pokazało Serial1.available());
  • Jak pisałem wcześniej – wysyłanie danych przez Serial1.print(charMessage) lub Serial1.write(charMessage) gdzie charMessage to tablica znaków char[] -> dochodzi do zafałszowania ostatnich znaków. Robienie Serial1.flush() nic w tym wypadku nie pomaga. Natomiast, wysyłanie znak po znaku czyli Serial1.write(charMessage); (w pętli for) powoduje dostarczenie do odbiorcy całego, niezmienionego komunikatu.
Trzeba zadbać o odpowiednio długie przerwy pomiędzy wysłaniem kolejnych komunikatów – aby uniknąć problemów po stronie odbiorcy
  • Lubię! 1
10 minut temu, DCH napisał:

Jak pisałem wcześniej – wysyłanie danych przez Serial1.print(charMessage) lub Serial1.write(charMessage) gdzie charMessage to tablica znaków char[] -> dochodzi do zafałszowania ostatnich znaków.

Próbowałeś z '\0' na końcu? Obstawiam, że może pomóc #TerminateYourStrings...

Gratuluję cierpliwości w przeprowadzaniu licznych eksperymentów, ale odnoszę wrażenie, że we wszystkich przypadkach zmieniana jest prędkość transmisji pomiędzy Arduino i komputerem, natomiast prędkość łącza RS485 pozostaje stała (115200). Ja bym próbował przede wszystkim obniżyć prędkość właśnie tego połączenia.

@jand jak zauważyłeś - testy są czasochłonne. Dlatego z tą stałą prędkością łącza RS485 to celowo - w rozwiązaniu, które będę robił tylko taka prędkość może być zastosowana (ograniczenie w postaci urządzenia z którym będę się komunikował) i dlatego testowałem zachowania bez zmiany tego parametru. 

9 minut temu, BananWszyscy napisał:

Te błędy co szukasz są już opisane w nocie uartu. 

rozwiń proszę myśl bo może ja szukać nie umiem. A szukanie na około to błędy początkującego 🤣

1 godzinę temu, DCH napisał:

tylko taka prędkość może być zastosowana

Rozumiem, ale ja bym obniżył tę prędkość choćby do przetestowania (osaczenia problemu).

Znak końca \0 jest istotny jak się wysyła i odbiera stringi, a Ty operujesz na pojedynczych znakach.

31 minut temu, jand napisał:

Znak końca \0 jest istotny jak się wysyła i odbiera stringi, a Ty operujesz na pojedynczych znakach.

No niby tak, ale dziwne zachowania były gdy operowałem na stringach i dla tego przeszedłem na znaki. Chyba że przed wysłaniem powinienem na sztywno dokleić \0 na końcu stringa?

@szczygiel256 bardzo dziękuję za tą radę. To było to!!!

kodu nie pokazywałem bo tam nie było nic wielkiego. Inicjalizacja, stan High aby włączyć nadawanie, wysłanie, flush i stan low aby wyłączyć nadawanie.

Teoretycznie flush powinien rozwiązać sprawę bo niby wstrzymuje aplikację do czasu opróżnienia bufora wysyłania. Ale jak się okazuje nie można mu ufać. Dałem po flush delay(150); i wszystko pięknie chodzi!

@jand działa poprawnie na stringu z i bez znaku \0 na końcu.

jest taka oficjalna biblioteka do arduino jak "ArduinoRS485" - ona to załatwia wszystko - możesz jej użyć lub podejrzeć jak tam jest to rozwiązane zamiast delay(150)

  • Lubię! 2

Bądź aktywny - zaloguj się lub utwórz konto!

Tylko zarejestrowani użytkownicy mogą komentować zawartość tej strony

Utwórz konto w ~20 sekund!

Zarejestruj nowe konto, to proste!

Zarejestruj się »

Zaloguj się

Posiadasz własne konto? Użyj go!

Zaloguj się »
×
×
  • Utwórz nowe...