Kiedy należy przejść z ASCII na zaawansowane protokoły szeregowe?


28

Wszystkie moje urządzenia mikrokontrolera komunikujące się z komputerem PC za pomocą UART używają ciągów ASCII do wysyłania poleceń i odbierania danych (jak zaimplementowano w Arduino). Tego się nauczyłem, kiedy zacząłem kopać w elektronice i zawsze uważałem, że wysyłanie nagich strun jest wystarczające. Zauważyłem jednak, że większość urządzeń, na które natknąłem się, używa wyrafinowanych protokołów binarnych, które obejmują kody funkcji, adresy i sprawdzanie błędów CRC.

Kiedy podstawowa komunikacja ASCII jest dopuszczalna i kiedy powinienem rozważyć coś bardziej zaawansowanego, na przykład Modbus? Czy urządzenia komercyjne używają takiego ASCII? Przemysłowy?


3
Krótka odpowiedź: kiedy aplikacja tego potrzebuje. Tak, urządzenia komercyjne używają ASCII. Weźmy na przykład GPS NMEA. (I znowu odniosę się tutaj do mojego pytania )
Eugene Sh.

1
Modbus ma tryb ASCII. Patrz Przewodnik po protokole Modicon Modbus
Tut

@EugeneSh .: Warto zauważyć, że NMEA ma pole sumy kontrolnej, a upuszczenie pojedynczej serii próbek z powodu awarii sumy kontrolnej (która zdarza się częściej niż myślisz) na ogół nie jest krytyczną awarią. Może się tak nie zdarzyć w przypadku innych protokołów ... i jest używanych wiele binarnych protokołów GPS (np. Garmin) do zastosowań, w których może to być naprawdę istotne (lub w których częstotliwość próbkowania wyższa niż 1 Hz jest wymagane, dla których NMEA jest zbyt szczegółowe). Chociaż to naprawdę tylko utrwala twój punkt widzenia.
Lekkość ściga się z Monicą

Odpowiedzi:


28
  1. ASCII i CRC nie wykluczają się wzajemnie. ASCII jest kodowaniem, a CRC służy do sprawdzania błędów.

  2. WSZYSTKO można wysłać jako ASCII. My, starsi, z pewnością pamiętamy UUEncoding, który zamienia wszystko w ciąg ASCII.

  3. A) Dla mnie zazwyczaj chodzi o szybkość i wydajność. Wysłanie dużej liczby 32-bitowej przez ASCII może zająć dużo czasu, ale przesłanie jej w postaci binarnej za pomocą protokołu szeregowego zajmuje tylko 4 bajty.

    B) Wysłanie NUMERÓW przez ASCII oznacza, że ​​musisz przekonwertować numer na ASCII, co jest wyraźnym dodatkowym krokiem (jest to część tego, co robi „printf”).

  4. Jeśli w jakiś sposób stracisz swoje miejsce, spieprzysz, stracisz format, dostaniesz niewłaściwy endian itp., Binarny protokół komunikacyjny z pewnością może spieprzyć. Jeśli wysyłasz ASCII, łatwiej jest odzyskać dane po pomyłkach, po prostu wchodząc i WYSZUKAJ w strumieniu danych.


12
+1 dla „ASCII to kodowanie”. To nie jest protokół; protokoły można budować na bazie ASCII.
Pete Becker,

8
Automatyczne odzyskiwanie po awarii nie jest z natury łatwiejsze dla protokołu opartego na tekście jako binarnego, ale sprawdzanie go i debugowanie z pewnością może być.
Nick Johnson

1
@NickJohnson - absolutnie. Gdy jesteś już w trakcie otwierania pliku w edytorze szesnastkowym, aby zobaczyć, co możesz odzyskać, jesteś już na FUBAR, o ile SOP idzie
Scott Seidman

1
@nickjohnson to nie jest tak naprawdę prawda. ASCII oferuje wiele opcji poza ramką / ograniczników, aby wspomóc synchronizację i odzyskiwanie, co wymagałoby dodatkowych znaków ucieczki, wypychania bitów, interwału czasu lub innych sztuczek, jeśli kanał jest używany do danych binarnych o pełnej szerokości.
Chris Stratton,

2
Zawsze preferuję ASCII przy pisaniu protokołów dla wszystkich oczywistych korzyści (czytelność, logowalność itp.). Są dwa przypadki, w których binarny ma większy sens: po pierwsze, jeśli problemem jest prędkość i potrzebujesz pliku binarnego, aby wcisnąć jak najwięcej danych do strumienia, a po drugie, marginalnie, jeśli celowo próbujesz zaciemnić lub nawet zaszyfrować dane strumień, aby utrudnić lub zapobiec inżynierii wstecznej. W tym momencie opracowałem odwrotne protokoły binarne i to w dużej mierze po prostu mnie zirytowało, niż faktycznie zapobiegło.
J ...

