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
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);
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
> 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.
> 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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.