Forum: Mikrocontroller und Digitale Elektronik UART Basiertes Programm funktioniert nur im Simulator


von Torsten B. (torty)


Angehängte Dateien:

Lesenswert?

Hallo zusammen

Ich bin leider mit C noch nicht so firm (vorher nur Assembler) und habe 
mir ein Projekt für dein Einstieg gesucht, bei dem ein Datenstrom über 
RS232 empfangen werden soll und auf bestimmte Zustände eine Reaktion 
folgen soll.
Die Daten bestehen zum einen aus GPS Daten und zum anderen aus 
Statusinformationen des Gerätes.

Ein Beispiel der empfangenen Daten ist in der Datei Flarm_log_klein.txt 
beigefügt.

Ich habe die Routine mit Eurer Hilfe zum Thema "strsep" so weit 
hinbekommen, dass sie mit HAPSIM, HypeTerm im AVRStudio Simulator das 
macht, was ich erwarte.

Jetzt habe ich den Kram mal in meinen ATMega16 auf dem STK500 gebrannt 
und es funktioniert leider nicht mehr so gut.

Soll-Funktion:

1. einzelne Zeichen einlesen, bis ein Satzende erreicht wurde.
2. einen kompletten Satz einlesen, mit strsep zerlegen und die 
informationen eines Satzes Namens "$PFLAU" in ein struct einlesen
3. den Satznamen $PFLAU ggf auf dem LCD drucken (nur Kontrolle)
4. den Wert (als String) des Feldes AlarmLevel auf dem LCD ausgeben (nur 
kontrolle)
4. Auf den Zustand eines Datenfeldes "AlarmLevel" in $PFLAU bestimmte 
LED ein bzw ausschalten.


Ich gehe hier davon aus, dass der Softwaretakt des STK 500 vom Quarz des 
Boards abgeleitet wird und daher den Ansprüchen der UART genügt.

Fehlerbild:

1. nach dem Reset des Flash-Vorganges läuft das Programm 4-5 (manchmal 
auch 14) Zyklen durch, was ich an der Ausgabe auf dem LCD erkenne.

2. nach einem manuellen Reset läuft es erst gar nicht, aber nach ein 
paar Minuten beginnt die Datenausgabe auf dem LCD
3. die Ausgabe stoppt zwischendurch immer mal wieder und läuft 
selbsständig wieder an.


Könnte es sein, dass es daran liegt, dass die Routine nicht 
interruptgesteuert ist ? Könnte mir die Warterei im echten Leben einen 
Strich durch die Rechnung machen ?

Könnte es ein Stack Overflow Problem sein ? Die Zeile 102 " 
free(running);    //String-Speicher wieder frei geben" am Ende des Codes 
ist erst später dazu gekommen und hatte keinen Effekt gebracht.

Ich hoffe, dass jemand helfen kann.
Danke für Eure Mühe
Torsten

von Helfer (Gast)


Lesenswert?

1) Bei dem Verdacht auf Stack- bzw. Bufferoverflow würde ich undbedingt 
mal alle strcpy() gegen strncpy() austauschen.

2) Ich verstehe den Sinn hinter deinem strdup/free nicht. Du kannst das 
doch komplett einsparen, wenn du direkt auf dem globalen Eingabepuffer 
Sentence arbeitest.

3) Beachte den Fall ptr == NULL z.B. hier wenn im Puffer kein Token mehr 
ist:
    ptr = strsep(&running,delimiter);
    strcpy(S_DATA.Name,ptr);

von Torsten B. (torty)


Angehängte Dateien:

Lesenswert?

Hallo Helfer
Danke, dass Du Dir die Zeit nimmst.

Helfer schrieb:
> 1) Bei dem Verdacht auf Stack- bzw. Bufferoverflow würde ich undbedingt
> mal alle strcpy() gegen strncpy() austauschen.

Ist es nicht so, dass strsep jeden delimiter (hier "," durch ein "\n" 
ersetzt ?
Dadurch sollte doch ein normales strcpy bereits wissen, wann es aufhören 
soll zu kopieren.

Helfer schrieb:
> 2) Ich verstehe den Sinn hinter deinem strdup/free nicht. Du kannst das
> doch komplett einsparen, wenn du direkt auf dem globalen Eingabepuffer
> Sentence arbeitest.

Hab es jetzt mal ohne das probiert und alles auf Sentence bezogen. Siehe 
Datei in diesem Beitrag. Jetzt geht gar nichts mehr. Kann Dir jedoch 
leider nicht sagen, warum ich das mit strdup/free gemacht habe. Es war 
halt so in einer Reference für strsep.

Helfer schrieb:
> 3) Beachte den Fall ptr == NULL z.B. hier wenn im Puffer kein Token mehr
> ist:
>     ptr = strsep(&running,delimiter);
>     strcpy(S_DATA.Name,ptr);

Dieser Fall dürfte doch nicht vorkommen.
Ich suche nach Einzelzeichen, bis ein Satzende auftaucht.
Danach wird ein kompletter Satz eingelesen und es stehen damit immer 
Token zu Verfügung. ptr sollte somit immer != NULL sein, wenn ein strcpy 
ausgeführt wird.

Hast Du oder sonst jemand noch eine Idee ?

Danke
Torsten

von Helfer (Gast)


Lesenswert?

> Ist es nicht so, dass strsep jeden delimiter (hier "," durch ein "\n"
> ersetzt ?
> Dadurch sollte doch ein normales strcpy bereits wissen, wann es aufhören
> soll zu kopieren.

strcpy() weiss aber nicht wie groß dein Ziel ist. Es kopiert bis zum 
'\0' gnadenlos. Wenn deine Übertragung ein Delimiterzeichen verliert 
oder der Sender was unerwartetes sendet, kann das der Tod deiner struct 
sein.

>> 3) Beachte den Fall ptr == NULL z.B. hier wenn im Puffer kein Token mehr
> Dieser Fall dürfte doch nicht vorkommen.
> Ich suche nach Einzelzeichen, bis ein Satzende auftaucht.

Laut Doku kann strsep() NULL zurück geben. Auf dem PC könnte man in 
diesem Fall (vom Programmierer unerwarteter Wert) wenigstens ein ASSERT 
einrichten. Auf dem µC würde ich den Fall immer abfangen bzw. zur Not 
mit einer Debug-LED anzeigen.

von Helfer (Gast)


Lesenswert?

> Hab es jetzt mal ohne das probiert und alles auf Sentence bezogen. Siehe
> Datei in diesem Beitrag. Jetzt geht gar nichts mehr.
1
  char *running;
2
...
3
    memset(S_DATA, 0, sizeof(struct _S_DATA));
4
    running = Sentence;
5
    for(i = 1; i < 12; i++) {      
6
      if( (ptr = strsep(&running, delimiter)) != NULL ) {
7
        switch(i) {
8
          case 1:  strncpy(S_DATA.Name, ptr, 6);             break;
9
          case 2:  strncpy(S_DATA.RX, ptr, 1);               break;
10
          case 3:  strncpy(S_DATA.TX, ptr, 1);               break;
11
          case 4:  strncpy(S_DATA.GPS, ptr, 1);              break;
12
          case 5:  strncpy(S_DATA.Power, ptr, 1);            break;
13
          case 6:  strncpy(S_DATA.AlarmLevel, ptr, 1);       break;
14
          case 7:  strncpy(S_DATA.RelativeBearing, ptr, 3);  break;
15
          case 8:  strncpy(S_DATA.AlarmType, ptr, 1);        break;
16
          case 9:  strncpy(S_DATA.RelativeVertical, ptr, 3); break;
17
          case 10: strncpy(S_DATA.RelativeDistance, ptr, 5); break;
18
          case 11: strncpy(S_DATA.ID, ptr, 3);               break;
19
        }
20
      } else {
21
        break;
22
      }
23
    }
24
    // ggf. i == 12 prüfen, ob S_DATA komplett gefüllt wurde
25
...

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.