Pages: [1]   Go Down
Author Topic: GPS Uhrzeit auswerten  (Read 1049 times)
0 Members and 1 Guest are viewing this topic.
Germany, BW
Offline Offline
Newbie
*
Karma: 0
Posts: 6
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Hallo,

ich programmiere schon eine Weile mit dem Arduino. Jetzt bin ich aber an einer Stelle angekommen, bei der ich nicht mehr weiter weiß. Ich habe ein GPS-Modul (NL-552ETTL) das ich über SoftwareSerial am Arduino Uno angeschlossen habe. Folgende Strings bekomme ich mit 9600 Baud gesendet:

Code:
$GPRMC,235945.180,V,0000.0000,N,00000.0000,E,0.00,0.00,120136,,,N*74
$GPVTG,0.00,T,,M,0.00,N,0.0,K,N*02
$GPGGA,235945.180,0000.0000,N,00000.0000,E,0,00,99.9,-17.0,M,17.0,M,,0000*7C
$GPGSA,A,1,,,,,,,,,,,,,99.9,99.9,99.9*09
$GPGSV,1,1,00*79
$GPGLL,0000.0000,N,00000.0000,E,235945.180,V,N*44

Für mich ist $GPGGA am wichtigsten, da die ersten Zahlen die Uhrzeit sind, hier: 23:59:45 UTC.
Wie mache ich das jetzt am besten, dass nur die $GPGGA-Zeile ausgewertet wird und die anderen ignoriert werden? Die Uhrzeit soll dann über die USB-Schnittstelle im Terminal angezeigt werden.

Gruß
Felix
Logged

Germany S-H
Offline Offline
Faraday Member
**
Karma: 140
Posts: 2898
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Wie mache ich das jetzt am besten, dass nur die $GPGGA-Zeile ausgewertet wird und die anderen ignoriert werden? Die Uhrzeit soll dann über die USB-Schnittstelle im Terminal angezeigt werden.

1. Zeilenpuffer als C-String deklarieren, z.B. "char linebuffer[80];" dann
2. die an der seriellen Schnittstelle eintreffenden Zeichen zeilenweise einlesen, dann
3  if (strstr(linebuffer,"$GPGGA")==linebuffer)

Eins, zwei oder drei, wo liegt das Problem?
Logged

Germany, BW
Offline Offline
Newbie
*
Karma: 0
Posts: 6
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Danke für die schnelle Antwort.

Quote
Eins, zwei oder drei, wo liegt das Problem?

Irgendwie bei allem  smiley-roll-sweat

Das ist mein Code den ich bis jetzt habe:
Code:
#include <SoftwareSerial.h>
#include <string.h>

SoftwareSerial gps(8, 9); // RX, TX

char linebuffer[80];

void setup()
{
  Serial.begin(19200);
  gps.begin(9600);
}

void loop()
{
  if (strstr(linebuffer,"$GPGGA")==linebuffer)
    Serial.write(gps.read()); 
}
Logged

Germany S-H
Offline Offline
Faraday Member
**
Karma: 140
Posts: 2898
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Irgendwie bei allem  smiley-roll-sweat

Das ist mein Code den ich bis jetzt habe:

Oh, oh, ich sehe schon.

Ich habe zwar kein solches GPS-Modul, aber ich habe mal versucht, Dir einen Sketch zu machen.

Code:
#include <SoftwareSerial.h>
#include <string.h>

SoftwareSerial gps(8, 9); // RX, TX

char linebuffer[80]; // Zeilenpuffer als C-String

void setup()
{
  Serial.begin(19200);
  gps.begin(9600);
}

boolean timeFromGps()
{
  int charnum;
  char c;
  if (gps.available()) // Es ist mindestens 1 Zeichen im seriellen Eingangspuffer
  {
    delay(100);  // Zeit geben, um die Zeile komplett zu empfangen
    memset(linebuffer,0,sizeof(linebuffer)); // Zeilenpuffer löschen
    charnum=0;
    while (gps.available())
    {
      c=gps.read(); // Zeichen von Schnittstelle einlesen
      if (c>=32 && charnum<sizeof(linebuffer)-1) // Nur Zeichen mit ASCII-Code ab Leerzeichen
      {
        linebuffer[charnum] = c;
        charnum++;
      }
      else break; // Sonst liegt ein Steuerzeichen vor, z.B. "Zeilenende"
    }
    if (strstr(linebuffer,"$GPGGA")==linebuffer)  // wonach wir suchen
    {
      // Ab Zeichen 7 insgesamt 10 Zeichen an den Anfang des Zeilenpuffers kopieren
      strncpy(linebuffer,&linebuffer[7],10);
      linebuffer[10]=0; // Stringende nach 10 Zeichen setzen
      return(true); // Rückkehr mit Erfolgsmeldung
    } 
  } 
  return(false); // Leider nichts empfangen
}   


void loop()
{
  if (timeFromGps())
    Serial.println(linebuffer);
}

Die timeFromGps() Funktion soll die ganze Arbeit erledigen, Du brauchst diese Funktion in der Loop nur regelmäßig aufrufen, und wenn der Rückgabewert "true" ist, dann steht die herauskopierte Zeit im linebuffer.

