www.mikrocontroller.net

Forum: Mikrocontroller und Digitale Elektronik Elegantes Interrupten


Autor: Stephan R. (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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;
    }
  }
}

Autor: Zwölf Mal Acht (hacky)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Naja. Durch Vergleichen. Das Vorgehen nennt sich Zustandsmaschine. Im 
Interrupt.

Autor: Stephan R. (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Also

if (array[0] != 'G')
count = 0;
 und von vorne anfangen? (Fänd ich unelegant..!)

Autor: X-Rocka (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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"

...

Autor: X- Rocka (x-rocka)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
dat ganze mit switch case

Autor: stefan hennig (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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):
static const unsigned char prefix[]="GPRMC";
static const unsigned int prefix_len = 5;
static       unsigned int prefix_pos = 0;

             unsigned char new_char = UDR;

if (prefix_pos < prefix_len)
{
  if (new_char == prefix[prefix_pos]) {
    ++prefix_pos;
  } else {
    prefix_pos = 0;
  }
} else {
  // Dein Code von oben...
  // am Zeilenende:
  prefix_pos = 0;
  uart_str_complete = 1;
}

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht 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
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;
      if( strncmp( uart_string, "$GPRMC", 6 ) == 0 )
        uart_str_complete = 1;
    }
  }
}

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.

Autor: Stephan R. (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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..

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht 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:
volatile char uart_string [uart_maxstrlen];

....

   char localCopy[80];

   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.

Autor: Norbert (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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)?

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Stephan R. (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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 :-)

Autor: Norbert (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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 ;-)

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.