10

Oto kilka przemyśleń na ten temat:

  • ASCII jest fajny, ponieważ możesz użyć monitora szeregowego, aby ręcznie sprawdzić, co jest wysyłane.
  • jeśli twoje połączenie nie jest niezawodne, musisz spodziewać się błędów transmisji i powinieneś użyć CRC do sprawdzenia integralności każdego odebranego komunikatu. Można to również zrobić w przypadku komunikatów ASCII.
  • jeśli twoje połączenie jest zbyt wolne, możesz zmniejszyć rozmiar wiadomości, przełączając się na format binarny
  • Specjalny format binarny może być łatwiejszy do odkodowania po stronie odbiornika niż ASCII

7

Na najprostszym poziomie można powiedzieć, że prosty protokół komunikacyjny ma trzy warstwy: fizyczny, transportowy i aplikacyjny. (Istnieją modele z większą liczbą, takie jak OSI z 7 lub TCP / IP z 4. Liczba warstw nie jest szczególnie ważna w kontekście tego pytania.)

Warstwa aplikacji jest warstwą, z którą masz do czynienia bezpośrednio w kodzie, i koncentruje się na pytaniu. Jeśli chodzi o warstwę transportową, bajt przekazany do niej w send_data jest tylko wzorem binarnym, ale możesz zinterpretować ją w kodzie aplikacji jako literę „A”. Obliczenia CRC lub sumy kontrolnej będą takie same, niezależnie od tego, czy uważasz bajt za „A”, 0x41 lub 0b01000001.

Warstwa transportowa to poziom pakietu, w którym znajdują się nagłówki wiadomości i sprawdzanie błędów, niezależnie od tego, czy jest to CRC, czy podstawowa suma kontrolna. W kontekście oprogramowania układowego możesz mieć funkcję taką jak send_data, w której przekazujesz bajt do wysłania. Wewnątrz tej funkcji jest umieszczany w pakiecie, który mówi: „Hej, to jest normalny komunikat, wymaga potwierdzenia, a suma kontrolna to 0x47, bieżący czas to X”. Ten pakiet jest wysyłany przez warstwę fizyczną do węzła odbiorczego.

Warstwa fizyczna to miejsce, w którym definiuje się elektronikę i interfejs: złącza, poziomy napięcia, taktowanie itp. Warstwa ta może wahać się od kilku śladów sygnałów TTL dla podstawowego UART na płytce drukowanej do całkowicie izolowanej pary różnicowej, jak w niektórych Implementacje CAN .

W węźle odbiorczym pakiet wchodzi w warstwę fizyczną, jest rozpakowywany w warstwie transportowej, a następnie twój wzór binarny jest dostępny dla warstwy aplikacji. Od warstwy aplikacji węzła odbiorczego zależy, czy ten wzorzec powinien być interpretowany jako „A”, 0x41 lub 0b01000001 i co z nim zrobić.

Podsumowując, wysyłanie znaków ASCII jest prawie zawsze dopuszczalne, jeśli wymaga tego aplikacja. Ważne jest zrozumienie schematu komunikacji i włączenie mechanizmu sprawdzania błędów.


Protokoły Ascii mogą również zawierać sumę kontrolną. Spotkałem warianty Hex-as-ascii, używając ascii reprezentacji liczb.
Eugene Sh.

@EugeneSh. Wyjaśniłem ten punkt
Matt Young,

Nie, żeby wygłupiać, ale TCP nie ma czterech warstw; jest postrzegany jako pasujący do czwartej warstwy modelu OSI. Komunikacja szeregowa nie bardzo dobrze pasuje do modelu OSI.
batsplatsterson

@batsplatsterson To jest podstępne i całkiem nieistotne do tego, o czym mówię.
Matt Young,

5

Jeszcze nie wspomniano, że niezależnie od tego, czy używa się ASCII, czy protokołu binarnego, wysłanie znaku wymazywania przed każdym pakietem zapewni, że nawet jeśli szum linii lub błędy ramkowania pojawią się przed rozpoczęciem pakietu, wszystkie znaki po pocieszeniu wyjście zostanie poprawnie wykadrowane przy braku dodatkowego hałasu. W przeciwnym razie, jeśli ktoś wysyła pakiety w sposób ciągły i nie zawiera żadnych znaków, które gwarantują resynchronizację, możliwe jest, że jedna usterka może uszkodzić wszystko, co nastąpi, do następnej przerwy w transmisji. Znak 0xFF jest fajny, ponieważ gwarantuje, że każdy odbiorca będzie mógł ponownie zsynchronizować następujący znak.

(*) 0xFF - nazywany wymazywaniem, ponieważ ktoś, kto wpisuje błędny znak podczas wpisywania danych na taśmie papierowej, może nacisnąć przycisk „przesuń taśmę do tyłu” i nacisnąć przycisk wymazywania, aby zastąpić błędnie wybity znak 0xFF, co spowoduje być ignorowanym przez większość odbiorców).


