web-dev-qa-db-de.com

Einfaches serielles Punkt-zu-Punkt-Kommunikationsprotokoll

Ich benötige ein einfaches Kommunikationsprotokoll zwischen zwei Geräten (einem PC und einem Mikrocontroller). Der PC muss einige Befehle und Parameter an das Mikro senden. Das Mikro muss ein Array von Bytes (Daten vom Sensor) übertragen.

Die Daten müssen rauschgeschützt sein (neben der Paritätsprüfung benötige ich meines Erachtens eine andere Datenkorrekturmethode).

Gibt es dafür eine Standardlösung? (Ich brauche nur eine Idee, nicht die komplette Lösung).

P.S. Jeder Rat wird geschätzt. P.P.S Entschuldigung für Grammatikfehler, ich hoffe du verstehst.

Edit 1. Ich habe nicht entschieden, ob es sein wird Master/Slave Das Protokoll oder beide Seiten können die Kommunikation initiieren. Der PC muss wissen, wann micro einen Job erledigt hat und kann Daten senden. Es kann das Mikro kontinuierlich abfragen, wenn Daten bereit sind, oder es kann Daten senden, wenn ein Auftrag erledigt ist. Ich weiß nicht, was besser und einfacher ist.

Edit 2. Hardware und physikalische Schicht Protokoll. Da RS-232 C serieller Standard im PC verwendet wird, verwende ich asynchrone Kommunikation . Ich werde nur RxD-, TxD- und GND-Signale verwenden. Ich kann keine zusätzlichen Kabel verwenden, da der Mikrocontroller AFAIK diese nicht unterstützt. Übrigens verwende ich den AVR ATmega128-Chip.

Also verwende ich eine feste Baudrate, 8 Datenbits, 2 Stoppbits ohne Paritätsprüfung (oder mit?).

Datenverbindungsprotokoll. Darum geht es meiner Frage in erster Linie. Vielen Dank, dass Sie die Protokolle HDLC , PPP und Modbus vorschlagen . Ich werde darüber recherchieren.

55
Vanuan

Ich würde HDLC verwenden. Ich hatte in der Vergangenheit viel Glück damit. Ich würde für eine Punkt-zu-Punkt-Serie einfach das Asynchronous Framing verwenden und all das andere Kontrollmaterial vergessen, da es wahrscheinlich übertrieben wäre.

Zusätzlich zur Verwendung von HDLC für die Erstellung des Pakets. Ich formatiere mein Paket wie folgt. So werden Optionen mit 802.11 übergeben

U8 cmd;
U8 len;
u8 payload[len];

Die Gesamtgröße jedes Befehlspakets beträgt len ​​+2

Sie definieren dann Befehle wie

#define TRIGGER_SENSOR 0x01
#define SENSOR_RESPONSE 0x02

Der andere Vorteil ist, dass Sie neue Befehle hinzufügen können. Wenn Sie Ihren Parser so gestalten, dass nicht definierte Befehle ignoriert werden, ist die Abwärtskompatibilität gewährleistet.

Wenn Sie also alles zusammenstellen, sieht das Paket folgendermaßen aus.

 // total packet length minus flags len+4
 U8 sflag;   //0x7e start of packet end of packet flag from HDLC
 U8 cmd;     //tells the other side what to do.
 U8 len;     // payload length
 U8 payload[len];  // could be zero len
 U16 crc;
 U8 eflag;   //end of frame flag

Das System überwacht dann den seriellen Datenstrom auf das Flag 0x7e und überprüft, wenn er vorhanden ist, die Länge, um festzustellen, ob pklen> = 4 und pklen = len + 4 sind und ob crc gültig ist. Hinweis Verlassen Sie sich bei kleinen Paketen nicht nur auf crc. Sie erhalten eine Menge falsch positiver Ergebnisse und überprüfen auch die Länge. Wenn die Länge oder CRC nicht übereinstimmt, setzen Sie einfach die Länge und CRC zurück und beginnen Sie mit dem Decodieren des neuen Frames. Wenn es sich um eine Übereinstimmung handelt, kopieren Sie das Paket in einen neuen Puffer und übergeben Sie es an Ihre Befehlsverarbeitungsfunktion. Setzen Sie Länge und CRC immer zurück, wenn ein Flag empfangen wird.

