Elegantes Interrupten

Gast #1848594
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;
    }
  }
}
Gast #1848635
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"

...
Gast #1848643
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
}
#1848644
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.
Gast #1848656
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..
#1848660
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.
Gast #1848676
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)?
#1848682
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.
Gast #1848686
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
#1848692
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 :-)

Antwort schreiben

Eine eigene Frage? Dieser Thread ist über 16 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.