Beim Herauskopieren der Zeit aus der Zeile habe ich mich jetzt mal darauf verlassen, dass die Zeit immer mit 10 Stellen (einschließlich drei Nachkommastellen) ab dem 7. Zeichen in der Zeile angeliefert wird. Falls das nicht immer der Fall ist, muß man an der Stelle natürlich nachbessern.

Schau's Dir mal an, ob Du mit den angebrachten Kommentaren klarer siehst, was da überhaupt abläuft.

P.S.: Du brauchst dringend einen C-Programmierkurs oder ein Programmierbuch zum Selbststudium.
Logged

Germany, BW
Offline Offline
Newbie
*
Karma: 0
Posts: 6
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Vielen Dank für den Sketch, ich bin begeistert.

Ich habe den Code gerade mal ausprobiert, bekomme allerdings keine Zeichen gesendet. Später werde ich mir das ganze noch einmal genauer anschauen.

Quote
P.S.: Du brauchst dringend einen C-Programmierkurs oder ein Programmierbuch zum Selbststudium.
Das muss ich wohl. Ich programmiere zwar schon seit Jahren mit AVR (Atmel) Studio, aber so wie ich das sehe ist das großer Aufholbedarf  smiley

Gruß
Felix
Logged

Germany S-H
Offline Offline
Faraday Member
**
Karma: 140
Posts: 2898
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Ich habe den Code gerade mal ausprobiert, bekomme allerdings keine Zeichen gesendet.

Von meinem Sketch wird jetzt alles rausgefiltert, was keine Zeitangabe ist.

Wie oft wird die Zeit im seriellen Protokoll gesendet?
So lange müßtest Du dann natürlich warten, bis Du was im seriellen Monitor siehst.

Wenn Du doch wieder alles angezeigt bekommen möchtest, z.B. zum Debuggen, kannst Du die loop-Funktion ändern auf:

Code:
void loop()
{
  if (timeFromGps())
    Serial.println(linebuffer);
  else
    Serial.println(linebuffer);
}

Dann wird im Fall einer Zeitangabe die verarbeitete und herauskopierte Zeit in der Zeile angezeigt und ansonsten die unveränderte Zeile wie sie empfangen wurde.

Wie schnell kommen denn die Zeilen hintereinander weg? Ich bin mal ausgegangen von ca. 1 Sekunde pro Zeile. Sobald mehr als 10 Zeilen pro Sekunde gesendet werden, könnte es sein, dass mein Code nicht mehr läuft, wegen "delay(100)", d.h. es wird eine Zehntelsekunde auf den Empfang einer vollständigen Zeile gewartet, und das funktioniert nur, wenn in einer Zehntelsekunde nicht mehr als eine Zeile gesendet wird. Wenn Dein Modul ständig mit Volldampf und ohne Pause Zeile für Zeile für Zeile sendet, müßte die Einleseroutine darauf angepaßt werden und etwas anders aussehen.
Logged

Germany, BW
Offline Offline
Newbie
*
Karma: 0
Posts: 6
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Quote
Wie schnell kommen denn die Zeilen hintereinander weg? Ich bin mal ausgegangen von ca. 1 Sekunde pro Zeile. Sobald mehr als 10 Zeilen pro Sekunde gesendet werden, könnte es sein, dass mein Code nicht mehr läuft, wegen "delay(100)", d.h. es wird eine Zehntelsekunde auf den Empfang einer vollständigen Zeile gewartet, und das funktioniert nur, wenn in einer Zehntelsekunde nicht mehr als eine Zeile gesendet wird. Wenn Dein Modul ständig mit Volldampf und ohne Pause Zeile für Zeile für Zeile sendet, müßte die Einleseroutine darauf angepaßt werden und etwas anders aussehen.

Ich kann bei diesem Modul die Zeit einstellen. Zur Zeit sind es 1000ms. Also jede Sekunde werden diese 6 Zeilen gesendet.

Jetzt habe ich loop-Schleife geändert und bekomme im Terminal folgendes:
Code:
000146.000
000146.000
000146.000
$GPRMC,000147.000,V,0000.0000,N,00000.0000,E,0.00,0.00,060180,,2

Gruß
Logged

Germany S-H
Offline Offline
Faraday Member
**
Karma: 140
Posts: 2898
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Ich kann bei diesem Modul die Zeit einstellen. Zur Zeit sind es 1000ms. Also jede Sekunde werden diese 6 Zeilen gesendet.

Jetzt habe ich loop-Schleife geändert und bekomme im Terminal folgendes:

Hm, 6 Zeilen pro Sekunde. Und die werden offenbar ohne Pause nacheinander weg gesendet?

Das paßt mit meinem Einlesecode und dem darin enthaltenen "delay(100)" nicht zusammen. Der von mir gepostete Code funktioniert nur, wenn nach jeder gesendeten Zeile mindestens 100 Millisekunden lang Pause auf der seriellen Schnittstelle herrscht. So läuft offenbar der serielle Eingangspuffer über und Du bekommst nur noch verstümmelte Zeilen.

