Hallo zusammen, ich steh hier vor einem ganz großen Problem und würde mich hierbei um eure Hilfe freuen. Es geht darum eine Datenkommunikation zwischen PC (serielle Schnittstelle) und µC ( ATMega8515 ) aufzubauen. Erst einmal nur zu Lernzwecken ein single Master Protokoll: <SenderID><EmpfängerID><Länge><Nutzdaten><Checksumme> Dabei habe ich erst einmal damit anfangen am PC ein kleines Datenpacket zu schnüren und dieses dann an den µC zu senden. PC-Seitig klappt das auch. Mein Problem ist jetzt allerdings der Empfang am/im µC. Es würde mich freuen, wenn ihr mir euer Vorgehen einmal schildern würdet, denn fertige Implementierungen, die man als Anfänger auch verstehen kann habe ich bisher nicht gefunden. Ich dachte mir das folgendermaßen, fühle mich dabei aber wie wenn ich auf dem Holzweg wäre: Ich erzeuge ein globales Array, in das ich nach und nach die per UART reinkommenden Daten im UART-RX-Interrupt schreibe. Wird eine längere Zeit nichts empfangen, wird das Array wieder vom ersten Element weg beschrieben. Wenn eine Packet angekommen ist wird ein Flag gesetzt und in der main-Routine wird das Array dann "ausgewertet", d.h. checksumme prüfen etc. Leider entdecke ich jetzt schon einige Probleme: als erstes das timeout. Wie erkenne ich wie lange keine Daten mehr eingetroffen sind? Oder was mache ich, damit mir das Array nicht überschrieben wird wenn noch nicht alle Daten verarbeitet wurden? Wäre schön wenn mir grad jemand mit seiner Idee auf die Sprünge helfen würde. Vielen vielen Dank Julian
Julian E. schrieb: > Lernzwecken ein single Master Protokoll: > <SenderID><EmpfängerID><Länge><Nutzdaten><Checksumme> Du hast einen der wichtigsten Punkt vergessen: Du brauchst entweder vorne oder hinten (oder an beiden Enden) eine EINDEUTIGE Kennung, die dir die Synchronisierung auf den Anfang eines Datenpaketes ermöglicht. Das übersehen Neulinge gerne. Neben den Nutzdaten benötigt man für ein stabiles Protokoll auch immer ein gewisses Mass an Verwaltungsinfo, welche nur dazu dient die Übertragung selbst zu steuern. > Es würde mich freuen, wenn ihr mir euer Vorgehen einmal schildern > würdet, denn fertige Implementierungen, die man als Anfänger auch > verstehen kann habe ich bisher nicht gefunden. > Ich dachte mir das folgendermaßen, fühle mich dabei aber wie wenn ich > auf dem Holzweg wäre: > Ich erzeuge ein globales Array, in das ich nach und nach die per UART > reinkommenden Daten im UART-RX-Interrupt schreibe. Wird eine längere > Zeit nichts empfangen, wird das Array wieder vom ersten Element weg > beschrieben. Kann man so machen, aber Timeouts zur Synchronisierungssteuerung sind meistens keine gute Idee. > Wenn eine Packet angekommen ist wird ein Flag gesetzt und in der > main-Routine wird das Array dann "ausgewertet", d.h. checksumme prüfen > etc. > Leider entdecke ich jetzt schon einige Probleme: als erstes das timeout. > Wie erkenne ich wie lange keine Daten mehr eingetroffen sind? Timer mitlaufen lassen. Aber mit einer dezidierten Framesteuerung in Form eines eindeutigen Frameanfangs ist das normalerweise nicht notwendig. Ungültige Frames können da normalerweise sauber identifiziert werden. > Oder was mache ich, damit mir das Array nicht überschrieben wird wenn > noch nicht alle Daten verarbeitet wurden? Das Array muss groß genug sein, damit das längste mögliche Paket da auch tatsächlich reinpasst.
Julian E. schrieb: > Ich erzeuge ein globales Array, in das ich nach und nach die per UART > reinkommenden Daten im UART-RX-Interrupt schreibe. Wird eine längere > Zeit nichts empfangen, wird das Array wieder vom ersten Element weg > beschrieben. Ich würde das globale Array als "Ringpuffer" organisieren. Ein Löschen ist dann "LeseIndex = SchreibIndex;" Julian E. schrieb: > Oder was mache ich, damit mir das Array nicht überschrieben wird wenn > noch nicht alle Daten verarbeitet wurden? Der Punkt erledigt sich von selbst wenn der Ringpuffer groß genug ist. Der Puffer muß dann um soviele empfangene Bytes größer sein wie Zeit benötigt wird um die alte Botschaft zu verarbeiten. Gruß Anja
Also ich muss sagen, ich mach es mir da etwas einfacher, und hatte damit noch keine Probleme... Checksumme usw... muss nicht sein, kommt halt darauf an wie fehlersicher deine Übertragung sein soll... Ich nutze immer einen Frame der folgendermaßen aufgebaut ist: S01! S = Frame anfang 01 = Daten / Kommando... ! = bezeichnet das ende des Frames Bei der übertragung von PC -> µC prüfe ich per Polling das RS232 Empfangsflag, wird was empfangen gehe ich in die RS232 Empfangsroutine die das empfangene Zeichen auswertet ist es ein "S" wird weiterhin immer das Empfangsflag geprüft, wird was empfangen kommt die Prüfung nach dem Kommando und danach könnten weitere Daten / Kommandos folgen oder dann das "!" was das ende des Strings kennzeichnet. Aber, viele Wege führen nach Rom... LG. Christian
Julian E. schrieb: > Erst einmal nur zu Lernzwecken ein single Master Protokoll: > <SenderID><EmpfängerID><Länge><Nutzdaten><Checksumme> Wozu braucht ein Single Master System eine SeinderID? > Es geht darum eine Datenkommunikation zwischen PC (serielle > Schnittstelle) und µC ( ATMega8515 ) aufzubauen. Wenn du eine "normale" serielle Schnitte hast, dann ist sogar die Empfänger-ID ziemlich eindeutig... > <SenderID><EmpfängerID><Länge><Nutzdaten><Checksumme> Wie willst du die <Checksumme> verpacken? Binär oder als ASCII-Zahl? > <SenderID><EmpfängerID><Länge><Nutzdaten><Checksumme> Dann also eher so: <STX><SenderID><EmpfängerID><Länge><Nutzdaten><Checksumme><CR>(oder <ETX>) Und die Daten am besten als ASCII-Zeichenkette. Also nicht 0x22 = 34 verschicken, sondern '3','4'... Christian T. schrieb: > und danach könnten weitere Daten / Kommandos folgen oder dann das "!" > was das ende des Strings kennzeichnet. Es gibt tolle Zeichen, die optimal für sowas geeignet sind. Ein Carriage-Return ist so eines. Wenn ich mich dann zum Debuggen in eine serielle Verbindung reinhänge, bekomme ich am Ende eines Datenpakets automatisch und umsonst eine neue Zeile...
Der Empfänger-ID kommt zuerst, da ein uC, welcher den Empfänger mittels Interrupt macht ev. dann für einen definierten Timeout nicht hinhören will oder einfach besseres zu tun hat. Sollte es möglich sein, die Adressen so vergeben, daß eine Parity damit gegeben ist und so eine 9bit Übertragung mit einem PC kompatibel ist.
Hi, wenn schon checksumme, wäre zu überlegen, ob du den Header auch Checksummen-sicherst, ansonsten kannst du nicht sicher sein, ob das was im Header steht korrekt ist. Ein Start- und Stop Signal habe ich bisher noch nicht gebraucht. In solchen Fällen greife ich zu einem finiten Automaten: Zustand 1: Idle (warte auf Daten) Zustand 2: Header empfangen Zustand 3: Daten empfangen Übergänge: 1-->2 erstes Header-Byte empfangen 2-->2 weitere Header-Bytes empfangen, solange Header nicht komplett 2-->3 wenn Header Checksumme ok 3-->3 Daten-Bytes empfangen, solange noch welche fehlen 3-->1 letztes Datenbyte empfangen 2-->1 Timeout (länger als 2s nichts empfangen) 2-->1 Checksumme Header falsch 3-->1 Timeout (länger als 2s nichts empfangen) 3-->1 Checksumme Datenblock falsch Wie lang der Header ist, weiß ich ja. Wenn ich also einen Header empfangen habe, steht da drin, wieviele Daten noch kommen müssen. Mit diesen beiden Informationen betreibe ich den Automaten. Den Header würde ich in eine Stack-Variable schreiben, wenn ich dann weiß, wieviele Nutzdaten kommen (am Übergang 2->3) würde ich bspw. Heap-Speicher allokieren und den Header reinkopieren und die Nutzdaten dahinter schreiben. Wenn das letze Datenbyte empfangen ist, kann der Heap-Speicher weitergereicht werden und das Protokoll wartet wieder im Zustand 1 auf Daten. ...eine von vielen Möglichkeiten
@Karl Heinz Buchegger >Du hast einen der wichtigsten Punkt vergessen: >Du brauchst entweder vorne oder hinten (oder anbeiden Enden) eine >EINDEUTIGE Kennung, die dir die Synchronisierung auf den Anfang eines >Datenpaketes ermöglicht. Kopfschüttel! Da bin ich anderer Meinung. Die Protokolldefinition liefert diese Informationen bereits - oder was denkst du, wie sagen wir mal UDP funktioniert? @Lothar Miller >Wenn du eine "normale" serielle Schnitte hast, dann ist sogar die >Empfänger-ID ziemlich eindeutig... Verstehe ich nicht. Angenommen, ich habe in meiner Software ein Protokollmodul, welches die serielle Schnittstelle öffnet und oben drauf sitzen zwei Komponenten (bspw. Datenkanal und Steuerkanal). Nehmen wir weiter an, dass diese Architektur an beiden Enden der Schittstelle implementiert ist. Da halte ich es schon für notwendig, dass es Absende- und Empfänger ID gibt, damit man eine gute Architektur und Komponenten-Kapselung machen kann und die verschiedenen Nutzdaten an der richtigen Stelle ankommen.
Peter schrieb: > @Karl Heinz Buchegger >>Du hast einen der wichtigsten Punkt vergessen: >>Du brauchst entweder vorne oder hinten (oder anbeiden Enden) eine >>EINDEUTIGE Kennung, die dir die Synchronisierung auf den Anfang eines >>Datenpaketes ermöglicht. > Kopfschüttel! Da bin ich anderer Meinung. das sei dir gegönnt. Jeder der an einer seriellen Schnittstelle Ausfälle wegen abgesteckter Kabel hatte, oder Geräte, die während einer laufenden Übertragung ein und ausgeschaltet wurden, denkt da anders darüber. Es gibt auch Leute, die meinen eine Versionsnummer am Anfang eines Files sei überflüssiger Luxus. PS: UDP setzt auf einem Ethernet Frame auf. Und ein Ethernet Frame beginnt mit einer Präambel :-) http://de.wikipedia.org/wiki/Ethernet#Formate_der_Ethernet-Daten.C3.BCbertragungsbl.C3.B6cke_und_das_Typfeld
@Karl Heinz Buchegger >Jeder der an einer seriellen Schnittstelle Ausfälle wegen abgesteckter >Kabel hatte, oder Geräte, die während einer laufenden Übertragung ein >und ausgeschaltet wurden, denkt da anders darüber. Ein Sync-Token hilft da leider nicht, das bestätigt dir jeder, der sich ernsthaft mit sicherer Datenübertragung auseinandersetzt. Ein Protokoll kann nur Datenintegrität zusichern - bspw. mit Checksumme. Eine Ausfall-Erkennung implementiere ich immer funktional bspw. mit zyklischen Handshake-Messages.
Peter schrieb: > @Karl Heinz Buchegger >>Jeder der an einer seriellen Schnittstelle Ausfälle wegen abgesteckter >>Kabel hatte, oder Geräte, die während einer laufenden Übertragung ein >>und ausgeschaltet wurden, denkt da anders darüber. > Ein Sync-Token hilft da leider nicht, Solange sicher gestellt ist, dass der Sync Token in den Daten nicht vorkommen kann, funktioniert das perfekt. Die Protokolldefinition ohne einleitendes Sync-Token hilft dir noch weniger, weil du nicht mit 100% Sicherheit davon ausgehen kannst, dass du nicht mitten in einen laufenden Frame einsteigst und die empfangenen Bytes vollkommen missverstehst. Wartest du aber auf das Sync Token für den Framestart, dann hast du schon mal die Gewähr, dass du auch tatsächlich die Bytes für den Frameanfang hältst, die auch tatsächlich den Frameanfang markieren. Und ab dort übernimmt dann die Protokolldefinition und erlaubt das Parsen des Frames. > Eine Ausfall-Erkennung Es geht nicht um Ausfallerkennung.
@Harl Heinz Buchegger >PS: UDP setzt auf einem Ethernet Frame auf. Und ein Ethernet Frame >beginnt mit einer Präambel :-) Du bringst da was durcheinander. Die Präambel signalisiert nicht den Beginn eines Ethernet Frames sondern war ganz früher mal gebräuchlich, um Sender und Empfänger zu synchronisieren. Sie ist lt. OSI unterhalb des MAC Layers definiert und somit nicht Bestandteil des Ethernet Frames. Auch kenne ich keinen Netzwerk-Chip, geschweige denn Treiber, der sich auf die Ethernet Präambel abstützen würde. Es wird immer nur mit Header und Nutzdaten hantiert. Die Ausfallsicherheit wird dann weiter oben bspw. mit TCP gemacht. http://de.wikipedia.org/wiki/Ethernet#Formate_der_Ethernet-Daten.C3.BCbertragungsbl.C3.B6cke_und_das_Typfeld
Peter schrieb: > @Harl Heinz Buchegger >>PS: UDP setzt auf einem Ethernet Frame auf. Und ein Ethernet Frame >>beginnt mit einer Präambel :-) > Du bringst da was durcheinander. Mag sein. Trotzdem ist dein Beispiel mit UDP nicht zutreffend, da UDP nicht die unterste Schicht ist und sich nicht um Framesynchronisierung kümmert. UDP setzt implizit voraus (durch das darunter liegende IP), dass es möglich ist ein Datenpaket an die Gegenstelle zu schicken, und das diese das Paket auch tatsächlich wieder als Paket erhält (wenn es das Paket überhaupt erhält). Aber UDP kümmert sich nicht darum, was zu passieren hat, wenn du eine Netzwerkkarte an ein Kabel stöpselst auf der gerade ein anderes Paket übertragen wird. Auch IP kümmert sich noch nicht darum. Die Ebene der Frames ist die OSI Schicht 1. > Es wird immer nur mit Header und Nutzdaten hantiert. Logo. Weil sich die Frame-Synchronisierung die Chips untereinander ausmachen. Ausserhalb der Chips interessiert das keinen. Aber all das ist letzten Endes im gegenständlichen Fall ziemlich uninteressant. Der TO hat es mit einer UART zu tun. Und da gibt es nun mal keine Frames, die von den UART Bausteinen gehandhabt werden. Also muss man sich die, samt zugehöriger Steuerung, in Software selber machen.
Peter schrieb: > Du bringst da was durcheinander. Ich gehe da mit Karl Heinz Buchegger konform, und sehe den Irrtum auf deiner Seite ;) Nicht umsonst nutzen darauf aufbauende Protokolle wie TCP eine Sequenznummer. Ein UDP Paket ist vergleichbar mit einem einzelnem Byte das du über die RS232 empfängst, auch da gibt es auf der Ebene "dadrunter" eine Schicht mit Start und Stopbit welche die Syncronisation sicherstellt und dir dann ein fertiges Paket (in diesem Fall ein byte) liefert. Ebeneso bekommst du ein UDP-Paket, was aber auch nicht auf magische Weise aus dem nichts entsteht, sondern einfach das Ergebnis einer sehr viel tieferliegenden Syncronisation der beiden Kommunikationspartner ist. Karl Heinz Buchegger schrieb: > Und da gibt es nun > mal keine Frames Wie gesagt, im kleinerem Rahmen schon ;)
Hallo, wie realisiert man sowas in C? Stehe vor einer ähnlichen Aufgabe, aber weiss nicht genau wie ich Programmiertechnisch mir ein solchen Frame zusammenbaue zum senden und wie ich die einzelnen States ändere bzw. ändern muss. Wäre für ein paar hilfreiche Tipps dankbar. Gruß paule
Moin ich hätte noch 2 kleine weitere dinge, die etwas höher angesiedelt sind. 1. ein kommando um die Protokoll version in erfahrung bringen zu können. ggf in der zukunft notwendig damit der PC ggf auf die unterschiedlichen Komandos / protokoll verhalten reagieren kann. Software und die protokolle entwickeln sich, die im Feld alle auf gleichem level halten zu können ist ein ding der unmöglichkeit. 2. ein Protokoll sollte bei unbekannten kommandos die er nicht kennt nicht einfach nichts tun. kann dazu führen, das der sender des kommandos sich zu tode wartet weil er auf ne antwort wartet (oder ein timeout kommt. wobei timeout immer böse sind, bzw wann kommt das timeout, .) besser ist es hier wenn das Protokoll ein NAC quasi eine negative antwort beitet z.B. Unbekanntes Kommando.
Ich gehe auch mit der meinung von Karl Heinz Buchegger konform. Habe hier von einem Lieferanten ein ser.Protokoll, das über UART rausgeknüppelt wird und keine EscSequenzen zur Synchronisation beinhaltet, sondern dies per Timeouts realisiert. Grauslich! Dann habe ich einen RFID-Leser, der per USB (VCOM) mit dem PC kommuniziert. Mit EscSequenzen. Läuft rund - auch wenn bei USB ein Kabelabziehen zu wesentlich drastischern Konsequenzen unter Windows führt. @paule: bastel Dir auf dem Papier eine Statemachine zusammen, die EscSequenzen hinzufügt bzw. entfernt. Ist eigentlich sehr einfach, wenn man das Prinzip gerafft hat. Die Umsetzung ist dann sehr einfach.
Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.