www.mikrocontroller.net

Forum: Compiler & IDEs Vorgehensweise UART-Empfangsverarbeitung


Autor: Matthias (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo zusammen!

Vorab: Ich bin generell noch eher ein Neuling in der µC-Programmierung. 
Die Erwartungen also bitte nicht zu hoch stecken! ;)

Meine derzeitigen Experimente beziehen sich auf die UART-Kommunikation 
eines Atmega8 mit dem PC/ einem Modem (AT-Befehle, Hayes), die Fragen 
sind aber sehr allgemein.

Der Controller sendet Daten, empfängt aber auch welche.

Wobei die Rx-Daten sowohl Antworten auf Tx-Daten (Befehle, Abfragen, 
...) sein können, als auch eintretende Ereignisse (z.B. ein "RING") oder 
periodisch (Hearbeat, etc.).

Wie verarbeite ich jetzt am besten die (byteweise) ankommenden Daten? 
Momentan habe ich vier Variablen deklariert:
volatile char msgRING[] = "RING";
volatile int  msgRINGct = 0;

volatile char msgNOCARRIER[] = "NO CARRIER";
volatile int  msgNOCARRIERct = 0;

Damit habe ich zwei Tx-Strings definiert, die ich abfangen will (ich 
glaube da könnte man noch ein "const" davorstellen). Die Variablen mit 
'ct' hinten sollen eine Zählvariable darstellen.

In der RX-ISR habe ich folgenden Code (gekürzt):
// UART rx complete interrupt
ISR(USART_RXC_vect)
{
  char ReceivedByte;
  ReceivedByte = UDR;
  
  // check the new char
  if(ReceivedByte == msgRING[msgRINGct])
  {
    msgRINGct++;
  }
  else {
    msgRINGct = 0;
  }
  
  if(ReceivedByte == msgNOCARRIER[msgNOCARRIERct])
  {
    msgNOCARRIERct++;
  }
  else {
    msgNOCARRIERct = 0;
  }

  // RING msg complete
  if(msgRINGct == strlen(msgRING)) {
    debug_msg("\r\nRING msg detected\r\n");
    msgRINGct = 0;
    
    // RING indication (toggle LED)
    PORTD ^= (1 << PD7);
  }

  // NO CARRIER msg complete
  if(msgNOCARRIERct == strlen(msgNOCARRIER)) {
    debug_msg("\r\nNO CARRIER msg detected\r\n");
    msgNOCARRIERct = 0;
  }
  
}

Damit wird geprüft, ob das neue Byte (char, sollte wohl auch noch 
unsigned vorangesetzt bekommen?) an der jeweiligen Position im String 
vorkommt. Es wird sozusagen geprüft, ob der von mir vorgegeben String 
Stück für Stück übertragen wird (keine Ahnung wie ich das ausdrücken 
soll, ich versteht das schon).

Ist bestimmt schon mal nicht so gut, dass das überhaupt in der ISR 
gecheckt wird; sollte vielleicht ein Flag setzen und dann in der 
main-loop überprüfen.

Welche Möglichkeiten gibt's denn dann noch? Die Befehle werden mit 
Sicherheit noch mehr aber kommt auch vor, dass ich eine Antwort mit 
dynamischem "Anhang" kriege: z.B. "ERROR 799" (wobei 799 eine beliebige 
andere Zahl sein könnte).

Vielleicht doch in einem Puffer zwischenspeichern?
Habe kürzlich auch das Stichwort "state machine" gelesen. Könnte das 
hier auch weiterhelfen?

Bin auch für Links ganz dankbar. Hoffe ihr könnt mir helfen!
Merci

Autor: Stefan Ernst (sternst)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Matthias schrieb:

> Vielleicht doch in einem Puffer zwischenspeichern?

Wäre auf jeden Fall besser.
Deine aktuelle Lösung funktioniert so eh nicht. Wenn z.B. beim "RING" 
das 'N' empfangen wird, erkennt das dein Code zusätzlich auch als erstes 
Zeichen von "NO CARRIER". Wenn also ein Wort erkannt wurde, musst du 
alle Zähler zurücksetzen. Außerdem musst du höllisch aufpassen, dass die 
Buchstaben eines Wortes nicht komplett in der richtigen Reihenfolge in 
einem anderen Wort enthalten sind.

Autor: Rufus Τ. Firefly (rufus) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Zwischenspeichern in einem Puffer, Auswertung des Puffers bei 
Zeilenende.

Autor: gast (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
braucht man nicht 2 puffer?
Was ist wenn, das erste Zeilenende erreicht ist und schon wieder neue 
Daten einflattern. Man müsste also in der ISR den Puffer auf einen 
anderen kopieren, damit der eine in aller Ruhe in der main abgearbeitet 
werden kann und der andere für neue Eingaben zur Verfügung steht.

Autor: Matthias (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hab mir jetzt auch überlegt nach einem oder mehreren bestimmten 
Trennzeichen (z.B. <LF> oder <CR>) zu "trennen" (klingt logisch). Zum 
Beispiel in einem zweidimensionalen Array dann für jede Zeile ein 
Element anlegen. Dooferweise muss man in C glaube ich wissen wie viel 
Platz dabei reserviert werden soll (aber sollte dafür ja genug da sein). 
Und dann könnte man eine Zählervariable nehmen für die aktuell 
abgearbeitete Zeile.

Gibt es denn irgendwo konkrete Implementierungen wo ich mir mal sowas 
an-/abschauen könnte?

Danke derweil!

Autor: Rufus Τ. Firefly (rufus) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Überlege mal, wie lange es braucht, bis Deine Software eine komplette 
Zeile auf ihren Inhalt untersucht hat, und wie oft neue Zeichen von der 
seriellen Schnittstelle empfangen werden können.

Du solltest der Interruptroutine nur das Empfangen und in einen 
Empfangs-Fifo eintragen überlassen, das Erkennen und Analysieren 
empfangener Zeilen kann im Hauptprogramm geschehen, und das hat (fast) 
alle Zeit der Welt, solange das Empfangs-Fifo nicht überläuft. 
Zusätzliche Puffer sind daher nicht nötig und müssen erst recht nicht 
von der Interruptroutine verwaltet werden.

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.