Nehmen Sie für Ihre Befehlsverarbeitungsfunktion die Befehle cmd und len und verwenden Sie dann einen Schalter, um jeden Befehlstyp zu verarbeiten. Außerdem muss ein bestimmtes Ereignis eine Antwort senden, damit sich das System wie ein ereignisgesteuerter Remoteprozeduraufruf verhält.

So kann beispielsweise die Sensoreinrichtung einen Timer haben oder auf einen Befehl zum Ablesen reagieren. Dann würde es ein Paket formatieren und es an den PC senden, und der PC würde antworten, dass es das Paket empfangen hat. Wenn nicht, könnte das Sensorgerät bei einer Zeitüberschreitung erneut senden.

Auch wenn Sie eine Netzwerkübertragung durchführen, sollten Sie sie als Netzwerkstapel wie das OSI-Modell als Foredecker entwerfen. Vergessen Sie nicht das Physical Layer Stuff) . Mein Beitrag bei der HDLC ist die Datenverbindungsschicht und die RPC- und Befehlsverarbeitung ist die Anwendungsschicht .

37
Rex Logan

RS232-Protokolle sind schwierig. Der Vorschlag, HDLC zu verwenden, ist gut, aber nicht die gesamte Lösung. Es gibt andere Dinge, die Sie entscheiden müssen:

  • Wie wird die Baudrate zwischen den beiden Geräten ermittelt? Autobuad? Vordefiniert oder explizit gesetzt?
  • Werden Sie die Flusskontrolle in Software oder Hardware oder beidem durchführen? Hinweis: Wenn Sie die Hardware-Flusskontrolle verwenden, müssen Sie sicherstellen, dass die Kabel korrekt aufgebaut sind .
  • Apropos Kabel, das ist mit RS233 ein großer Schmerz. Je nach Gerät müssen Sie möglicherweise ein Straight-Through-Kabel, ein Cross-Over-Kabel oder eine Variante verwenden.
  • Die Verwendung eines softwarebasierten Flusskontrollmechanismus kann effektiv sein, da das einfachste Kabel verwendet werden kann - nur drei Kabel (TX, RX und Common).
  • Wählen Sie ein 7- oder 8-Bit-Wort aus?
  • HW-Parität oder Softwarefehlerprüfung.

Ich schlage vor, Sie verwenden 8 Datenbits, keine Hardware-Parität, 1 Stoppbit und eine softwarebasierte Flusssteuerung. Sie sollten Autobaud verwenden, wenn Ihre Hardware dies unterstützt. Wenn nicht, ist Autobaud in der Software äußerst schwierig.

10
Foredecker

Hier finden Sie einige gute Antworten, hier einige nützliche Hinweise:

Auch wenn Ihre Pakete nicht zeitlich getrennt sind, ist das Synchronisierungsbyte ein wesentlicher Faktor, um die Anzahl der Stellen zu verringern, an denen Sie versuchen müssen, ein Paket zu erstellen. Ihre Geräte müssen häufig eine Reihe von Junk-Daten verarbeiten (z. B. das Ende eines Pakets im Flug, wenn sie eingeschaltet sind, oder das Ergebnis einer Hardware-Kollision). Ohne ein Synchronisierungsbyte müssen Sie versuchen, aus jedem empfangenen Byte ein Paket zu erstellen. Das Synchronisationsbyte bedeutet, dass nur 1/255 Bytes zufälliges Rauschen das erste Byte Ihres Pakets sein können. Auch FANTASTISCH, wenn Sie Ihr Protokoll überprüfen möchten.

Eine Adresse auf Ihren Paketen zu haben oder nur ein bisschen Master/Slave oder PC/Gerät zu sagen, ist nützlich, wenn Sie sich die Pakete mit einem Snoop-Tool irgendeiner Art ansehen. Sie können dies tun, indem Sie für den PC ein anderes Synchronisierungsbyte als für das GERÄT verwenden. Dies bedeutet auch, dass ein Gerät nicht auf sein eigenes Echo reagiert.

Möglicherweise möchten Sie die Fehlerkorrektur untersuchen (z. B. Hamming ). Sie packen 8 Bit Daten in ein 12 Bit geschütztes Byte. Jedes dieser 12 Bits kann unterwegs umgedreht und die ursprünglichen 8 Bits abgerufen werden. Nützlich für die Datenspeicherung (auf CDs verwendet) oder wenn das Gerät nicht einfach erneut senden kann (Satellitenverbindungen, Einweg-HF).

