Vorgehensweise UART-Empfangsverarbeitung

Gast #1295042
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:
1
volatile char msgRING[] = "RING";
2
volatile int  msgRINGct = 0;
3

4
volatile char msgNOCARRIER[] = "NO CARRIER";
5
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):
1
// UART rx complete interrupt
2
ISR(USART_RXC_vect)
3
{
4
  char ReceivedByte;
5
  ReceivedByte = UDR;
6
  
7
  // check the new char
8
  if(ReceivedByte == msgRING[msgRINGct])
9
  {
10
    msgRINGct++;
11
  }
12
  else {
13
    msgRINGct = 0;
14
  }
15
  
16
  if(ReceivedByte == msgNOCARRIER[msgNOCARRIERct])
17
  {
18
    msgNOCARRIERct++;
19
  }
20
  else {
21
    msgNOCARRIERct = 0;
22
  }
23

24
  // RING msg complete
25
  if(msgRINGct == strlen(msgRING)) {
26
    debug_msg("\r\nRING msg detected\r\n");
27
    msgRINGct = 0;
28
    
29
    // RING indication (toggle LED)
30
    PORTD ^= (1 << PD7);
31
  }
32

33
  // NO CARRIER msg complete
34
  if(msgNOCARRIERct == strlen(msgNOCARRIER)) {
35
    debug_msg("\r\nNO CARRIER msg detected\r\n");
36
    msgNOCARRIERct = 0;
37
  }
38
  
39
}

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
#1295087
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.
Gast #1298160
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.
Gast #1298449
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!
Persönliche Seite #1298509
Ü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

Eine eigene Frage? Dieser Thread ist über 17 Jahre alt. Stell sie in einem eigenen Thread – dort lesen mehr Leute mit, und sie wird öfter und schneller beantwortet.

Neuen Thread starten

Eine Lösung, Ergänzung oder Rückmeldung zu diesem Thread? Dann antworte hier.

Formatierung
  • [c]C-Code[/c]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] – Link zu einem Artikel
  • Verweis auf einen anderen Beitrag: Rechtsklick auf dessen Beitrags-ID (#8078628), „Adresse kopieren“, in den Text einfügen

Mehr zur Formatierung

Längeren Sourcecode als Anhang, nicht in den Text. JPG nur für Fotos und Scans; Zeichnungen und Screenshots als PNG oder GIF. Siehe Bildformate.

Schon registriert? Anmelden

Wird nicht angezeigt. Wir schicken dir einen Link; sobald du damit bestätigst, erscheint dein Beitrag.

Mit dem Abschicken legst du einen kostenlosen Account an und erkennst die Nutzungsbedingungen und die Datenschutzerklärung an.