Forum: Compiler & IDEs Vorgehensweise UART-Empfangsverarbeitung


von Matthias (Gast)


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:
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

von Stefan E. (sternst)


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.

von Rufus Τ. F. (rufus) Benutzerseite


Lesenswert?

Zwischenspeichern in einem Puffer, Auswertung des Puffers bei 
Zeilenende.

von gast (Gast)


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.

von Matthias (Gast)


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!

von Rufus Τ. F. (rufus) Benutzerseite


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.

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
Noch kein Account? Hier anmelden.