2

Jedną z zalet wysyłania ciągów ASCII jest to, że kody sterujące mogą być następnie użyte do zasygnalizowania początku / końca komunikatu. np. STX (char 2) i ETX (char 3) mogą sygnalizować rozpoczęcie i zakończenie transmisji. Możesz też dodać prosty wiersz do oznaczenia końca transmisji.

Podczas przesyłania danych binarnych staje się to bardziej skomplikowane, ponieważ nie można zarezerwować żadnego konkretnego wzorca bitów dla kodu sterującego (bez dodatkowego obciążenia lub złożoności), ponieważ prawidłowy bajt danych może mieć ten sam wzorzec.


3
Wiele protokołów binarnych rezerwuje jeden lub więcej wzorów bitów jako kody sterujące, ale zawierają one także mechanizm zmiany znaczenia, który obsługuje te kody, gdy pojawiają się w danych.
Dave Tweed

Możesz zarezerwować dowolny wzór, aby oznaczyć wszystko, co chcesz w formacie binarnym. Na przykład pracuję nad projektami z szybkim strumieniem danych i powolnym strumieniem danych wychodzącym z tego samego uart. Zarezerwowałem największy negatywny int32 jako flagę dla moich wolnych danych i po prostu nasycam moje negatywne dane największym, ujemnym + 1
Scott Seidman

Zgoda. Mam nadzieję, że wyjaśniłem to w edytowanej odpowiedzi.
Tranzystor

2

ASCII jest w porządku, używam go we wszystkich projektach. To sprawia, że ​​debugowanie jest znacznie łatwiejsze do monitorowania portu, i stałoby się problemem, gdyby było dużo danych do wysłania.

Kolejna korzyść: używam szeregowych urządzeń radiowych, aby odbierać wiadomości między arduinami, i mogę używać szeregowego monitora podłączonego do mojego laptopa i wysyłać wiadomości, aby pewne rzeczy się zdarzyły. Idealne do testowania.

Ponadto wysyłanie rzeczy jako pliku binarnego nie jest niemożliwe do debugowania, a w zależności od narzędzi można pobrać plik binarny i przekonwertować go na coś czytelnego dla człowieka. Lub jeśli wiesz, czego szukasz, możesz wizualnie sprawdzić strumień danych i rozpoznać wartości tam, gdzie powinny one być, i znaleźć sposób winy, choć nie tak łatwo. tzn. rozpoznasz wzorce bajtów i rozpoznasz oczekiwane wartości


2

Zamiast Modbus rozważ HDLC . Dostajesz wykrywanie błędów (co jest ważne w przypadku głośnych linii szeregowych). Synchronizacja jest solidna, ucieczka jest solidna.

Użyłem HDLC w sieciach RS-485 bez żadnych problemów, a PPP również z niego korzysta.


2
Byłoby miło, gdybyś wskazał, dlaczego sugerujesz to przez Modbus.
Nie mam pojęcia, co robię

1

ASCII przez UART jest najbardziej popularny częściowo dlatego, że:

  • Podczas debugowania jest czytelny dla ludzi (jeszcze nie widziałem analizatora logiki, który nie dekoduje ASCII).

  • Jest bardzo łatwy do wdrożenia, masz tabelę ASCII za pośrednictwem szybkiego google, który jest dobrze znormalizowany.

  • Ma wbudowaną synchronizację z bitami start / stop.

  • Prawie cały świat hobbystów skonfigurował ASCII nad szeregowo, więc wszelkie nowe metody będą musiały sobie z tym poradzić, a to wcale nie jest łatwe.

Następnie pojawia się sytuacja, gdy zaczynasz wysyłać określone kodowanie, takie jak wysyłanie reprezentacji liczby zmiennoprzecinkowej w pamięci w porównaniu z konwersją liczby zmiennoprzecinkowej na ASCII, wysyłanie tej wartości przez port szeregowy, który może być znacznie dłuższy niż 4 bajty, a następnie konwersja do reprezentacji w pamięci na hoście. Zamiast tego po prostu wysyłasz reprezentację 4-bajtową za każdym razem. Oczywiście możesz samodzielnie rozpocząć kodowanie, ale musisz skonfigurować tagi początkowe / końcowe, kolejność itp.

Zamiast tego można użyć rzeczy takich jak Protobuf . Zostało to wykorzystane w projekcie, nad którym pracowałem, i było niezwykle korzystne, robi komunikaty o zmiennej długości, obsługuje dla ciebie endian i kilka innych fajnych funkcji. Nie ma też tak dużego rozmiaru kodu i można określić wszystko, co ma być statycznie przydzielane podczas uruchamiania. Jeśli będziesz tego potrzebował, będziesz musiał samodzielnie wprowadzić sumę kontrolną.

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.