Elegantes Interrupten

Gast #1848594
Lesenswert?

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
Lesenswert?

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
Lesenswert?

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
Lesenswert?

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
Lesenswert?

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
Lesenswert?

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
Lesenswert?

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
Lesenswert?

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
Lesenswert?

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

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren