Forum: Compiler & IDEs GPS String auswerten wiedermal


von Bene J. (terfagter)


Lesenswert?

Hallo zusammen,

ich empfange über die USART1 sekündlich einen NMEA-GPS-String und möchte 
nur bestimmte Daten heraus filtern. Soweit so gut. Ich habe viele 
Beiträge gelesen und versucht die Hilfen anzuwenden.
1
#include <avr/io.h>
2
#include <util/delay.h>
3
#include <stdlib.h>
4
#include "uart.h"
5
#include <stdio.h>
6
#include <string.h> 
7
8
char nmea_packet[100];
9
10
int main (void) 
11
{
12
  
13
  initusart0();                      //Alle USART-Schnittstellen initialisieren
14
  initusart1();
15
  
16
  char *Kennung;
17
  char *Time;
18
  while(1) {
19
  getstr1(nmea_packet,100);
20
  
21
  char *stringp = nmea_packet; // Inhalt von nmea_packet wird verändert!
22
  if(strstr( stringp,"$GPRMC" )) {
23
  Kennung    = strsep( &stringp, "," ); // $GPRMC
24
  Time       = strsep( &stringp, "," );
25
  putstr0(Kennung);
26
  putstr0(Time);
27
  }
28
  else
29
  putstr0("Fehler");
30
  _delay_ms(1000);
31
  }
32
33
  /*---- Arbeitsschleife ----*/
34
35
36
}
37
38
// http://fxr.watson.org/fxr/source/libkern/strsep.c#L53
39
char * strsep(char ** stringp, const char * delim)
40
{
41
  char *s;
42
  const char *spanp;
43
  int c, sc;
44
  char *tok;
45
46
  if ((s = *stringp) == NULL)
47
    return (NULL);
48
  for (tok = s;;) {
49
    c = *s++;
50
    spanp = delim;
51
    do {
52
      if ((sc = *spanp++) == c) {
53
        if (c == 0)
54
          s = NULL;
55
        else
56
          s[-1] = 0;
57
        *stringp = s;
58
        return (tok);
59
      }
60
    } while (sc != 0);
61
  }
62
  /* NOTREACHED */
63
}

So lange ich die _delay_ms(1000); im Code habe wird nur Fehler gesendet. 
Nehme ich die _delay_ms(1000); raus erscheint ein paar mal Fehler aber 
oft auch das gewüschte $GPRMC und die Zeit. Wie kann ich den Code so 
verändern, das nur noch meine gewünschten Werte ausgegeben werden.
Die USART0 ist mt der RS232 meines Computer verbunden.
Vielen Dank für eure Hilfe!

von nicht "Gast" (Gast)


Lesenswert?

Nur so nebenbei...
> char *stringp = nmea_packet; // Inhalt von nmea_packet wird verändert!
Damit kopierst du nur den Pointer, nicht die eigentlichen Daten!
Du brauchst http://en.wikipedia.org/wiki/Strcpy und Konsorten.

von nicht "Gast" (Gast)


Lesenswert?

Vergiss mal besser was ich oben geschrieben hab, irgendwie schaff ich es 
grad nicht da durchzublicken... gähn

von Rolf Magnus (Gast)


Lesenswert?

Bene Ja schrieb:
> So lange ich die _delay_ms(1000); im Code habe wird nur Fehler gesendet.

Das verwundert nicht sehr. Während der GPS sendet, hängt dein µC in der 
Schleife fest und verliert währenddessen praktisch alles außer dem 
letzten Zeichen. Da die GPS-Empfänger üblicherweise einmal pro Sekunde 
ihre Daten senden, kommt dann natürlich nie was an, weil den Programm 
für diese Sekunde immer komplett "taub" ist.

> Wie kann ich den Code so verändern, das nur noch meine gewünschten Werte
> ausgegeben werden.

Möglicherweise, indem du die unbekannte Funktion getstr1() korrigierst.

von AVRli (Gast)


Lesenswert?

Ich weiß nun nicht wie Du die Daten einsammelst, ich hoffe du 
synchronisierst auf $ oder 0x0d damit Du weißt, wann ein neuer Datensatz 
begonnen hat. In der Sekunde kommt nicht nur Dein GMRS Datensatz sondern 
auch bestimmt 4 weitere (kann man einstellen).

- Daten sammeln und erstmal auf komplette Datensätze konzentrieren
- dann Datensatz filtern in Deinem Fall sind nur GPRMC Datensätze 
interessant, steht was anderes drin kannst gleich wieder raus, dann ist 
das ein uninteressanter Datensatz
- wurde ein GPRMC Datensatz gefunden, Aufbau überprüfen, dazu an das 
Ende der Aufgenommenen Zeile Ende-2 sollte ein * sein, Ende-1 + Ende-0 
ist die Checksumme, diese über die Daten von $ - * berechnen (immer XOR 
Byte für Byte) kommst Du auf das gleicher Ergebnis dann passt der 
Datensatz und Du kannst Dich auf Deine Auswertung stürzen
- die Token Geschiechte habe ich mir nun nicht weiter angesehen, ein 
debugging würde ich vlt. mit einer festen Konstante versuchen, von einem 
Datensatz wo ich weiß das der geht

Viel Erfolg, AVRli...

von Bene J. (terfagter)


Lesenswert?

Hier erst mal die getstr1 und die dazugehörigen Funktionen, die gefehlt 
haben:
1
#define BUFFER_LEN 128
2
3
char Buffer1[BUFFER_LEN];
4
5
volatile uint8_t NextWriteBufferPos1 = 0;
6
volatile uint8_t NextReadBufferPos1 = 0;
7
volatile uint8_t CharsInBuffer1 = 0;
8
9
void initusart1(void)
10
{
11
  UBRR1 = UBRR_VAL0;
12
  UCSR1B |= (1 << TXEN1) | (1 << RXEN1) | (1 << RXCIE1);
13
  UCSR1C |= (1<<UCSZ01)|(1<<UCSZ00);
14
}
15
16
ISR(USART1_RX_vect)
17
{
18
  Buffer1[NextWriteBufferPos1] = UDR1;
19
20
  NextWriteBufferPos1 = ( NextWriteBufferPos1 + 1 ) % BUFFER_LEN;
21
  CharsInBuffer1++;
22
}
23
24
char getch1(void)
25
{
26
  char NextChar = Buffer1[NextReadBufferPos1];
27
  NextReadBufferPos1 = ( NextReadBufferPos1 + 1 ) % BUFFER_LEN;
28
  CharsInBuffer1--;
29
30
  return NextChar;
31
}
32
33
void getstr1( char* Buffer, uint8_t MaxLen )
34
{
35
  uint8_t NextChar='\0';
36
  uint8_t StringLen = 0;
37
 
38
  do {
39
    if( CharsInBuffer1 > 0 )   // es könnten ja auch mehrere Zeichen im Buffer warten
40
    {
41
      NextChar = getch1();      // Hole 1 Zeichen aus dem Buffer
42
                                // und im String ablegen, wenn
43
                                // es sich nicht um das Zeilende handelt UND
44
                                // noch Platz im String ist
45
      if( NextChar != '\n' && StringLen < MaxLen - 1 ) {
46
        *Buffer++ = NextChar;
47
        StringLen++;
48
      }
49
    }
50
  } while( NextChar != '\n' );
51
52
  *Buffer = '\0';
53
}

Die Token-Geschichte funktioniert mit einem festen String schonmal.
Aber wie kann ich jetzt den Datensatz am besten filtern?
Ich dachte, dass ich das eigentlich schon in meiner main-Schleife mache.
Mein erster Gedanke wäre jetzt die getstr1 zu verändern, sodass nach $ 
gesucht wird und ab dann nach dem * und der Checksumme. Die Schritte bis 
zum * würde ich dann mit der Checksumme vergleichen. Wenn es 
übereinstimmt, dann mache ich dann das, was in meiner main steht. Wenn 
es nicht stimmt verwerfe ich den String. Soweit sollte der Grundgedanke 
doch richtig sein?

von AVRli (Gast)


Lesenswert?