Paketnummern erleichtern das Leben. Ein gesendetes Paket trägt eine Nummer, Antworten tragen dieselbe Nummer und ein Flag mit der Aufschrift "Antwort". Dies bedeutet, dass Pakete, die nie angekommen sind (z. B. durch Synchronisierung beschädigt), vom Absender leicht erkannt werden und im Vollduplexmodus mit einer langsamen Verbindung zwei Befehle gesendet werden können, bevor die erste Antwort empfangen wird. Dies erleichtert auch die Protokollanalyse (Ein Dritter kann verstehen, welche Pakete ohne Kenntnis des zugrunde liegenden Protokolls empfangen wurden.)

Einen einzigen Meister zu haben, ist eine unglaubliche Vereinfachung. In einer Vollduplex-Umgebung spielt dies jedoch keine große Rolle. Es genügt zu sagen, dass Sie dies immer tun sollten, es sei denn, Sie versuchen Strom zu sparen oder Sie tun etwas Ereignisgesteuertes am Geräteende (Eingangsstatus geändert, sample ready).

8
Tom Leys

Ich habe diese Frage vor ein paar Monaten gelesen, hatte genau das gleiche Problem und fand nichts, was für ein winziges 8-Bit-Mikro mit winzigem RAM-Speicher effizient genug wäre. So inspiriert von CAN und LIN habe ich etwas gebaut, um diesen Job zu erledigen. Ich habe es MIN (Microcontroller Interconnect Network) genannt und es hier auf GitHub hochgeladen:

https://github.com/min-protocol/min

Dort gibt es zwei Implementierungen: eine in Embedded C, eine in Python für einen PC. Außerdem ein kleines "Hallo Welt" -Testprogramm, in dem der PC Befehle sendet und die Firmware eine LED aufleuchtet. Ich habe gebloggt Hier erfahren Sie, wie Sie dies auf einem Arduino-Board zum Laufen bringen:

https://kentindell.wordpress.com/2015/02/18/micrcontroller-interconnect-network-min-version-1-0/

MIN ist ziemlich einfach. Ich habe die Layer 0-Darstellung (8 Datenbits, 1 Stoppbit, keine Parität) korrigiert, aber die Baudrate offen gelassen. Jeder Frame beginnt mit drei 0xAA-Bytes, die in der Binärdatei 1010101010 sind. Dies ist ein Nice-Pulszug, mit dem eine Autobaudratenerkennung durchgeführt werden kann, wenn sich ein Ende dynamisch an das andere anpassen möchte. Frames bestehen aus 0-15 Byte Nutzdaten, einer 16-Bit-Fletcher-Prüfsumme sowie einem Steuerbyte und einer 8-Bit-Kennung (um der Anwendung mitzuteilen, was die Nutzdaten enthalten).

Das Protokoll verwendet die Zeichenfüllung, sodass 0xAA 0xAA 0xAA immer den Frame-Anfang anzeigt. Dies bedeutet, dass ein Gerät, das aus dem Reset-Modus kommt, immer mit dem Start des nächsten Frames synchronisiert wird (ein Entwurfsziel für MIN bestand darin, niemals einen unvollständigen oder falschen Frame zu überspringen). Dies bedeutet auch, dass keine spezifischen zeitlichen Einschränkungen zwischen Bytes und Frames erforderlich sind. Alle Details zum Protokoll finden Sie im GitHub-Repo-Wiki.

MIN bietet Raum für zukünftige Verbesserungen. Ich habe dort einige Haken für die Weiterleitung von Blocknachrichten (4 Bits des Steuerbytes sind reserviert) und für die Aushandlung von Fähigkeiten auf höherer Ebene (der Bezeichner 0xFF ist reserviert) gelassen, sodass genügend Spielraum für das Hinzufügen von Unterstützung für häufig benötigte Funktionen vorhanden ist.

5
Ken Tindell

Mein Vorschlag ist Modbus. Es ist ein effizientes und einfaches Standardprotokoll für die Kommunikation mit Geräten mit Sensoren und Parametern (z. B. einer SPS). Die technischen Daten erhalten Sie unter http://www.modbus.org . Es gibt es schon seit 1979 und es wird immer beliebter. Sie werden kein Problem damit haben, Beispiele und Bibliotheken zu finden.

5
Martin Liesén

Hier ist ein alternatives Protokoll:

u8  Sync          // A constant value which always marks the start of a packet
u16 Length        // Number of bytes in payload
u8  Data[Length]  // The payload
u16 Crc           // CRC

Verwenden Sie RS232/UART, da der PC (serielle Schnittstelle) und der Prozessor (UART) dies bereits mit minimalem Aufwand erledigen können (Sie benötigen lediglich einen MAX232 Chip oder Ähnliches, um die Pegelverschiebung durchzuführen).

Und mit RS232/UART müssen Sie sich keine Sorgen um Master/Slave machen, wenn dies nicht relevant ist. Bei Bedarf ist eine Flusskontrolle verfügbar.

Vorgeschlagene PC-Software: Schreiben Sie entweder Ihre eigene oder Docklight zur einfachen Überwachung und Steuerung (Testversion ist kostenlos).

Für eine bessere Fehlerprüfung ist die Paritätsprüfung am einfachsten, oder wenn Sie etwas Stärkeres benötigen, vielleicht Faltungscodierung .

Was auch immer Sie tun: halten Sie es einfach!

BEARBEITEN: Die Verwendung von RS232 mit einem PC ist noch einfacher als früher, da Sie jetzt USB-zu-RS232/TTL-Konverter erhalten können. Ein Ende wird in die USB-Buchse Ihres PCs gesteckt und als normaler serieller Anschluss angezeigt. Der andere Ausgang liefert 5 V- oder 3,3 V-Signale, die direkt an Ihren Prozessor angeschlossen werden können , ohne dass eine Pegelverschiebung erforderlich ist.

Wir haben TTL-232R-3V von FDTI Chip verwendet, was für diese Art von Anwendung perfekt funktioniert.

3
Steve Melnikoff

Mein einziger Vorschlag ist, wenn Sie rauschresistent sein möchten, Vollduplex RS-422/485 zu verwenden. Sie können auf der AVR-Seite einen IC ähnlich this und auf der PC-Seite einen RS-232-> RS-422-Konverter wie hier den 485PTBR verwenden. Wenn Sie ein abgeschirmtes Kabel finden oder herstellen können (zwei verdrillte abgeschirmte Paare), haben Sie noch mehr Schutz. Und das alles ist für Mikro und PC unsichtbar - keine Softwareänderungen.

Was auch immer Sie tun, stellen Sie sicher, dass Sie ein Vollduplex-System verwenden, und stellen Sie sicher, dass die Lese-/Schreibaktivierungsleitungen auf dem IC aktiviert sind.

2

Sie können sich Telemetry und die zugehörige Desktop-Implementierung in python Pytelemetry ansehen

Haupteigenschaften

Es ist ein PubSub-basiertes Protokoll, aber im Gegensatz zu MQTT ist es ein Punkt-zu-Punkt-Protokoll, kein Broker .

Wie bei jedem Pubsub-Protokoll können Sie von einem Ende eines topic aus veröffentlichen und am anderen Ende über dieses Thema benachrichtigt werden.

Auf der eingebetteten Seite ist das Veröffentlichen in einem Thema so einfach wie:

publish("someTopic","someMessage")

Für Zahlen:

publish_f32("foo",1.23e-4)
publish_u32("bar",56789)

Diese Art des Sendens von Variablen scheint begrenzt zu sein, aber der nächste Meilenstein beabsichtigt, dem Parsen des Themas eine zusätzliche Bedeutung zu verleihen, indem folgende Aktionen ausgeführt werden:

// Add an indexing meaning to the topic
publish("foo:1",45) // foo with index = 1
publish("foo:2",56) // foo with index = 2

// Add a grouping meaning to the topic
publish("bar/foo",67) // foo is under group 'bar'

// Combine
publish("bar/foo:45",54)

Dies ist gut, wenn Sie Arrays, komplexe Datenstrukturen usw. senden müssen.

Auch das PubSub-Muster ist aufgrund seiner Flexibilität großartig. Sie können Master/Slave-Anwendungen, Geräte-zu-Geräte usw. erstellen.

C Bibliothek GitHub version

Die C-Bibliothek kann auf jedem neuen Gerät sehr einfach hinzugefügt werden, solange Sie eine anständige UART Bibliothek darauf haben.

