GPS - NMEA Daten Auswertung

    This site uses cookies. By continuing to browse this site, you are agreeing to our Cookie Policy.

    • GPS - NMEA Daten Auswertung

      GPS ist eine tolle Sache, der freundliche Chinese hat mir einen GPS Empfänger verkauft, der viel mehr kann, als ich brauche.
      Der Empfänger braucht nur eine Stromversorgung und gibt dann alle Sekunde ein Datenpaket aus, bestehend aus mehreren Zeilen Text, die immer mit $ beginnen und mit CRLF enden.
      Hier der Wikipedia-Eintrag: de.wikipedia.org/wiki/NMEA_0183

      Ich habe mir die GPRMC Daten rausgegriffen, da sie mir am einfachsten erscheinen für ein spätere Projekt eines Datenloggers.
      Hier brauche ich neben der Position, also Länge und Breite, auch die Uhrzeit und das Datum.
      Ziel ist es, später einen GPX-Datensatz als Pfad zu generieren, der in Google Maps lesbar ist.

      Das ist das Stichwort zum eigentlichen Problem.

      Während NMEA eine Breitenangabe in der Form einer 4-stelligen Breite in Grad mit angehängten Minuten und als Nachkomma noch die dezimalen Bruchteile der Minuten ausgibt, erwartet GPX die Breite 2 stellig mit dezimalem Nachkomma-Rest, was mir ehrlich gesagt, wirklich gefällt.
      Beispiel Berliner Reichstag: Breite 52.518620 Länge 13.376187

      https://www.google.de/maps/place/52°31'07.0"N+13°22'34.3"E/@52.51862,13.3739983,17z

      In NMEA sieht das so aus: Breite 5231.070 und Länge 1322.343

      Damit kann aber GPX nichts anfangen, also müssen die Daten zerlegt, berechnet und neu zusammengefügt werden.

      Ich mache das mit der Split-Funktion, ist ja alles schön mit Komma getrennt.

      Danach werden die 2 Stellen vor dem Punkt ausgelöst (das ist ja die Nachkommastelle in Minuten) und mit dem Wert nach dem Punkt vereinigt, um mit der Teilung durch 60 den dezimalen Anteil zu bekommen. Das ganze wird dann wieder zusammengefügt und als String ausgegeben.

      ( z.B. Sub Breiteerfassen)

      Das funktioniert hier auf dem Schreibtisch super, nur ist das sehr mühsam und wie ich finde, sehr fehleranfällig. Wenn nur eine Stelle verschoben ist, passt es schon nicht mehr. Die ganze String/Long Orgie gefällt mir nicht wirklich.

      Habt ihr da andere Ansätze oder geht das nicht anders?
      Die Daten sollen später mal sparsam im internen EEprom oder kleinen externen EEprom/Flash abgelegt werden und bei Anforderung als GPX-File ausgegeben werden (das Zusammenbasteln steht auch noch auf der Agenda ;))

      https://www.google.de/maps/place/52°31'07.0"N+13°22'34.3"E/@52.51862,13.3739983,17z

      BASCOM Source Code: NMEA Auswertung

      1. $regfile = "m328pdef.dat"
      2. $crystal = 16000000
      3. $hwstack = 34
      4. $swstack = 32
      5. $framesize = 40
      6. $baud = 9600
      7. Ddrb.5 = 1
      8. Led Alias Portb.5
      9. Ddrb.4 = 1
      10. Led2 Alias Portb.4
      11. Taster Alias Pinc.0
      12. Portc.0 = 1
      13. Config Clock = User
      14. Config Date = Dmy , Separator = .
      15. On Urxc Serieller_irq
      16. Enable Urxc
      17. Enable Interrupts
      18. Dim Temp As Byte
      19. Dim Flag As Bit
      20. Dim Tastflag As Bit
      21. Dim Zaehler As Byte
      22. Dim Datensorte As Byte
      23. 'Datensorte 1 = GNRMC
      24. Dim Daten As String * 100
      25. Dim Kopierdaten As String * 100
      26. Dim Ar(14) As String * 12
      27. Dim Bcount As Byte
      28. Dim Temps As String * 12
      29. Dim Zeit As String * 8
      30. Dim Datum As String * 8
      31. Dim Gps_hour As Byte
      32. Dim Breite As String * 12
      33. Dim A As Long
      34. Dim B As Long
      35. Dim L As Long
      36. Dim Laenge As String * 12
      37. Dim Length As Byte
      38. Dim Lsyssec As Long
      39. Tastflag = 1
      40. Const Speichergroesse = 120
      41. Dim Br(speichergroesse) As Long
      42. Dim Le(speichergroesse) As Long
      43. Dim Dt(speichergroesse) As Long
      44. Dim Datenzaehler As Byte
      45. Do
      46. Bitwait Flag , Set
      47. If Taster = 0 Then Toggle Tastflag
      48. Led = 1
      49. Flag = 0
      50. Bcount = Split(kopierdaten , Ar(1) , ",")
      51. Gosub Zeiterfassen
      52. Gosub Datumerfassen
      53. Gosub Breiteerfassen
      54. Gosub Laengeerfassen
      55. If Tastflag = 1 Then
      56. Print Bcount ; " " ; Kopierdaten
      57. ' Print Ar(1) ; "," ; Ar(2) ; "," ; Ar(3) ; "," ; Ar(4) ; "," ; Ar(5) ; "," ; Ar(6) ; "," ; Ar(7) ; "," ; Ar(8) ; "," ; Ar(9) ; "," ; Ar(10) ; "," ; Ar(11)
      58. Print Zeit ; " " ; Breite ; " " ; Laenge ; " " ; Lsyssec ; " " ; Time(lsyssec) ; " " ; Date(lsyssec)
      59. Print B ; " " ; L
      60. End If
      61. If Ar(3) = "A" Then
      62. Incr Datenzaehler
      63. If Datenzaehler > Speichergroesse Then Datenzaehler = 1
      64. Br(datenzaehler) = B
      65. Le(datenzaehler) = L
      66. Dt(datenzaehler) = Lsyssec
      67. Else
      68. Led2 = 1
      69. End If
      70. Waitms 100
      71. ' Print "Warte auf Daten "
      72. Led = 0
      73. Led2 = 0
      74. Loop
      75. Laengeerfassen:
      76. Laenge = Mid(ar(6) , 4 , 2)
      77. Length = Len(ar(6))
      78. Length = Length - 6
      79. Temps = Mid(ar(6) , 7 , Length)
      80. Laenge = Laenge + Temps
      81. A = Val(laenge)
      82. Laenge = Left(ar(6) , 3)
      83. L = Val(laenge)
      84. Laenge = Laenge + "."
      85. A = A / 60
      86. L = L * 100000
      87. L = L + A
      88. Laenge = Laenge + Str(a)
      89. Return
      90. Breiteerfassen:
      91. Breite = Mid(ar(4) , 3 , 2)
      92. Length = Len(ar(4))
      93. Length = Length - 5
      94. Temps = Mid(ar(4) , 6 , Length)
      95. Breite = Breite + Temps
      96. A = Val(breite)
      97. Breite = Left(ar(4) , 2)
      98. B = Val(breite)
      99. Breite = Breite + "."
      100. A = A / 60
      101. B = B * 100000
      102. B = B + A
      103. Breite = Breite + Str(a)
      104. Return
      105. Zeiterfassen:
      106. Temps = Left(ar(2) , 2)
      107. Gps_hour = Val(temps)
      108. Gps_hour = Gps_hour + 2
      109. If Gps_hour > 23 Then
      110. Gps_hour = Gps_hour - 24
      111. End If
      112. Zeit = Str(gps_hour)
      113. Zeit = Zeit + ":"
      114. Temps = Mid(ar(2) , 3 , 2)
      115. Zeit = Zeit + Temps
      116. Zeit = Zeit + ":"
      117. Temps = Mid(ar(2) , 5 , 2)
      118. Zeit = Zeit + Temps
      119. Return
      120. Datumerfassen:
      121. Temps = Left(ar(10) , 2)
      122. Datum = Temps + ":"
      123. Temps = Mid(ar(10) , 3 , 2)
      124. Datum = Datum + Temps
      125. Datum = Datum + ":"
      126. Temps = Mid(ar(10) , 5 , 2)
      127. Datum = Datum + Temps
      128. Lsyssec = Syssec(zeit , Datum)
      129. Return
      130. Serieller_irq:
      131. Temp = Udr
      132. 'Print Chr(temp); 'Debug
      133. If Temp = 13 Then
      134. If Datensorte = 1 Then
      135. Kopierdaten = Daten
      136. Flag = 1
      137. End If
      138. 'umkopieren
      139. Daten = ""
      140. Zaehler = 1
      141. Datensorte = 0
      142. Else
      143. If Temp = 10 Then
      144. Else
      145. Daten = Daten + Chr(temp)
      146. If Daten = "$GNRMC" Then
      147. Datensorte = 1
      148. End If
      149. End If
      150. End If
      151. Return
      152. 'Beispiel $GPRMC,162614,A,5230.5900,N,01322.3900,E,10.0,90.0,131006,1.2,E,A*13
      Display All
    • Und wenn du beim Einlesen mit zählst und gleich die strings füllst, wie Grad_Breite, Minuten_Breite, Sekunden_Breite..., dann musst du zumindest die strings nicht zusammen setzen.
      Raum für Notizen

      -----------------------------------------------------------------------------------------------------

      -----------------------------------------------------------------------------------------------------
    • Die Umwandlung String->Dec könnte man ein bisschen sparsamer machen.
      Die Anzahl an Stellen ist ja fix, somit ist für jede Ziffer die Wertigkeit bekannt (ohne vorher die Ziffern durchzuzählen).
      Wenn man dann die Zahl von vorne (mit der höherwertigen Stelle) Ziffer für Ziffer betrachtet, kann die Zahl direkt mit umgerechnet werden,
      pro Ziffer hat man eine Substraktion (ASCII auf Zahlenwert), eine Multiplikation (Zahlenwert mal Wertigkeit) und eine Addition (einzelne Stellen aufaddieren).
      Das könnte man auch auf Byte-Array-Basis umsetzen und spart sich die Stringmanipulationen komplett.
    • @zaubara das ziffernweise hab' ich auch schon angedacht, bin aber nicht draufgekommen, wie das gehen sollte. Ausgang sind 'Minuten', gesucht Nachkomma von Grad. Von 30 (Minuten) zu (,)50 Grad, oder 15 zu 25. Mit was multiplizierst du die 3, dass du zur 5 kommst?
      Zumal 09 Minuten 0,15Grad sind (wenn ich mich nicht verrechnet hab) und da gibt es einen Übertrag auf die vorausgehende Stelle.
      Ok, es geht schon, aber man muss dann ja mit single rechnen, oder erst mit einem großen Wert multiplizieren um im Ganzzahlenbereich zu bleiben.
      Raum für Notizen

      -----------------------------------------------------------------------------------------------------

      -----------------------------------------------------------------------------------------------------

      The post was edited 1 time, last by tschoeatsch ().

    • Das ziffernweise Einlesen betrifft ja mal nur die Umwandlung aus dem empfangenen String zum Zahlenwert. Die Umrechnung könnte man dann mit Single-Berechnungen erledigen, oder auch mit Fixed-Point-Arithmetik, womit sich die CPU wesentlich leichter tut :)

      Aber weil Code mehr sagt als 1000 Bilder, hab ich den Parser mal geschrieben (Code > 10000 Zeichen, ist im Anhang)
      Produziert folgenden Output:

      Source Code

      1. 18:26:14 13.10.06: https://www.google.de/maps/place/52.509765625,13.373046875/@52.509765625,13.373046875,17z
      2. from input: $GPRMC,162614,A,5230.5900,N,01322.3900,E,10.0,90.0,131006,1.2,E,A*13
      3. 11:27:51 28.05.11: https://www.google.de/maps/place/53.361328125,-6.505615234375/@53.361328125,-6.505615234375,17z
      4. from input: $GPRMC,092751.000,A,5321.6802,N,00630.3371,W,0.06,31.66,280511,,,A*45
      5. H1:D4:C9 85.01.E6: https://www.google.de/maps/place/48.1171875,11.625732421875/@48.1171875,11.625732421875,17z
      6. from input: $GPRMC,123519,A,4807.038,N,01131.000,E,022.4,084.4,230394,003.1,W*6A
      7. 20:37:29 08.03.01: https://www.google.de/maps/place/39.12255859375,-121.041259765625/@39.12255859375,-121.041259765625,17z
      8. from input: $GPRMC,183729,A,3907.356,N,12102.482,W,000.0,360.0,080301,015.5,E*6F
      9. 02:24:54 18.07.00: https://www.google.de/maps/place/35.89208984375,139.64404296875/@35.89208984375,139.64404296875,17z
      10. from input: $GPRMC,002454,A,3553.5295,N,13938.6570,E,0.0,43.1,180700,7.1,W,A*3F
      11. 04:30:42 13.11.02: https://www.google.de/maps/place/39.123046875,-121.041015625/@39.123046875,-121.041015625,17z
      12. from input: $GPRMC,023042,A,3907.3837,N,12102.4684,W,0.0,156.1,131102,15.3,E,A*36
      13. WRN 17:29:26 19.08.03: https://www.google.de/maps/place/60.463623046875,22.427734375/@60.463623046875,22.427734375,17z
      14. from input: $GPRMC,152926,V,6027.8259,N,02225.6713,E,10.8,0.0,190803,5.9,E,S*22
      15. 20:40:50 08.03.01: https://www.google.de/maps/place/39.123046875,-121.041259765625/@39.123046875,-121.041259765625,17z
      16. from input: $GPRMC,184050.84,A,3907.3839,N,12102.4772,W,00.0,000.0,080301,15,E*54
      17. 12:47:15 14.08.01: https://www.google.de/maps/place/51.00341796875,5./@51.00341796875,5.,17z
      18. from input: $GPRMC,104715.20,A,5100.2111,N,00500.0006,E,21.7,003.0,140801,01.,W*70
      19. 19:15:37 06.04.01: https://www.google.de/maps/place/33.849365234375,-118.399658203125/@33.849365234375,-118.399658203125,17z
      20. from input: $GPRMC,171537,A,3350.975,N,11823.991,W,0.0,096.5,060401,013.0,E,D*07
      21. WRN 01:06:11 05.10.02: https://www.google.de/maps/place/39.122802734375,-121.041015625/@39.122802734375,-121.041015625,17z
      22. from input: $GPRMC,230611.016,V,3907.3813,N,12102.4635,W,0.14,136.40,041002,,*04
      23. 14:05:57 22.05.03: https://www.google.de/maps/place/50.97900390625,6.7841796875/@50.97900390625,6.7841796875,17z
      24. from input: $GPRMC,120557.916,A,5058.7456,N,00647.0515,E,0.00,82.33,220503,,*39
      25. 02:14:30 22.04.03: https://www.google.de/maps/place/39.123046875,-121.041259765625/@39.123046875,-121.041259765625,17z
      26. from input: $GPRMC,001430.003,A,3907.3885,N,12102.4767,W,000.0,175.3,220403,015.4,E*71
      27. WRN 07:03:06 29.10.03: https://www.google.de/maps/place/42.998046875,-71.50634765625/@42.998046875,-71.50634765625,17z
      28. from input: $GPRMC,050306,V,4259.8839,N,07130.3922,W,010.3,139.7,291003,,*10
      29. 18:22:54 30.03.37: https://www.google.de/maps/place/37.3837890625,145.359619140625/@37.3837890625,145.359619140625,17z
      30. from input: $GPRMC,162254.00,A,3723.02837,N,12159.39853,W,0.820,188.36,110706,,,A*74
      Display All

      Der Parser arbeitet den Input Zeichen für Zeichen ab und konvertiert bzw rechnet die Daten dabei mit um (ohne String- oder Single-Operationen) und prüft die Checksumme.
      Wenn diese Ok ist, wird die Variable Parser_new_data_available auf 1 gesetzt (255 bei Checksummen-Fehler), die Daten (Zeit, Datum, Längen-, Breitengrad und GPS-Status (Ok/Warnung) sind dann in einem 13 Byte großen Datensatz verfügbar.

      Hier wird der serielle Empfang einfach simuliert, die Funktion Nmea_parser könnte aber auch im URXC-Interrupt laufen.
      Wenn korrekte Daten verfügbar sind, wird aus dem Datensatz (13 Byte) der Outputstring generiert.
      Files
      • NMEA-parser.bas

        (16.95 kB, downloaded 33 times, last: )

      The post was edited 3 times, last by zaubara ().

    • @Michael Ich hab' jetzt mal eine Frage zu deinem Aufbau: Wie hast du das Einlesen des Moduls und den Printbefehl unter einem Hut gebracht? AVR-RX an das Modul-TX und AVR-Tx über Usb-Dingens an den Pc und Hterm? Und könnte man das auch mit einem Arduino-board machen, wo ja die RX und TX schon verdrahtet sind? Lasse ich da einfach die Verbindung Arduino-TX zu Modul-RX einfach weg?
      Raum für Notizen

      -----------------------------------------------------------------------------------------------------

      -----------------------------------------------------------------------------------------------------
    • tschoeatsch wrote:

      Frage zu deinem Aufbau: Wie hast du das Einlesen des Moduls und den Printbefehl unter einem Hut gebracht? AVR-RX an das Modul-TX und AVR-Tx über Usb-Dingens an den Pc und Hterm?
      Ehrlicherweise benutze ich hier die nackten RX-TX Pins des Arduino und flashe über ISP

      tschoeatsch wrote:

      Und könnte man das auch mit einem Arduino-board machen, wo ja die RX und TX schon verdrahtet sind? Lasse ich da einfach die Verbindung Arduino-TX zu Modul-RX einfach weg?
      probieren kannst du es ja mal.

      tschoeatsch wrote:

      da ist ein kleiner Fehler passiert, es solte sicher "$GPRMC" heißen.
      Nein, das war Absicht.
      Fälschlicherweise hat sich als Beispiel ein GP eingeschlichen.
      Da mein Empfänger neben GPS auch Glonass kann, sollte natürlich eines der möglichen Satellitensysteme benutzt werden
      GPRMC funktioniert natürlich genauso, aber eben nur mit GPS

      GPS Galileo Glonass pdf
    • Aber beim Arduino sind Rx und Tx ja nicht nackt. Nach meinem Schaltbild geht es über Widerstände zum Usb-Abteil. Vielleicht sind die ja auch zum 'entkoppeln' drin. Ich probier's mal. So wie ich das jetzt lese, hast du ja auch einen Arduino verwendet.
      Raum für Notizen

      -----------------------------------------------------------------------------------------------------

      -----------------------------------------------------------------------------------------------------
    • Ich hab' mich auch mal am Auslesen von Zeit und Datum aus einem billigen GPS-Modul versucht.
      ebay.de/itm/GYNEO6MV2-GPS-Modu…ksid=p2057872.m2749.l2649
      Geht gut, der Haken an der Sache, es ist UTC. Es fehlt noch die Anpassung an die MEZ (einfach) und die eventuelle Sommerzeit (etwas komplizierter)

      BASCOM Source Code

      1. 'Zeit und Datum (UTC) aus GPS-Modul auslesen
      2. 'getestet mit Arduino-uno und Neo-6M-GPS-Modul, Modul-TX an Arduino-RX
      3. $regfile = "m328pdef.dat"
      4. $crystal = 16000000
      5. $hwstack = 34
      6. $swstack = 32
      7. $framesize = 40
      8. $baud = 9600
      9. Config Clock = User
      10. Config Date = Dmy , Separator = .
      11. On Urxc Serieller_irq
      12. Enable Urxc
      13. Enable Interrupts
      14. Dim Zeichen As String * 1 'empfangenes Zeichen
      15. Dim Zz As Byte 'Zeichenzähler
      16. Dim Utc_time As String * 8
      17. Dim Utc_date As String * 8
      18. Dim Einlesen As Bit '=1, dann sind die folgenden empfangenen Zeichen interessant
      19. Dim Zeit_da As Bit '=1 wenn Zeit und Datum empfangen wurden
      20. Dim Zeilencode As String * 5 'Bezeichnung der Datenzeile
      21. Const Vergleichscode = "GPRMC" 'diese Zeile wird gebraucht
      22. Wait 2
      23. Print "Übertragungstest"
      24. Do
      25. If Zeit_da = 1 Then
      26. Print Utc_time ; " " ; Utc_date
      27. Zeit_da = 0
      28. End If
      29. Loop
      30. End
      31. Serieller_irq:
      32. 'Beispiel: $GPRMC,085636.00,A,4934.94722,N,01057.70667,E,0.085,,250719,,,A*78
      33. 'Beispiel: $GPRMC,hhmmss.ss,A,llll.lllll,a,xxxxx.xxxxx,a,x.xxx,,ddmmyy,,,a*hh
      34. ' | | | | | | | | | ||| | |
      35. 'zz Zuordnung 7 9 11 1314 1516 1718 19
      36. ' 20
      37. ' 212325
      38. Zeichen = Chr(udr)
      39. If Zeichen = "$" Then 'Start einer Datenzeile erkannt
      40. Zz = 1 'Zeichenzähler setzen
      41. Einlesen = 1 'Zeichen sind interessant
      42. Zeilencode = ""
      43. Else
      44. If Einlesen = 1 Then
      45. Select Case Zz
      46. Case 1 'Zeichen "G"
      47. Zeilencode = Zeichen
      48. Incr Zz
      49. Case 2 'Zeichen "P"
      50. Zeilencode = Zeilencode + Zeichen
      51. Incr Zz
      52. Case 3 'Zeichen "R"
      53. Zeilencode = Zeilencode + Zeichen
      54. Incr Zz
      55. Case 4 'Zeichen "M"
      56. Zeilencode = Zeilencode + Zeichen
      57. Incr Zz
      58. Case 5 'Zeichen "C"
      59. Zeilencode = Zeilencode + Zeichen
      60. If Zeilencode = Vergleichscode Then
      61. Einlesen = 1 'erwünschte Zeile wird übertragen
      62. Else
      63. Einlesen = 0
      64. End If
      65. Incr Zz
      66. Case 6 : Incr Zz 'Trennungskomma
      67. Case 7 'Zeit wird übertragen
      68. Utc_time = Zeichen 'Stunde
      69. Incr Zz
      70. Case 8 'Zeit wird übertragen
      71. Utc_time = Utc_time + Zeichen 'Stunde
      72. Utc_time = Utc_time + ":" 'Trennzeichen einbauen
      73. Incr Zz
      74. Case 9 'Zeit wird übertragen
      75. Utc_time = Utc_time + Zeichen 'Minute
      76. Incr Zz
      77. Case 10 'Zeit wird übertragen
      78. Utc_time = Utc_time + Zeichen 'Minute
      79. Utc_time = Utc_time + ":" 'Trennzeichen einbauen
      80. Incr Zz
      81. Case 11 'Zeit wird übertragen
      82. Utc_time = Utc_time + Zeichen 'Sekunde
      83. Incr Zz
      84. Case 12 'Zeit wird übertragen
      85. Utc_time = Utc_time + Zeichen 'Sekunde
      86. Incr Zz
      87. Case 13 : If Zeichen = "," Then Incr Zz 'Sekundenbruchteile ignorieren und auf nächstes Datenfeld warten
      88. Case 14 : If Zeichen = "," Then Incr Zz 'auf nächstes Datenfeld warten
      89. Case 15 : If Zeichen = "," Then Incr Zz 'auf nächstes Datenfeld warten
      90. Case 16 : If Zeichen = "," Then Incr Zz 'auf nächstes Datenfeld warten
      91. Case 17 : If Zeichen = "," Then Incr Zz 'auf nächstes Datenfeld warten
      92. Case 18 : If Zeichen = "," Then Incr Zz 'auf nächstes Datenfeld warten
      93. Case 19 : If Zeichen = "," Then Incr Zz 'auf nächstes Datenfeld warten
      94. Case 20 : If Zeichen = "," Then Incr Zz 'auf nächstes Datenfeld warten
      95. Case 21 'Datum wird übertragen
      96. Utc_date = Zeichen 'Tag
      97. Incr Zz
      98. Case 22 'Datum wird übertragen
      99. Utc_date = Utc_date + Zeichen 'Tag
      100. Utc_date = Utc_date + "." 'Trennzeichen einbauen
      101. Incr Zz
      102. Case 23 'Datum wird übertragen
      103. Utc_date = Utc_date + Zeichen 'Monat
      104. Incr Zz
      105. Case 24 'Datum wird übertragen
      106. Utc_date = Utc_date + Zeichen 'Monat
      107. Utc_date = Utc_date + "." 'Trennzeichen einbauen
      108. Incr Zz
      109. Case 25 'Datum wird übertragen
      110. Utc_date = Utc_date + Zeichen 'Jahr
      111. Incr Zz
      112. Case 26 'Datum wird übertragen
      113. Utc_date = Utc_date + Zeichen 'Jahr
      114. Zeit_da = 1 'Einlesen von Zeit und Datum komplett
      115. Einlesen = 0 'weitere Zeichen sind uninteressant
      116. End Select
      117. End If
      118. End If
      119. Return
      Display All
      Raum für Notizen

      -----------------------------------------------------------------------------------------------------

      -----------------------------------------------------------------------------------------------------
    • Naja, ein +2 Stunden und auf Überlauf von 24 Stunden checken ist zu einfach, wenn man eine Uhr haben möchte, die auch automatisch Sommer/Winterzeit anzeigen soll. Aber die dafür nötigen Berechnungen sind ja schon mal entwickelt worden. Aber ohne deine Datenauswertung wäre ich jetzt auch nicht soweit, da habe ich einiges an Anregung heraus gezogen.
      Raum für Notizen

      -----------------------------------------------------------------------------------------------------

      -----------------------------------------------------------------------------------------------------
    • Mit dem GPS-Modul habe ich eigentlich nicht wirklich was am Hut.
      Aber die Auswertung von @tschoeatsch hat mich sehr an eine Statemachine und an Parsen von Strings erinnert.

      Daher habe ich mal erlaubt, die Auswertung mit einer Statemachine umgesetzt, damit mal sieht, wie es mit einer Statemachine gelöst werden kann.
      Der Code ist sehr einfach und nachvollziehbar gehalten. Die Auswerte-Routine wirkt gleich viel überschaubarer.

      Testen konnte ich nicht wegen mangelndem GPS-Modul. Aber simuliert und scheint zu funktionieren.
      Hier wäre also meine Variante mit Statemachine:

      BASCOM Source Code

      1. ' Zeit und Datum auslesen von GPS-Modul
      2. ' Das Auslesen funktioniert via Statemachine in Routine GPS_Auswertung()
      3. $Regfile = "m8def.dat"
      4. $HWStack = 30
      5. $SWStack = 20
      6. $Framesize = 40
      7. $Crystal = 8000000 ' Interner RC-Oszillator
      8. $Baud = 9600
      9. ' Uhrzeit und Datum von GPS-Modul
      10. Dim Stunden as Byte
      11. Dim Minuten as Byte
      12. Dim Sekunden as Byte
      13. Dim Tag as Byte
      14. Dim Monat as Byte
      15. Dim Jahr as Byte
      16. Dim tmpString as String * 4 ' temporärer String (Umwandlung String in Byte)
      17. ' Interne Variablen von GPS_Auswertung() verwendet
      18. Dim GPSZeichen as Byte ' aktuelles Zeichen von GPS
      19. Dim GPSBuffer as String * 20 ' Buffer für GPS-String
      20. Dim GPSCount as Byte ' Zeichen zählen
      21. ' Zustände des GPS-Signals
      22. Const ST_GPS_IDLE = 0 ' Warte-Zustand, bis Startbyte kommt
      23. Const ST_GPS_KENNUNG = 1 ' Kennung einlesen (GNRMC)
      24. Const ST_GPS_UTC = 2 ' UTC-Zeit einlesen
      25. Const ST_GPS_SKIP = 3 ' Überspringen bis Datum kommt
      26. Const ST_GPS_DATE = 4 ' Datum einlesen
      27. Const ST_GPS_COMPLETED = 5 ' Alle Daten angekommen
      28. Dim GPSState as Byte ' Empfangsstatus serielle Daten von GPS-Modul
      29. Declare Sub GPS_Auswertung()
      30. Do
      31. If IsCharWaiting() = 1 then
      32. Call GPS_Auswertung()
      33. End If
      34. If GPSState = ST_GPS_COMPLETED then ' GPS-Empfang ist komplett
      35. ' Hier Daten verarbeiten, anzeigen, Uhr stellen etc.
      36. ' Danach den Empfang wieder scharf machen für nächsten GPS-String
      37. GPSState = ST_GPS_IDLE ' neuer Empfang starten
      38. End If
      39. Loop
      40. ' Wird bei jedem emfangenen Zeichen aufgerufen.
      41. ' Zeichen muss vor Aufruf in Variable GPS_Zeichen vorliegen,
      42. ' oder man liest das Zeichen in der Routine ein (vor Select Case) wie hier gezeigt.
      43. ' Beispiel: $GPRMC,085636.00,A,4934.94722,N,01057.70667,E,0.085,,250719,,,A*78
      44. ' Beispiel: $GPRMC,hhmmss.ss,A,llll.lllll,a,xxxxx.xxxxx,a,x.xxx,,ddmmyy,,,a*hh
      45. Sub GPS_Auswertung()
      46. InputBin GPSZeichen ' Zeichen in der Routine einlesen (bei HW-UART)
      47. Select Case GPSState
      48. ' ------------------------------
      49. Case ST_GPS_IDLE ' Auf Start-Zeichen '$' warten
      50. If GPSZeichen = "$" then ' Startzeichen erkannt
      51. GPSBuffer = "" ' Buffer löschen
      52. GPSState = ST_GPS_KENNUNG ' nächster Zustand
      53. End If
      54. ' ------------------------------
      55. Case ST_GPS_KENNUNG ' Kennung einlesen
      56. If GPSZeichen = "," then
      57. If GPSBuffer = "GPRMC" then ' Kennung ok
      58. GPSBuffer = "" ' Buffer löschen
      59. GPSState = ST_GPS_UTC ' nächster Zustand
      60. Else ' Kennung falsch
      61. GPSState = ST_GPS_IDLE ' Abbruch, auf nächstes Startbyte warten
      62. End If
      63. Else
      64. GPSBuffer = GPSBuffer + Chr(GPSZeichen)
      65. If len(GPSBuffer()) >= 6 then ' Kennung zu lang
      66. GPSState = ST_GPS_IDLE ' Abbruch, auf nächstes Startbyte warten
      67. End If
      68. End If
      69. ' ------------------------------
      70. Case ST_GPS_UTC ' UTC-Zeit einlesen
      71. If GPSZeichen = "," then ' Ende-Kennung der Uhrzeit
      72. tmpString = Mid(GPSBuffer , 1 , 2) ' Stunden
      73. Stunden = val(tmpString)
      74. tmpString = Mid(GPSBuffer , 3 , 2) ' Minuten
      75. Minuten = val(tmpString)
      76. tmpString = Mid(GPSBuffer , 5 , 2) ' Sekunden
      77. Sekunden = val(tmpString)
      78. GPSCount = 0 ' Zeichenzähler löschen
      79. GPSState = ST_GPS_SKIP ' nächster Zustand
      80. Else
      81. GPSBuffer = GPSBuffer + Chr(GPSZeichen)
      82. End If
      83. ' ------------------------------
      84. Case ST_GPS_SKIP ' Überspringen bis Datum
      85. If GPSZeichen = "," then
      86. Incr GPSCount ' Kommas zählen
      87. If GPSCount = 7 then ' letztes Komma vor Datum
      88. GPSBuffer = "" ' Buffer löschen
      89. GPSState = ST_GPS_DATE ' nächster Zustand
      90. End If
      91. End If
      92. ' ------------------------------
      93. Case ST_GPS_DATE ' Datum einlesen
      94. If GPSZeichen = "," then ' Ende-Kennung
      95. tmpString = Mid(GPSBuffer , 1 , 2) ' Tag
      96. Tag = val(tmpString)
      97. tmpString = Mid(GPSBuffer , 3 , 2) ' Monat
      98. Monat = val(tmpString)
      99. tmpString = Mid(GPSBuffer , 5 , 2) ' Jahr
      100. Jahr = val(tmpString)
      101. GPSState = ST_GPS_COMPLETED ' nächster Zustand
      102. Else
      103. GPSBuffer = GPSBuffer + Chr(GPSZeichen)
      104. End If
      105. Case ST_GPS_COMPLETED ' Daten sind komplett
      106. ' Weitere Auswertung wird unterbunden
      107. ' Daten können verarbeitet werden.
      108. ' Um neuen GPS-String zu empfangen, muss nach der Verarbeitung
      109. ' GPSState = ST_GPS_IDLE gesetzt werden.
      110. End Select
      111. End Sub
      Display All
      Der Code ist auch simpel zu erweitern, um auch die anderen Daten zu erhalten.

      The post was edited 1 time, last by Mitch64 ().

    • Ich hab' jetzt bisschen mit diesem u-blox NEO-6M Modul gespielt, mit dem Hintergedanken einen Tacho zu basteln. Wäre ein Geschenk für einen Kapitän.
      Zum Probieren gibt es von u-blox eine software u-blox.com/en/product/u-center, die das Modul ausliest und Klartext darstellt. Da findet man auch den Datensatz, der gleich die Geschwindigkeit ausgibt.
      speed-over-ground.PNG
      Jetzt ist das aber so, dass der Wert doch recht rumzappelt. Gut, die Koordinaten zappeln auch und wenn da der Ort von Sekunde zu Sekunde um 2m springt, hat man 2m/s=7,2km/h. Bei mir springt die Anzeige im Stillstand so zwischen 0,2 und 6km/h, ist dann eigentlich schon eine genaue Ortsbestimmung. Das kann man jetzt mit gleitender Mittelwertbildung glätten, aber bei Stillstand wird nie 0,0km/h angezeigt, ist schon mal ein Schönheitsfehler. Und wie würde man einen Kilometerzähler realisierten? Spontan hätte ich die aktuelle Geschwindigkeit mit dem Sekundentakt verrechnet, aber dann wird der zurückgelegte Wert schon im Stillstand mehr. Wäre es besser, zB. alle 30 Sekunden die Koordinaten zu nehmen und aus denen den in den 30 Sekunden zurückgelegten Weg zu berechnen und aufzusummieren?
      Raum für Notizen

      -----------------------------------------------------------------------------------------------------

      -----------------------------------------------------------------------------------------------------
    • tschoeatsch wrote:

      Jetzt ist das aber so, dass der Wert doch recht rumzappelt.
      Wie genau zappeln die da?
      Gibts da auch mal negative Geschwindigkeiten oder sind alle Werte nur positiv? - Dann ist mit gleitendem Mittelwert natürlich keine Geschwindigkeit mit 0km/h zu erreichen!

      Wenn nicht, müsstest du mal schauen, in welche Richtungen die Geschwindigkeiten gehen. Also +2kmh nach Nord und dann +2kmh nach Süd hebt sich ja auf. Mal so als Beispiel.

      Wenn du für die Kilometer-Zählerei eine aktuelle Position nimmst und dann im Folgenden die Abweichung zu dieser die Strecke ermittelst, dann hast du nur Luftlinie berechnet.
      Ich denke daher musst du eine Position nehmen und dann die Strecke Luftlinie zu einem Folgenden berechnen. Wobei der Letzte Punkt vor einer Richtungsänderung die Distanz bis zu diesem Punkt angibt.
      Und so die Teilstücke, die in eine Richtung gehen, aufaddieren. Nach Richtungsänderung ist dann diese Position für das nächste Teilstück relevant.

      Sonst hätte ich im Moment auch kein Ansatz.