Ich weiß nicht genau wie Du es machst, aber ich habe es bis jetzt immer 
so gemacht das ich im ISR die Daten in einen ISR Buffer geschrieben 
habe, bei Dir Buffer 1 den hab ich im Main in einen zweiten Buffer 
Zeichen für Zeihen kopiert bis ich ein CR hatte. Dann hatte ich den 
Datensatz und dann ging es damit weiter. Also mit dem Buffer dann.

Ob Deine Bufferzuordnung so funktioniert, weiß ich nicht. Da muß ich 
erstmal schauen was da genau passiert.

Gruß AVRli...

von Karl H. (kbuchegg)


Lesenswert?

Bene Jan schrieb:

> es nicht stimmt verwerfe ich den String. Soweit sollte der Grundgedanke
> doch richtig sein?

An deiner Stelle würde ich damit anfangen nicht einfach nur "Fehler" 
auszugeben. Denn damit bist du so schlau wie vorher.
Lass dir doch den Anfang des Datensatzes ausgeben, dann siehst du schon 
mehr warum ein empfangener Datensatz abgelehnt wurde.


Um Problemstellen bzw. Fehler zu suchen, ist es eine altbewährte 
Strategie, dass man das Program so umändert, dass es einem bei der 
Fehlersuche hilft. Dazu gehört auch, dass man das Programm relevante 
Information ausgeben lässt.

Natürlich muss man darauf achten, dass man durch die zusätzlichen 
Ausgaben das Timing des Programms nicht allzuseh verändert. Daher 
Kontrollausgaben kurz und bündig halten. Wenn du dir im Fehlerfall die 
ersten 8 oder 10 Buchstaben des fehlerhaften Strings ausgeben lässt, 
dann tut es das fürs erste auch um eine Vorstellung davon zu bekommen, 
was da abgeht.
1
      ...
2
    }
3
    else {
4
      nmea_packet[8] = '\0';   // String künstlich terminieren
5
      putstr0( "Fehler" );
6
      putstr0( nmea_packet );
7
    }
8
  }

und rück deinen Code sauber ein!

von Bene J. (terfagter)


Lesenswert?

Alsoich habe mal versucht, dass umzusetzen was ich wollte. Aber so ganz 
klappt es noch nicht.

Funktion in main.c:
1
void GPSAbfrage(void)
2
{
3
4
  char *Kennung;
5
  char *Time;
6
  char nmea_packet[128];
7
  
8
  getstr1(nmea_packet,128);
9
  
10
  char *stringp = nmea_packet; // Inhalt von nmea_packet wird verändert!
11
  if(strstr( stringp,"$GPRMC" )) 
12
  {
13
    Kennung    = strsep( &stringp, "," ); // $GPRMC
14
    Time       = strsep( &stringp, "," );
15
    putstr0(Kennung);
16
    putstr0(Time);
17
  }
18
19
}


In der uart.h:
1
ISR(USART1_RX_vect)
2
{
3
  Buffer1[NextWriteBufferPos1] = UDR1;
4
5
  NextWriteBufferPos1 = ( NextWriteBufferPos1 + 1 ) % BUFFER_LEN;
6
  CharsInBuffer1++;
7
}
8
9
10
char getch1(void)
11
{
12
  char NextChar = Buffer1[NextReadBufferPos1];
13
  NextReadBufferPos1 = ( NextReadBufferPos1 + 1 ) % BUFFER_LEN;
14
  cli();
15
  CharsInBuffer1--;
16
  sei();
17
18
  return NextChar;
19
}
20
21
22
void getstr1( char* Buffer, uint8_t MaxLen )
23
{
24
  uint8_t NextChar='\0';
25
  uint8_t StringLen = 0;
26
 
27
  do {
28
    if( CharsInBuffer1 > 0 )   // es könnten ja auch mehrere Zeichen im Buffer warten
29
    {
30
    NextChar = getch1();    // Hole 1 Zeichen aus dem Buffer
31
                                // und im String ablegen, wenn
32
                                // es sich nicht um das Zeilende handelt UND
33
                                // noch Platz im String ist
34
    if( NextChar != '\n' && StringLen < MaxLen - 1 && NextChar == '$') {
35
    do 
36
    {
37
      *Buffer++ = NextChar;
38
      StringLen++;
39
      NextChar = getch1();
40
    } while( NextChar != '\n' );  
41
      }
42
    }
43
  } while( NextChar != '\n' );
44
45
  *Buffer = '\0';
46
}

Wenn ich die Funktion GPSAbfrage in meiner main-Schleife dann aufrufe 
und kein delay eingebaut habe, funktioniert sie. Baue ich aber ein delay 
ein oder rufe noch andere Funktionen auf, die etwas Zeit benötigen (zum 
Abfragen von Temperaturen), funktioniert sie nur noch ganz selten.

Ich dachte eigentlich, dass durch den Ringbuffer und die ISR-Funktion es 
so funktonieren sollte, wie ich mir das vorstelle.
Was mache ich denn noch falsch? Bzw. wie kann ich mein Programm so 
umändern, dass mir getstr1() nur den passenden String liefert? Würde es 
etwas bringen die ISR zu verändern?

von Karl H. (kbuchegg)


Lesenswert?

Zunächst mal würde ich hier
1
char getch1(void)
2
{
3
  char NextChar = Buffer1[NextReadBufferPos1];
4
  NextReadBufferPos1 = ( NextReadBufferPos1 + 1 ) % BUFFER_LEN;
5
  cli();
6
  CharsInBuffer1--;
7
  sei();
8
9
  return NextChar;
10
}

eine Sicherung einbauen.
So wie die Funktion jetzt ist, ist es definitiv nicht zulässig sie 
aufzurufen, wenn CharsInBuffer gleich 0 ist.

In deiner vorhergehenden Programmversion hast du das noch berücksichtigt 
in dem du vor Aufruf der Funktion CharsInBuffer abgefragt hast.
In deiner jetzigen nicht mehr:
In
1
void getstr1( char* Buffer, uint8_t MaxLen )
2
{
3
   .....
4
5
    do 
6
    {
7
      *Buffer++ = NextChar;
8
      StringLen++;
9
      NextChar = getch1();
10
    } while( NextChar != '\n' );

wird getchl auf Biegen und Brechen aufgerufen. Dir ist auch völlig egal, 
ob du deinen Buffer zumüllst oder gar überläufst.
Dies deshalb weil du deine String Empfangsroutine jetzt immer 
unlogischer nach dem 'Na da probier ich mal was' Prinzip umänderst.

Wenn du in der String Empfangsroutine sowieso solange wartest, bis eine 
Zeile komplett beisammen ist, dann schreib dir eine Funktion (oder 
ändere die bestehende so um), die auch auf ein Zeichen wartet. Eine 
eigene Funktion für diese Funktionalität:  Warte bis ein Zeichen im 
Empfangsbuffer vorliegt und hole es. Deine getch1 lässt sich relativ 
leicht dahingehend umbauen.
Dann braucht sich ausserhalb der getchl niemand mehr Gedanken darüber 
machen, ob es jetzt überhaupt zulässig ist getchl aufzurufen. Lerne 
daraus, dass du deine eigenen Funktionen falsch benutzt hast, damit dir 
das in Zukunft nicht wieder passiert. Funktionen immer so bauen, dass es 
keine oder zumindest nur wenige Voraussetzungen für deren Aufruf gibt. 
Wenn es aber Voraussetzungen gibt, dann müssen die strikt eingehalten 
werden! Code so bauen, dass man derartige Kontrakt-Verletzungen erkennen 
kann.

Der andere Punkt steht immer noch aus:
Wenn in einem Programm Dinge passieren, die du nicht verstehst, dann 
musst du als allererstes die Ratespielchen abstellen. Und dazu gehört, 
dass dir unter Umständen das Programm hilft, indem du dir für den 
Programmablauf wichtige Variablenwerte ausgeben lässt. Und ja: ein 
String, der von einer Schnittstelle empfangen wird, ist definitv ein 
wichtiger Variablenwert. Denn wenn der nicht stimmt und nicht so 
aussieht wie er deiner Meinung nach aussehen sollte, geht die ganze 
weitere Ausswertung schief.

Mach dir Ausgaben in dein Programm rein! Das geht schneller und ist sehr 
oft weit zielführender als deinen Code hier ins Forum zu stellen und 
nach Hilfe zu rufen. Die 3 Anweisungen für die Ausgabe hast du schnell 
eingebaut und genauso schnell wieder entfernt, wenn alles funktioniert. 
Aber während der Fehlersuche sind sie von unschätzbarem Wert (wenn man 
sich die richtigen Dinge ausgeben lässt! Bei Strings kann das manchmal 
etwas tricky sein)

von Bene J. (terfagter)


Lesenswert?

Nach tagelangem hin und her, dachte ich eigentlich, dass ich es jetzt 
fast geschafft hätte, aber als ich den Code dann in meinen eigentlichen 
Code einbauen wollte, funktionierte er nicht mehr.

Ich habe eine kleine Funktion eingebaut, die überprüft, ob Zeichen in 
meinem Ringbuffer vorhanden sind.
Ich habe auch versucht zu verstehen, was falsch läuft und habe viele 
Ausgaben auf die RS232-Schnittstelle eingebaut. Aber trotzdem habe ich 
Probleme den Fehler zu verstehen und abzuändern.

Mein Code läuft, wenn der Controller sonst nichts anderes macht. Baue 
ich ein delay z.B. 1sec ein, macht der Controller nicht mehr das was ich 
will. D.h. er geht in die Funktion StringHolen in die 1. do-Schleife, 
versucht /n zu finden und geht wieder aus der kompletten Funktion raus. 
1x pro Minute geht er dann in die zweite do-Schleife und bleibt dort, 
bis er /n das nächste mal findet. Es kommt aber nie vor, das $GPRMC 
gefunden wird.
Wo kann ich ansetzen?

main.c:
1
char nmea_packet[128];
2
char buffer[128];
3
void StringHolen(void);
4
5
int main (void) 
6
{
7
  
8
  initusart0();                      //Alle USART-Schnittstellen initialisieren
9
  initusart1();
10
  
11
  sei();
12
  putstr0("Start");
13
    
14
  char *Kennung;
15
  char *Time;
16
  while(1) 
17
  {
18
  
19
     if( char_vorh1() == 1 )
20
       StringHolen();
21
  
22
     if(strstr( buffer,"$GPRMC" )) {
23
       putstr0(buffer);
24
  }
25
  
26
  _delay_ms(1000);
27
  
28
  }
29
}
30
31
void StringHolen(void)
32
{
33
  putch0('1');
34
  uint8_t NextChar='\n';
35
  uint8_t StringLen = 0;
36
  do 
37
  {
38
    if( char_vorh1() == 1 )   // es könnten ja auch mehrere Zeichen im Buffer warten
39
    {
40
      putch0('2');
41
      NextChar = getch1();    // Hole 1 Zeichen aus dem Buffer
42
                  // und im String ablegen, wenn
43
                  // es sich nicht um das Zeilende handelt UND
44
                  // noch Platz im String ist
45
      if( NextChar != '\n' && StringLen < 127 && NextChar == '$') 
46
      {
47
        do 
48
        {
49
          putch0('3');
50
          buffer[StringLen] = NextChar;
51
          StringLen++;
52
          NextChar = getch1();
53
        } while( NextChar != '\n' );  
54
      }
55
    }
56
  
57
  } while( NextChar != '\n' );
58
59
  buffer[StringLen] = '\0';
60
}
61
62
63
int char_vorh1(void)
64
{
65
  if( CharsInBuffer1 == 0 )
66
     return 0;
67
  return 1;
68
}

Die anderen Funktionen sind gleich geblieben.
Ich würde den Fehler gerne selber lösen, aber wo genau ich ansetzen soll 
weiß ich nicht!?

von Karl H. (kbuchegg)


Lesenswert?

Bene Jan schrieb:

> Die anderen Funktionen sind gleich geblieben.

Das heisst, du bügelst hier
1
        do 
2
        {
3
          putch0('3');
4
          buffer[StringLen] = NextChar;
5
          StringLen++;
6
          NextChar = getch1();
7
        } while( NextChar != '\n' );

immer noch den buffer nieder?

> Ich habe eine kleine Funktion eingebaut, die überprüft, ob Zeichen
> in meinem Ringbuffer vorhanden sind.

Die hättest du dir sparen können.
Was ist so schwer daran getch1 so umzubauen, dass es auf ein Zeichen 
wartet?
1
char getch1(void)
2
{
3
  while( CharsInBuffer == 0 )
4
    ;
5
6
  char NextChar = Buffer1[NextReadBufferPos1];
7
  NextReadBufferPos1 = ( NextReadBufferPos1 + 1 ) % BUFFER_LEN;
8
  cli();
9
  CharsInBuffer1--;
10
  sei();
11
12
  return NextChar;
13
}

Damit ist sicher gestellt, dass getchl mit Sicherheit immer ein Zeichen 
holt, WENN eines im Ringbuffer vorhanden ist. Den Fall, dass getch1 
zurückkehrt ohne ein Zeichen (bzw. ein altes Zeichen) aus dem Rungbuffer 
geholt zu haben kann es nicht mehr geben.

1
void StringHolen(void)
2
{
3
  uint8_t NextChar='\n';
4
  uint8_t StringLen = 0;
5
6
  do {
7
    NextChar = getch1();
8
  } while( NextChar != '$' );
9
10
  do 
11
  {
12
    if( StringLen < 127 ) 
13
    {
14
      buffer[StringLen] = NextChar;
15
      StringLen++;
16
    }
17
18
     NextChar = getch1();
19
  
20
  } while( NextChar != '\n' );
21
22
  buffer[StringLen] = '\0';
23
}

von Karl H. (kbuchegg)


Lesenswert?

Und die wichtigste aller Kontrollausgaben hast du wieder nicht gemacht.
1
  while(1) 
2
  {
3
  
4
     StringHolen();
5
6
     putstr0( "Zeile vorhanden: *" );
7
     buffer[8] = '\0';   // buffer abschneiden, damit die Ausgabe nicht zu
8
     putstr0( buffer );  // lange dauert und man Gefahr läuft, an der GPS Front
9
     putstr0( "*\n" );   // etwas zu verpassen
10
11
     if(strstr( buffer,"$GPRMC" )) {
12
       putstr0( "$GPRMC erkannt\n" );
13
     }
14
  }

von Karl H. (kbuchegg)


Lesenswert?

Warum hast du hier
1
void StringHolen(void)

 die Argmuente entfernt, die da ursprünglich mal waren?
1
void getstr1( char* Buffer, uint8_t MaxLen )
2
{

Du arbeitest im Moment in die genaue Gegenrichtung dessen, wohin die 
Reise eigentlich gehen sollte.

von Wolfgang G. (wgrimm55)


Lesenswert?

Hi all

will mich auch mal eintakten. beschaeftige mich z.Z auch mit dem Thema,
will einen Autopiloten fuer Flugmodelle bauen, das nach GPS koordinaten 
fliegt. Ziel ist es ein Modell das ausser Reichweite (Sicht oder Funk)
ist, sicher wieder zum Startpunkt zurueck zu bringen. Hatten
schon einige Modellverluste dadurch.
Bin noch ganz am Anfang, aber hier schon mal meine GPS Versuche.
Bevor ich alles in eine Mega32 programmiere habe ich das Grundprinzip 
der Datenauswertung erstmal auf Computer emuliert.
Und setze will das nun auf den Mega32 umsetzen.
Sehe darin kein grosses Problem, da die wichtigsten Grundfunktionen
getestet sind.
Bei meinen Versuchen verwende ich immer die int routinen (USART SPI
TIMER,..), finde es vom  handling einfacher, hat sicher auch Nachteile.

hier mein code:
//-------------------------------------------------------------------

char  stream [256];
int  Status;
int  ValidDataFlag;
char  Key    [86];
char  ValidData  [86];
char  Breite    [12];
char  Laenge    [12];
char  Geschwindigkeit  [32];
char  Qualitaet  [4];
char  Satellit  [4];
char  Hoehe    [8];

//--------------------------------------------------------------
// emulierte int routine, wird spaeter durch
// ATMega 32 int ersetzt
// jedes ankommende Zeichen wird unter Key gespeichert
// wenn ende \n erkannt dann nach ValidData kopieren
// um sicher zu stellen das waehrend des auswerten
// die Daten nicht durch neue daten ueberschrieben
// werden ( i.A unwahrscheinlich) aber besser ist besser
// da prozessor neben bei noch andere Aufaben ueber nehmen soll
// ValidDataFlag zeigt main an ob  gueltige daten vorhanden
//-------------------------------------------------------------
// emulierte recv int routine
// in Mega32 entfaellt dann (char *s1)
void SIGNAL_RECV (char *s1)
{
  char  RecData;
  char  Tmp [2];
  int  count;
// naechste Zeile wenn Mega32 verwendet
// RecData = UDR;

// naechate Zeile entfallet in Mega32
  RecData  = s1[0];
  sprintf (Tmp,"%c",RecData);

  switch (Status)
  {
    case 0:
    {
      if (RecData == '$')
      {
        Key [0]    = '\0';
        Status    = 1;
        ValidDataFlag  = 0;
      }
      break;
    }
    case 1:
    {
      if (RecData == '$')     // error, string untgueltig wird verworfen
      {
        Key [0]    = '\0';
        Status    = 0;
      }
      else
      {
        if (RecData == '\n')      // string ende erkannt
        {
//--------------------------------------------------------------------
// auf Key steht jetzt z.B.
// GPRMC,191410,A,4735.5634,N,00739.3538,E,0.0,0.0,181102,0.4,E,A*19
//--------------------------------------------------------------------

         ValidDataFlag  = 1;    // Flag zur Weiterverarbeitung setzen
          Status    = 0;
          ValidData [0]   = '\0'; // kopieren in Auswertebereich
          strcat (ValidData,Key);
        }
        else
        {
          strcat (Key,Tmp);
          if (strlen(Key) > 86) //Laenge auf 82 Zeichen fest, NMEA
          {
            Status  = 0;  // abbruch ende nicht erkannt, string zu lang
          }
        }
      }
    }
  }
}

//---------------------------------------------------------------------- 
--
// pars routine erkennet trenn/ende Zeichen
// hier , space \0 \n
// Leerzechen am Anfang werden ignoriert
// beispiel wenn **s1 GPRMC,191410,A,ist
//          dann steht danach *s1 auf GPRMC,191410,A,
//          und der return wert auf ,191410,A,
//---------------------------------------------------------------------- 
--

char *pars (char**s1)
{
  static  char  *s2;
  s2  = *s1;
  while (*s2 == ' ' && *s2 != '\0')        // leerzeichen ignorieren
    s2++;

  *s1  = s2;                  // string anfang

  if (*s2 != '\0' && *s2 != '\n')
  {
 //ende string feststellen
   while (*s2 != '\0' && *s2 != ' ' && *s2 != ',' && *s2 != '\n')
      s2++;
  }
  return (s2);
}
//---------------------------------------------------------------------- 
---
// routine gibt decodierten string zurueck
// beispiel
// input **s1, GPRMC,191410,A,
// output *s1, 191410,A,
//        return string, GPRMC
//---------------------------------------------------------------------- 
---
char *ParsValue (char **s1)
{
  char     *p1,*p2;
  static  char  tmp [32];

  p1  = *s1;
  p2  = pars (&p1);
  tmp [0]  = '\0';
  strncat (tmp,p1,p2 - p1);
  p1  = tmp;
  *s1  = p2;

  return p1;
}

//------------------------------------
// decodiere Daten
// datenstehen unter ValidData
//------------------------------------

void DecodeGpsData ()
{
  char  *p1,*p2;
  char  code [32];
  char  tmp [32];

  p1  = ValidData;
  p2  = pars (&p1);
  code [0]  = '\0';
  strncat (code,p1,p2 - p1);
  if (strcmp(code,"GPRMC") == 0)
  {
    p1  = ++p2;
    p2  = ParsValue (&p1);          // ignore time
    p2  = ParsValue (&(++p1));
    if (strcmp (p2,"A") == 0)          // check ob GPS data valid
    {
      p2      = ParsValue (&(++p1));
      Breite [0]    = '\0';
      strcat (Breite,p2);          // speichert die Breite

      p2      = ParsValue (&(++p1));    // ignore nord or sued
      p2      = ParsValue (&(++p1));
      Laenge [0]    = '\0';
      strcat (Laenge,p2);          // speichert die Laenge

      p2      = ParsValue (&(++p1));    // ignore ost or west
      p2      = ParsValue (&(++p1));
      Geschwindigkeit [0]  = '\0';
      strcat (Geschwindigkeit,p2);   // speichertgeschwindigkeits info

    }
  }
  if (strcmp(code,"GPGGA") == 0)
  {
    p1      = ++p2;
    p2      = ParsValue (&p1);      // ignore time

    p2      = ParsValue (&(++p1));
    Breite [0]    = '\0';
    strcat (Breite,p2);

    p2      = ParsValue (&(++p1));      // ignore nord or sued
    p2      = ParsValue (&(++p1));
    Laenge [0]    = '\0';
    strcat (Laenge,p2);

    p2      = ParsValue (&(++p1));      // ignore ost or west
    p2      = ParsValue (&(++p1));
    Qualitaet [0]  = '\0';
    strcat (Qualitaet,p2);

    if (strcmp(Qualitaet,"1") == 0)
    {
      p2      = ParsValue (&(++p1));
      Satellit [0]  = '\0';
      strcat (Satellit,p2);

      p2      = ParsValue (&(++p1));    // ignore HDOP
      p2      = ParsValue (&(++p1));
      Hoehe [0]    = '\0';
      strcat (Hoehe,p2);          // speichert die hoehe
    }
  }
}
//------------------------------------
// ueberprueft die checksumme der daten
//------------------------------------
int CheckSum ()
{
  char    *p1,*p2;
  p1    = Key;

  unsigned int Checksum     = 0;
  unsigned int OriginalCheckSum  = 0;

  if (strlen(p1) == 0)
  {
    return 0;
  }

  while (*p1 != '*')              // berechnen der checksumme
  {
       Checksum ^= *p1;
    p1++;
  }
  p1++;
  p2  = p1 + 1;

 // lesen der orginalchecksumme
  OriginalCheckSum  = (*p1 - '0') << 4 | (*p2 -'0');

  if (OriginalCheckSum == Checksum)
  {
    return 1;              // kein datenfehler
  }
  else
  {
    return 0;              // datenfehler
  }
}

int main(int argc, char *argv[])
{
  char    *p1,*p2;
  char    ret;

  stream [0]    = '\0';
  strcat 
(stream,"$GPRMC,191410,A,4735.5634,N,00739.3538,E,0.0,0.0,181102,0.4,E,A 
*19\n$GPGGA,191410,4735.5634,N,00739.3538,E,1,04,4.4,351.5,M,48.0,M,,*45 
\n");

  p1      = stream;
  Status      = 0;
  Breite [0]    = '\0';
  Laenge [0]    = '\0';
  Geschwindigkeit  [0]  = '\0';
  Hoehe [0]    = '\0';


  while (*p1 != '\0')
  {
    SIGNAL_RECV (p1);
// Flag zeigt an ob string komplett vorhanden von $ bis \n,
// $ nicht im string enthalten
   if (ValidDataFlag == 1)
    {
// pruefen ob checksumme o.k wenn nicht verwerfen
     ret  = CheckSum ();
      if (ret == 1)
      {
// decodieren der Strings nach den Daten, hier GPRMC und GPGGA daten
       DecodeGpsData ();
      }
    }
    p1++;
  }
}

Habe zur Zeit die Transmit int routine fuer mega32 implemtiert, und 
funktioniert.
Als GPS empfaenger verwende ich den  NL 552 ETTL  mit 38400 Baud.

Alle Info zu GPS habe ich mir von der Seite

http://www.kowoma.de/gps/

geholt.
Habe mich hier eingetaktet um meine Erfahrungen zu vermittlen.
Vielleicht kann das als Anregung mit dienen. Es gibt sicher noch andere
Wege, die sicher auch optimaler sind.
Moechte das nur als Anregung sehen

Gruss W.G.

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
Noch kein Account? Hier anmelden.