www.mikrocontroller.net

Forum: Mikrocontroller und Digitale Elektronik Datenframe auslesen - UART


Autor: Michael 93 (michael93) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo Leute,

ich baue gerade an einer kleinen Bluetoth-Fernsteuerung für 
Modellfahrzeuge.

Es wird (vom Sender) ein Frame geschickt (über den UART 19,2kbaud) :
Adresse des Empängers - Wert 1 - Wert 2 - Adresse des Empängers

ohne Zeichen dazwischen

8 Bit - 1 Start - 1 Stop - kein Parity

und das mindestens 24 mal pro Sekunde. Das Frame soll auch noch um ein 
paar Bytes erweitert werden, aber das hier muss erst funktionieren.

Das ganze geht über UART und Bluetoothmodule (übertragung funktioniert).

-> Wie identifiziere ich im Empfänger die beiden Werte und speichere sie 
in zwei Variablen ab?

Hab schon ein paar Tage dran gearbeitet, funktioniert aber noch nicht. 
Im Forum gesucht hab ich auch schon.

Ach ja, das ganze arbeitet mit 2 ATMega8L bei 8 Mhz und 2 
Bluetoothmodulen BTM-112.

Michael

Autor: Peter (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Du wirst dir wohl selber eine kleine Protokoll überlegen müssen, sonst 
kannst du die bytes NIE unterscheiden.

z.b. Länge, Daten, Daten, [,Prüfsumme] und dann wieder Länge ...

Autor: Michael 93 (michael93) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Gibts irgendwo etwas in der Richtung in C, wo man sich sowas mal 
anschauen könnte?

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Wenn ich dir jetzt einfach mal die Zahlenfolge

  ..... 23   23   23   23   23   23   23   23  .....

vorwerfe, kannst du dann sagen, was denn nun was ist?
Nein, das kannst du nicht!

Du hast kein eindeutiges Kriterium, welche Zahl den die Empfängeradresse 
und welche Zahl ein dich interessierender Wert ist.

Die Aufgabe eines Protokolls ist es, dies zu regeln.
Und sowas musst du dir ausdenken!

Du brauchst irgendein eindeutiges Kriterium, an dem du erkennen kannst, 
wo ein Datensatz anfängt. Dein Problem werden wahrscheinlich die beiden 
Werte sein, da dort alle möglichen Werte vorkommen können. Dafür musst 
du dir eine Lösung überlegen (zb. indem du mit dir selbst vereinbarst, 
dass bestimmte Werte einfach nicht vorkommen).

Autor: Michael 93 (michael93) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
ach SO meint ihr das!

also, als Startbyte/Adresse (momentan gibt es nur eine Adresse) sende 
ich ein kleines f, bei den Werten wird das rausgefiltert mit:

if (a1 == 'f')   a1++;
if (a2 == 'f')   a2++;

aber es klappt irgendwie noch nicht so ganz, und deshalb frage ich nach 
einem Codebeispiel.

Danke schonmal.

Michael

Autor: Peter (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
das kann doch gar  nicht so schwer ein.

Beim empfänger musst du ja bloss auf das 'f' warten und das erste byte 
was genach konnt ist halt Byte1 das nächste ist Byte2.

Für solche sachen wird mal kaum Beispielcode finden, weil es zum schluss 
bloss ein paar zeilen sind - und diese sind meist sehr individuell.

Zeigt doch mal dein Code.

Autor: Bernd Hallinger (bhallinger) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Also Sinnvolles Startbyte kommt von Haus aus nicht im Datenstrom vor.

Ich verwende gerne so Zeichen wie < > @ # etc.

Meine Nutzdaten sende ich in der Regel als Hexzahlen. Das erhöht zwar 
die Datenmenge, dafür brauch ich keine Verrenkungen wenn das Startbyte 
als Wert vorkommt.
Wenns die Kanalbelegung zulässt, sende ich noch ein Ende byte.

Wenn die Frames unterschiedlich lang sein sollen, dann muss entweder am 
Frametyp (Parameterkennung) oder am Endebyte die Datenlänge erkannt 
werden.

Hübsch sind natürlich noch CRC-Summen und event Framenummern. Wenn man 
dann jedes Frame bestätigt, ist die Übertragung auch sicher. Bestätigen 
kann man auch falls ein Fehler vorliegt. Leider erkennt man ein 
ausgelassenen Frame dann erst beim nächsten guten (Es fehlt dann eine 
Framenummer)

Autor: Michael 93 (michael93) Benutzerseite
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
Hier mal die Sende- und Empfangsroutinen.

Zum Sender: Die Werte a1 + a2 werden natürlich entsprechend gefüllt und 
dann die Senderoutine aufgerufen.

Zu den Kommentaren: lasst euch von mal DE mal EN nicht verwirren, ich 
kann mich nicht entscheiden, ob ich Kommentare auf DE oder EN schreiben 
soll...

Michael

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Deine Adresse ist beim Senden sicher immer 'f'?

Vereinfach doch mal deine Empfangsroutine ein wenig. Das ist doch massig 
zu kompliziert. Im Endeffekt wird das wahrscheinlich sowieso alles ganz 
anders gelöst werden, weil du dir warten auf einen Empfang nicht leisten 
kannst :-)
  inSync = FALSE;     // Empfänger ist nicht synchronisiert

  while( 1 ) {

    x = uart_rxd();

    if( x == 'f' ) {
      inSync = true;   // Frame hat angefangen. Empfänger ist synchronisiert
      nextByte = 0;
    }

    else if( inSync ) {   // ein empfangenes Byte zählt nur dann, wenn
                          // der Empfänger sich auf ein Datenpaket
                          // synchronisiert hat.
      if( nextByte == 0 )
        a1 = x;

      else if( nextByte == 1 ) {
        a2 = x;
        inSync = false;  // Frame ist fertig. Gebe synchronisierung auf

        ...  Verarbeite a1 und a2
      }

      nextByte++;   // kann auch dann gemacht werden, wenn die Synchronisierung
                    // aufgegeben wurde. Beim nächsten Framestart wirds
                    // sowieso wieder auf 0 gesetzt
    }

    .....
  }


Anstatt getrennter Variablen inSync und nextByte könnte man auch beide 
Aufgaben in eine Variable zusammenfassen. zb könnte ein nextByte Wert 
von -1 bedeuten, dass keine Synchronisierung besteht. Mit dem Empfang 
eines 'f' geht nextByte auf 0, 1. Byte führt zu 1, und beim 2. Wertbyte 
wird nextByte wieder zu -1 ( um dann mit dem nächsten 'f' wieder zu 0 zu 
werden, etc).

Autor: Peter (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
kannst du noch sagen, was genau nicht geht? Von code ist zwar nicht 
schön sollte aber gehen.

Ich würde ihn aber gleich umschreiben, sonst bekommst du später Probleme 
wenn das Programm mal etwas mehr machen soll. Dein µC ist in der Main 
immer mit dem empfangen beschäftigt!

Nutze die Interruptroutinge zum empfangen von Daten. Dort Merkst du dir 
bei welchen byte die bist. Jedes mal wenn du ein byte empfängst zählst 
du einfach hoch. Wenn ein 'f' kommt dann setzt du den zähler wieder auf 
1. Das ganze sollte dann auch ein wenig übersichtlicher sein.

Wo sendest du üerbaupt das 'f' das ist nicht ersichtlich?

Autor: Michael 93 (michael93) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Was tut nicht: Gute Frage. Also, es hat mal so halbwegs funktioniert. 
Aber in unregelmäßigen Abständen hat es plötzlich gestockt, d.h. das 
Fahrzeug ist einfach so weitergefahren, egal wie der Kreuzknüppel (Werte 
a1 + a2) stand. Ebenso plötzlich gings dann auch wieder, und ich hatte 
mich schon gefreut. Das war Mittags. Abends gings dann nicht mehr. Die 
Module haben sich (mit 99% iger Wahrscheinlichkeit) verbunden, aber das 
Fahrzeug hat komplett getan was es wollte. Da hab ich die Empfangenen 
Daten am PC angeschaut, aber die sind aber in Ordnung. Deshalb bin ich 
zu dem Schluss gekommen, dass meine Frame-auswertung nicht richtig 
funktioniert. Und seitdem es einmal so verrückt gespielt hat, tut es das 
jetzt immer.

 > Wo sendest du üerbaupt das 'f' das ist nicht ersichtlich?

Oops, 'f' ist in der Variable adr_e gespeichert, Sorry.

Dass der µC in main immer mit empfangen beschäftigt ist, ist momentan 
noch nicht schlimm, die Servos werden per HW-PWM angesteuert.

@Karl Heinz
Deinen Code müsste man nur in eine Interrupt-Routine packen. Was 
passiert aber, wenn ein Byte verloren geht(ich glaube, bei meinen 
BT-Modulen gehen ab und wann ein, zwei Bytes verloren). Wäre aber 
machbar.

Zu dem "mehr machen":
später soll noch ein Programmiermodus rein, um LED's dimmen zu können. 
Weils acht stück sind, muss es SW-PWM sein. Könnte noch tolle 
Timing-Probleme geben, um die ich mich mal jetzt noch nicht kümmere.

Vielen Dank für eure Hilfe, Michael

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Michael 93 wrote:

> Deinen Code müsste man nur in eine Interrupt-Routine packen. Was
> passiert aber, wenn ein Byte verloren geht(ich glaube, bei meinen
> BT-Modulen gehen ab und wann ein, zwei Bytes verloren). Wäre aber
> machbar.

Spiels in Gedanken durch.
Die eigentliche Anwendung der Daten passier erst, nachdem a2 empfangen 
wurde. Wenn zwischendurch ein 'f' eintrudelt, dann beginnt der Frame 
wieder von vorne und nextByte wird wieder auf 0 zurückgestetzt.

So wie der Code aufgebaut ist, wird immer auf ein f gewartet und die 
nachfolgenden 2 Byte als Werte interpretiert (sofern nicht ein 'f' dabei 
war). Selbst wenn ein 'f' verloren geht, passiert auch nichts. 
Empfangene Bytes werden nur dann ausgewertet, wenn vorher ein 'f' kam. 
Und nach 2 empfangenen Bytes muss wieder ein 'f' kommen, damit die 
Auswertung der Bytes in Gang kommen kann.

Die Variable inSync fungiert wie ein Torwächter. Nur wenn sie auf TRUE 
steht, werden die nächsten beiden Bytes als gültige Daten akzeptiert. 
Das Tor geht nur dann auf, wenn ein 'f' empfangen wird und schliesst 
sich selbsttätig nach 2 empfangenen Bytes wieder.

Autor: Michael 93 (michael93) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
> Spiels in Gedanken durch.
> Die eigentliche Anwendung der Daten passier erst, nachdem a2 empfangen
> wurde. Wenn zwischendurch ein 'f' eintrudelt, dann beginnt der Frame
> wieder von vorne und nextByte wird wieder auf 0 zurückgestetzt.

ok, hatte ich übersehen.

> So wie der Code aufgebaut ist, wird immer auf ein f gewartet und die
> nachfolgenden 2 Byte als Werte interpretiert (sofern nicht ein 'f' dabei
> war). Selbst wenn ein 'f' verloren geht, passiert auch nichts.
> Empfangene Bytes werden nur dann ausgewertet, wenn vorher ein 'f' kam.
> Und nach 2 empfangenen Bytes muss wieder ein 'f' kommen, damit die
> Auswertung der Bytes in Gang kommen kann.
>
> Die Variable inSync fungiert wie ein Torwächter. Nur wenn sie auf TRUE
> steht, werden die nächsten beiden Bytes als gültige Daten akzeptiert.
> Das Tor geht nur dann auf, wenn ein 'f' empfangen wird und schliesst
> sich selbsttätig nach 2 empfangenen Bytes wieder.

nach einem 'f' folgen aber 2 Werte und noch ein 'f', sieht also i.e. so 
aus:

f-126-126-f-f-134-123-f-f-....

ein Frame sieht schließlich so aus: f-wert1-wert2-f
und das wird immer hintereinander gesendet.

(- trennt die bytes)

Oder hab ich schon wieder was falsch verstanden?

Michael

Autor: tommy776 (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo.
Ich habe folgendes Problem:

Ich empfange eine Variable die einen 16Bit-Wert beinhaltet.Nur die 
oberen 10Bit(Zweierkomplement) sind letztendlich relevant.

Diese 10Bit möchte ich über Uart an den Hyperterminal schicken und dort
als Gleitkomma-Zahl mit einer Nachkommastelle angezeigt bekommen.
Steh aber grad auf dem Schlauch wie ich das realisieren kann.

Variable:
int16_t temp = 0x1102; -> davon obere 10Bit: 0001 0001 00 -> diese Zahl 
möchte ich halt über Uart mit einer Nachkommastelle auf dem 
HyperTerminal sehen.

Hat jemand ne Idee?Danke

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Michael 93 wrote:

> f-126-126-f-f-134-123-f-f-....
>
> ein Frame sieht schließlich so aus: f-wert1-wert2-f
> und das wird immer hintereinander gesendet.
>
> (- trennt die bytes)
>
> Oder hab ich schon wieder was falsch verstanden?

Ooops. das hab ich in deiner Senderoutine übersehen.

Das ist keine gute Idee!
Sorge dafür dass Start und Endekennungen immer eindeutig sind!
Beim Empfang eines der beiden (Start oder Ende-Kennung) muss immer 
eindeutig klar sein, welches der beiden es ist. Für beides, Start und 
Ende, dasselbe Zeichen zu nehmen, ist abolut keine gute Idee! Da ist es 
noch besser, wenn du zb. die Ende Kennung ganz weg lässt.

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
tommy776 wrote:

> Variable:
> int16_t temp = 0x1102; -> davon obere 10Bit: 0001 0001 00 -> diese Zahl
> möchte ich halt über Uart mit einer Nachkommastelle auf dem
> HyperTerminal sehen.

http://www.mikrocontroller.net/articles/FAQ#Wie_ka...

Autor: Michael 93 (michael93) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Tag,

ok, ich lass das Stopp-Byte weg. Komme aber Momentan nicht zum 
Entwickeln, schreiben morgen und übermogen je eine Klassenarbeit, blöde 
Schule (bitte jetzt keine Diskussion über die Wichtigkeit der Bildung 
und ähnliches)!!!

Michael

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.