Du brauchst eine andere Einlese-Logik ohne delay, wenn Du Dein Modul nicht so umkonfigurieren kannst, dass es nach jeder Zeile für mindestens 100 ms nichts sendet, sondern z.B. nur eine Zeile pro eine Sekunde.

Muss ich nochmal überlegen. Auf jeden Fall muß es ohne delay auskommen, denn Dein Modul sendet zu viele Zeichen zu schnell hintereinander weg. Und der serielle Eingangspuffer kann überhaupt nur 63 Zeichen zwischenpuffern.
Logged

Germany, BW
Offline Offline
Newbie
*
Karma: 0
Posts: 6
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

So, habe jetzt über die Software des GPS-Moduls die Baudrate auf 4800 herruntergesetzt und das Delay auf 2000ms erhöht.

Quote
Hm, 6 Zeilen pro Sekunde. Und die werden offenbar ohne Pause nacheinander weg gesendet?
Das ist die hier die Frage. Im Terminal bekomme ich ja immer neue Zeilen, also muss ein Zeilensprungbefehl gesendet werden.

Ich werde mich mal mit der Software auseinandersetzen, vielleicht ist es ja möglich nur die $GPGGA Zeile zu senden.

Gruß

Nachtrag:
Der Linebuffer muss doch 78 sein, oder?
Quote
NMEA GPGGA,  Size  78,  'Global Positioning System Fix Data'
« Last Edit: March 10, 2013, 07:13:35 am by socke » Logged

Germany S-H
Offline Offline
Faraday Member
**
Karma: 140
Posts: 2898
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Der Linebuffer muss doch 78 sein, oder?

Der linebuffer muss mindestens so lang sein wie die längste Zeile, dier er enthalten soll, PLUS EINS für das Zeilendende-Zeichen (Nullzeichen) bei C-Strings. D.h. um eine Zeile mit 78 Zeichen aufzunehmen muß mindestens ein "char linebuffer[79] deklariert sein.

So, anbei mal ein verbesserter Auslesesketch zum Auslesen der Zeitangabe "ohne delay", so daß num vom Prinzip her keine Annahmen über die Geschwindigkeit der Aussendung und Pausen zwischen den Zeilen gemacht werden müssen.

Wenn Du die Kommentarstriche der in der loop auskommentierten Zeile entfernst, bekommst Du die anderen Zeilen.

Code:
#include <SoftwareSerial.h>

SoftwareSerial gps(8, 9); // RX, TX

enum gpsResults {GPSNONE,GPSTIME,GPSOTHER};
char linebuffer[80]; // Zeilenpuffer als C-String
char timebuffer[11]; // Zeitpuffer als C-String

void setup()
{
  Serial.begin(19200);
  gps.begin(9600);
}

int timeFromGps()
{
  static int charnum;
  static boolean eol; // End of Line marker
  char c;
  if (eol) // end of line marker wurde beim letzten Aufruf gesetzt
  { // linebuffer und eol marker löschen
    memset(linebuffer,0,sizeof(linebuffer)); // Zeilenpuffer löschen
    charnum=0; // Zeichenzähler auf 0
    eol=false; // end of line marker auf false setzen
  }
  if (!gps.available()) return GPSNONE;
  while (gps.available())
  {
    c=gps.read(); // Zeichen von Schnittstelle einlesen
    if (c>=32) // Nur Zeichen mit ASCII-Code ab Leerzeichen
    {
      linebuffer[charnum] = c;
      if (charnum<sizeof(linebuffer)-1) charnum++;
    }
    else break; // Sonst liegt ein Steuerzeichen vor, z.B. "Zeilenende"
  }
  if (c<32) eol=true;
  if (eol && strstr(linebuffer,"$GPGGA")==linebuffer)  // Zeilenende und gefunden wonach wir suchen
  {
    // Ab Zeichen 7 insgesamt 10 Zeichen an den Anfang des Zeilenpuffers kopieren
    strncpy(timebuffer,&linebuffer[7],10);
    timebuffer[10]=0; // Stringende nach 10 Zeichen setzen
    memset(linebuffer,0,sizeof(linebuffer)); // Zeilenpuffer löschen
    charnum=0; // Zeichenzähler auf 0
    return GPSTIME; // Zeitstempel in Zeile gefunden
  } 
  else if (eol && strlen(linebuffer)>0) return GPSOTHER;
  else return GPSNONE; // Zeile ist noch nicht vollständig
}   


void loop()
{
  switch (timeFromGps())
  {
    case GPSTIME : Serial.println(timebuffer);break;
//    case GPSOTHER: Serial.println(linebuffer);break;
  } 
}
Logged

Germany, BW
Offline Offline
Newbie
*
Karma: 0
Posts: 6
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Es funktioniert!
Vielen Dank. Ich bin echt überrascht wie gut man hier im Forum Hilfe bekommt, da gibt es auch anderes.

Ich werde den Code für meine Anwendung noch ein bisschen anpassen und dann stimmt es. Auch in C werde ich mich jetzt intensiever einarbeiten.

Gruß
Felix
Logged

Pages: [1]   Go Up
Jump to: