Moin! Ich bin fleissig dabei, meinen Atmega8 mit NMEA zu füttern, woraus diverse Informationen herausgepflückt werden sollen. Dazu verwende ich die ISR aus dem Tutorial, klappt alles ganz hervorragend. Nur zwei Sachen, die mich wurmen: 1.: wie bringe ich der Routine ELEGANT bei, dass Sie den String erst bei GPRMC anfangen soll 2.: das Char- Array für die Aufnahme ist (richtig so?) ausserhalb der main- Funktion und damit (so meine Auffassung) als globale Variablen namens "volatile char uart_string [uart_maxstrlen]" deklariert. Meine Versuche, diese in ein handhabbareres (cooles Wort) char-Array zu kopieren, haben nicht funktioniert, da gabs Compiler- Mecker. Also hab ich das "volatile" rücksichtslos entfernt und plötzlich funktionierts. Schön ist das sicher nicht, wie also besser lösen? Die ISR: ISR(USART_RXC_vect) { unsigned char buffer; buffer = UDR; if ( uart_str_complete==0 ){ if (buffer!='\n' && buffer!='\r' && uart_str_count<uart_maxstrlen-1){ uart_string[uart_str_count]=buffer; uart_str_count++; } else { uart_string[uart_str_count]='\0'; uart_str_count=0; uart_str_complete=1; } } }
Naja. Durch Vergleichen. Das Vorgehen nennt sich Zustandsmaschine. Im Interrupt.
Also if (array[0] != 'G') count = 0; und von vorne anfangen? (Fänd ich unelegant..!)
man baue sich eine state machine. ganz grob: states in ISR_RX: idle_state: kucke was kommt, wenn startzeichen, kopiere in buffer und state=data_state, ansonsten state=idle_state data_state: solang buffer frei und kein endzeichen, data in buffer. wenn endzeichen dann state=idle_state, flag setzen "mir-ham-daten" ...
Stephan R. schrieb: > 1.: wie bringe ich der Routine ELEGANT bei, dass Sie den String erst bei > > GPRMC anfangen soll ich würd's ungefähr so machen (code nicht getestet, einfach so hingetippt):
1 | static const unsigned char prefix[]="GPRMC"; |
2 | static const unsigned int prefix_len = 5; |
3 | static unsigned int prefix_pos = 0; |
4 | |
5 | unsigned char new_char = UDR; |
6 | |
7 | if (prefix_pos < prefix_len) |
8 | {
|
9 | if (new_char == prefix[prefix_pos]) { |
10 | ++prefix_pos; |
11 | } else { |
12 | prefix_pos = 0; |
13 | }
|
14 | } else { |
15 | // Dein Code von oben...
|
16 | // am Zeilenende:
|
17 | prefix_pos = 0; |
18 | uart_str_complete = 1; |
19 | }
|
Stephan R. schrieb: > Moin! > > Ich bin fleissig dabei, meinen Atmega8 mit NMEA zu füttern, woraus > diverse Informationen herausgepflückt werden sollen. Dazu verwende ich > die ISR aus dem Tutorial, klappt alles ganz hervorragend. > Nur zwei Sachen, die mich wurmen: > > 1.: wie bringe ich der Routine ELEGANT bei, dass Sie den String erst bei > GPRMC anfangen soll Heißt das, das du nur an diesem Datensatz interessiert bist? zb so
1 | ISR(USART_RXC_vect) |
2 | {
|
3 | unsigned char buffer; |
4 | |
5 | |
6 | buffer = UDR; |
7 | if ( uart_str_complete == 0 ) { |
8 | if (buffer!='\n' && buffer!='\r' && |
9 | uart_str_count<uart_maxstrlen-1){ |
10 | uart_string[uart_str_count]=buffer; |
11 | uart_str_count++; |
12 | }
|
13 | else { |
14 | uart_string[uart_str_count] = '\0'; |
15 | uart_str_count = 0; |
16 | if( strncmp( uart_string, "$GPRMC", 6 ) == 0 ) |
17 | uart_str_complete = 1; |
18 | }
|
19 | }
|
20 | }
|
Die Zeichen musst du so und so aus dem UDR abholen. Also kannst du sie auch zu einer Zeile zusammensetzen, das kostet nicht viel. Ist die Zeile fertig, überprüfst du, ob du es mit einem GPRMC Satz zu tun hast, und nur dann 'belästigst' du die Hauptschleife, in dem du der mitteilst, dass ein interessanter Datensatz vorliegt (durch Setzen das Complete Flags) > 2.: das Char- Array für die Aufnahme ist (richtig so?) ausserhalb der > main- Funktion und damit (so meine Auffassung) als globale Variablen > namens "volatile char uart_string [uart_maxstrlen]" deklariert. Meine > Versuche, diese in ein handhabbareres (cooles Wort) char-Array zu > kopieren, haben nicht funktioniert, da gabs Compiler- Mecker. Also hab > ich das "volatile" rücksichtslos entfernt und plötzlich funktionierts. > Schön ist das sicher nicht, wie also besser lösen? In dem Fall hätte man das volatile auch ruhig wegcasten können.
Danke für die Codevorschläge, arbeite sie ein. Betreffend volatile: was ist wegcasten? Ich hatte schlimmere Beschimpfungen befürchtet, dass ich es wage, das volatile zu entfernen. Glück gehabt..
Stephan R. schrieb: > Danke für die Codevorschläge, arbeite sie ein. > > Betreffend volatile: was ist wegcasten? > Ich hatte schlimmere Beschimpfungen befürchtet, dass ich es wage, das > volatile zu entfernen. Glück gehabt.. Dein Glück, dass es sich um ein Array handelt, das noch dazu als Stringspeicher verendet wird. Da tut sich der Optimizer schwer, das Array komplett in 1 oder 2 Registern zu halten :-) Von daher ist die Gefahr nicht sehr groß, dass dir hier der Optimizer einen Streich spielen wird, weil die meisten Stringoperationen ja soweiso mittels str... Funktionen erfolgen werden. wegcasten:
1 | volatile char uart_string [uart_maxstrlen]; |
2 | |
3 | ....
|
4 | |
5 | char localCopy[80]; |
6 | |
7 | strcpy( localCopy, (char*)uart_string ); |
du weißt ja, das es sicher ist, an dieser stelle uart_string so zu behandeln als ob es ein ganz gewöhnliches char Array wäre.
Hmmm, da kann man ja nur hoffen das in main() recht zügig gearbeitet und der Buffer schnellstmöglich wieder freigegeben wird. Ansonsten leidet wohl der Anfang des nächsten Datensatzes ein wenig und wird in /dev/null kopiert ;-) Wie wäre es als Alternative mit zwei alternierenden Buffers (der eine wird von der ISR beschrieben während der andere von main() abgearbeitet wird)?
Norbert schrieb: > Hmmm, da kann man ja nur hoffen das in main() recht zügig gearbeitet und > der Buffer schnellstmöglich wieder freigegeben wird. Ansonsten leidet > wohl der Anfang des nächsten Datensatzes ein wenig und wird in /dev/null > kopiert ;-) Daran hab ich auch schon mal gedacht. Wenn du dir aber die Ausgabe eines GPS Devices ansiehst, dann sieht man auch mit freiem Auge schon, dass es nach einem Datensatz meistens eine kleine Pause einlegt :-) Bei typischen Updateraten von 5 Datensätzen pro Sekunde, hat man meistens genug Zeit, einen Satz zu verarbeiten. > Wie wäre es als Alternative mit zwei alternierenden Buffers (der eine > wird von der ISR beschrieben während der andere von main() abgearbeitet > wird)? Kann man natürlich auch machen.
Danke Karlheinz, Dein Einzeiler if( strncmp( uart_string, "$GPRMC", 6 ) == 0 ) hat die Sache rund gemacht, läuft. Mit einem Schönheitsfehler: passing argument discards qualifiers from pointer target type
Stephan R. schrieb: > Danke Karlheinz, Dein Einzeiler > > if( strncmp( uart_string, "$GPRMC", 6 ) == 0 ) > > hat die Sache rund gemacht, läuft. Mit einem Schönheitsfehler: > > passing argument discards qualifiers from pointer target type Selbes Problem: volatile. Aber mitlerweile weißt du ja, wie du sie wegkriegst :-)
Karl heinz Buchegger schrieb: > Bei typischen Updateraten von 5 Datensätzen pro Sekunde, hat man > meistens genug Zeit, einen Satz zu verarbeiten. Ahhh, wusste ich nicht. Dann reicht ja schon ein mit einer Pendeluhr getakteter µC ;-)
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.