Sie müssen lediglich eine Datenstruktur mit dem Namen TM_transport (Definiert durch Telemetry) instanziieren und die 4 Funktionszeiger readreadablewrite zuweisen. writeable.

// your device's uart library function signatures (usually you already have them)
int32_t read(void * buf, uint32_t sizeToRead);
int32_t readable();
int32_t write(void * buf, uint32_t sizeToWrite);
int32_t writeable();

Um Telemetrie zu verwenden, müssen Sie nur den folgenden Code hinzufügen

// At the beginning of main function, this is the ONLY code you have to add to support a new device with telemetry
TM_transport transport;
transport.read = read;
transport.write = write;
transport.readable = readable;
transport.writeable = writeable;

// Init telemetry with the transport structure
init_telemetry(&transport);  

// and you're good to start publishing
publish_i32("foobar",...

Python-Bibliothek PyPI version

Auf der Desktopseite gibt es das Modul pytelemetry, das das Protokoll implementiert.

Wenn Sie Python kennen, stellt der folgende Code eine Verbindung zu einem seriellen Port her, veröffentlicht ein Thema foo, druckt alle empfangenen Themen innerhalb von 3 Sekunden und wird dann beendet.

import runner
import pytelemetry.pytelemetry as tm
import pytelemetry.transports.serialtransport as transports
import time

transport = transports.SerialTransport()
telemetry = tm.pytelemetry(transport)
app = runner.Runner(transport,telemetry)

def printer(topic, data):
    print(topic," : ", data)

options = dict()
options['port'] = "COM20"
options['baudrate'] = 9600

app.connect(options)

telemetry.subscribe(None, printer)
telemetry.publish('bar',1354,'int32')
time.sleep(3)

app.terminate()

Wenn Sie Python nicht kennen, können Sie die Befehlszeilenschnittstelle verwenden

Pytelemetrie CLI PyPI version

Die Kommandozeile kann mit gestartet werden

pytlm

Anschließend können Sie connect, ls (Liste) empfangene Themen, print zu einem Thema empfangene Daten, pub (Veröffentlichung) zu einem Thema öffnen oder ein plot für ein Thema, um empfangene Daten in Echtzeit anzuzeigen

enter image description here

enter image description here

2
Overdrivr

In Bezug auf Paritätsprüfungen (wie es hier einige Male vorkommt):

Sie sind meistens nutzlos. Wenn Sie befürchten, dass ein einzelnes Bit fehlerhaft geändert wird, ist es sehr wahrscheinlich, dass sich auch ein zweites Bit ändert und Sie durch die Paritätsprüfung ein falsches Positiv erhalten.

Verwenden Sie etwas Leichtes wie CRC16 mit einer Nachschlagetabelle - es kann berechnet werden, wenn jedes Byte empfangen wird und ist im Grunde nur ein XOR. Steve Melnikoffs Vorschlag ist großartig für kleine Mikros.

Ich würde auch vorschlagen, vom Menschen lesbare Daten anstatt roher Binärdaten zu übertragen (wenn Leistung nicht Ihre erste Priorität ist). Es wird das Debuggen und Protokollieren von Dateien viel angenehmer machen.

1
Peter Gibson

vielleicht kann diese Frage völlig dumm sein, aber hat jemand die Verwendung eines von X/Y/Z MODEM Protokollen in Betracht gezogen?

Der Hauptvorteil der Verwendung eines der oben genannten Protokolle ist die hohe Verfügbarkeit einsatzbereiter Implementierungen in verschiedenen Programmierumgebungen.

0

Sie legen nicht genau fest, wie sich der Mikrocontroller verhält, aber wird alles, was vom Mikro übertragen wird, eine direkte Antwort auf einen Befehl vom PC sein? In diesem Fall können Sie anscheinend ein Master/Slave-Protokoll verwenden (dies ist normalerweise die einfachste Lösung). Wenn beide Seiten die Kommunikation initiieren können, benötigen Sie ein allgemeineres Protokoll für die Datenverbindungsschicht. HDLC ist ein klassisches Protokoll dafür. Obwohl das vollständige Protokoll wahrscheinlich ein Übermaß für Ihre Anforderungen ist, könnten Sie zum Beispiel mindestens dasselbe Frame-Format verwenden. Sie können sich auch PPP ansehen, um festzustellen, ob es nützliche Teile gibt.

0
hlovdal