PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : NMEA von GPS-Modul auswerten



JeyBee
03.02.2010, 10:19
Nabend,

Ich habe ein GPS Modul an einem AVR, welchen ich mit C programmiere. Desweiteren befinden sich am ATmega16 ein 16*2 LCD, womit ich mal die Längen und Breitengrade angeben möchte.
Wie man die Daten ausliest, ist mir klar.
Für Längen und Breitengrade kann ihc ja z.B. die Zeile "$GPGGA" verwenden. Nun muss ich ja theoretisch nur noch die Komata zählen, bis zu der Zahl, die ich gerne hätte.
Jedoch weiss ich nicht, wie ich genau die Zahl nach dem Komma (bzw. zwischen zwei Komata) in eine Variable einlesen kann.

Kann mir jemand weiterhelfen?


Mfg JeyBee

wkrug
03.02.2010, 12:33
Jedoch weiss ich nicht, wie ich genau die Zahl nach dem Komma (bzw. zwischen zwei Komata) in eine Variable einlesen kann.
Du nimmst die einzelnen ASCII Zeichen zwischen den gewünschten kommas und kopierst die in eine String Variable.

Nun benutzt Du das Kommando atoi das Dir dann diesen String in eine Variable umwandelt.
Du müsstest nur darauf achten, das die Variable auch einen genügend großen Umfang hat ( Anzahl der BITS )

maw_hn
03.02.2010, 12:40
Hallo JeyBee,

ich gehe mal davon aus, dass der GPS via RS232 mit deinem AVR verbunden ist.
Wenn ich mich richtig entsinne, kommen die Daten ja als ASCII-Zeichen rüber.

Ich würde das Ganze so angehen:
1. Die ASCII-Zeichen (sind ja nix weiter als einzelne Bytes) nacheinander in ein char-Array ablegen.

2. Das char-Array durchgehen und überall die 48 abziehen (Umwandlung ASCII->Zahl)

3. Dann das Array nochmals durchlaufen und die einzelnen Ziffern aufsummieren (1. Stelle * 1000 + 2. Stelle * 100 ... 1. Nachkommastelle * 0,1 ...) und das Ergebnis in eine float schreiben

Natürlich kannst du die einzelnen Schritte auch in einem Durchlauf machen.

Grüße,
Marco

maw_hn
03.02.2010, 12:44
@wkrug:

atoi eignet sich nur für Integer. Wenn dann müsste er atof nutzen.
Allerdings würde ich in diesem Fall davon abraten, da die Funktion nicht sonderlich effizient ist.

Mal davon abgesehen ist der Lerneffekt natürlich größer, wenn man es mal selber implementiert hat ;-)

Grüße,
Marco

JeyBee
03.02.2010, 12:46
Nabend

Das mit dem Char array, war auch meine Überlegung. Da ich jedoch auf dem Gebiet Funktionen, Arrays, Buffer etc. noch nicht viel Ahnung habe, wolle ich nur mal jeweils den Zeilenanfang "$GPGGA" auf mein LCD Display zaubern. Jedcoh geht auch das schon nicht ganz:

Nach dem Reset des Controllern, funktionert alles einmalig perfekt. "$GPGGA" wird korrekt in das Char-Array eingelesen, über ein paar if-schleifen und die strcmp(); funktion wird überprüft, ob in dem char array auch "$GPGGA" steht. Nun mien Problem:
Nachdem das alles einmalig gut funktionierte, wird zwar wieder "$GPGGA" in ein Char-Array eingelesen, jedoch ist alles auf zwei Arrays aufgeteilt, wodurch ich nichts mehr auf dem Display erhalte.
Wie kann ich das Problem lösen?

Hier mein Code:
http://pastebin.com/m2d23eac2


Mfg JeyBee

wkrug
03.02.2010, 13:06
@maw_hn
Es kommt eben auf den Wertbereich an, der in die Variable rein soll.
bei Integer sind es 65536.
Bei Float hat man halt das Problem mit den Rundungsfehlern.

Eventuell würde ja auch eine Long Variable reichen, dann müsste das Kommando atol benutzt werden.

Zum Problem mit dem String.
Am Ende des Strings wird doch immer ein <CR> bzw. <CR>,<LF> ausgegeben.
Du startest die Aufzeichnung des Strings mit dem $ und zeichnest alles auf, bis ein <LF> kommt.
Ist dieses Da wird der komplette String ausgewertet.
CRC usw.
Ein $ veranlasst den Stringzähler dazu imme auf Position 0 zu springen.
Somit werden nur gültige Strings ausgewertet und es ist immer nur einer im Buffer.
Ist es dein gewünschtes Positionskommando angekommen, werden die Daten aus dem String geholt und für die weitere Verarbeitung abgespeichert.

JeyBee
03.02.2010, 13:24
Hat mir villeicht mal jemand eine Source oder so?

Ceos
03.02.2010, 13:51
folgende funktionen solltest du dir eventuell mal ansehen


size_t strcspn ( const char * str1, const char * str2 );
const char * strrchr ( const char * str, int character );
const char * strstr ( const char * str1, const char * str2 );
char * strtok ( char * str, const char * delimiters );


vor allem die letzte methode sollte für dich überaus hilfreich sein!!!
http://www.cplusplus.com/reference/clibrary/cstring/
zum nachlesen

JeyBee
03.02.2010, 14:02
Okay, das scheint hilfreich zu sein.

Aber what the hell ist char* xxx. *x ist ja ein pointer.
Ist char *string z.B. ein pointer im char format, mit dem Namen string?

Ceos
03.02.2010, 16:36
wo der punkt steht ist von mäßige bedeutung, nach konvention schreibt man beim DEKLARIEREN eines pointer

type* name;

wenn man dann

*name

schreibt, dereferenziert man den pointer und greift auf den inhalt zu!

das const kann man bei diese methoden zumindest ignorieren

deine aussage

"Aber what the hell ist char* xxx. *x ist ja ein pointer. " ist also nicht ganz richtig, dein xxx ist der name des pointer *x ist der dereferenzierte pointer

MfG

sternst
04.02.2010, 09:46
wo der punkt steht ist von mäßige bedeutung, nach konvention schreibt man beim DEKLARIEREN eines pointer

type* name;
Das würde ich bestreiten. Wenn es diesbezüglich überhaupt eine Konvention gibt, dann "type *name;".
Und das hat auch einen guten Grund:

type* name1, name2;

Man könnte denken, dass hier zwei Pointer deklariert würden,
aber in Wirklichkeit ist nur name1 ein Pointer. Daher sinnvoller:

type *name1, name2;

Oder wenn halt tatsächlich beides Pointer sein sollen:

type *name1, *name2;

Ceos
04.02.2010, 10:04
arrgh ja sorry da hat sich wieder mein daumen geirrt ... ich plautz das leerzeichen fast immer so hin, ist ne schlechte angewohnheit mein fehler ... aber ich wollte klar stellen, dass der stern zwischen typ und name ein pointer ist und stern mit name alleine eine dereferenzierung ist!

EDIT: in größeren projekten ist die position des sterns eher zweitrangig, da man dort eh alle variablen einzeln deklarieren muss, wenn man vernünftig mit doxygen dokumentieren will

Richard
04.02.2010, 10:15
Leider kann ich kein C, aber auch dort sollte es String Befele
ähnlich Wert =mit (string, x,y) Wobei dann String eine komplette
Zeile der GPS Daten darstellt, x den Anfang vom gewünschten
abschnitt und y das Ende. In Wert steht dann der gewünschte String
und muß in einen Numerischen Wert gewandelt werden.

Da braucht man dann überhaupt nicht nach Kommas oder ähnlich
suchen, die gewünschten Daten stehen ja immer an der gleichen
Stelle im Datenstring.

Gruß Richard

Ceos
04.02.2010, 10:43
jain richard ^^ es kommt auch vor, dass die daten mit 0.0 angegeben werden, statt 0.00000xxx (edit: ich meine damit dass auf 10 stellig auch mal 3 stellig wird)

z.B. wenn kein sattelit verfügbar ist ... die methode mit strtok ist ideal, man gibt die trenner ein (in dem falle wohl das komma) und mit der angegebenen beispielfunktion bekommt man dann alle werte nacheinander aufgelistet und kann sie z.B. mit sscanf auswerten ... obwohl man im falle eines konstanten strings auch gleich komplett die zeile mit sscanf verarbeiten könnte!

theborg
06.02.2010, 08:40
Nabend,
Für Längen und Breitengrade kann ihc ja z.B. die Zeile "$GPGGA" verwenden. Nun muss ich ja theoretisch nur noch die Komata zählen, bis zu der Zahl, die ich gerne hätte.
Mfg JeyBee

hi das geht nur bedingt da du ja noch andere Feinheiten und variablen drinne hast, hatte des grade in ASM gemacht deswegen :P hier haste mal nen pahr sampels mit und ohne b.z.w. schlechten entfang.
und den haste ja noch manchmal zwischen den werten mehrere Vars.

Und dann gibt es noch Protokollunterschide (letztenbeiden zeilen) des erste ist NEMA 1.0 und des andere 2.2 (hinten die Kennung)



; $GPRMC,001915.928,V,0000.0000,N,00000.0000,E, , ,270102, ,*1D
; $GPRMC,191410 ,A,4735.5634,N,00739.3538,E,0.0 ,0.0 ,181102,0.4,E,A*19
; $GPRMC,140815.000,A,5339.2125,N,01000.8120,E,0.18, 59.16,301209,0 , ,A*6E
; k 0 1 2 3 4 5 6 7 8 9 0 1
; ^ ^ ^ ^ ^ ^ ^ ^ ^
; | | | | | | | | Neu in NMEA 2.3:
; | | | | | | | | Art der Bestimmung
; | | | | | | | | A=autonomous (selbst)
; | | | | | | | | D=differential
; | | | | | | | | E=estimated (geschätzt)
; | | | | | | | | N=not valid (ungültig)
; | | | | | | | | S=simulator
; | | | | | | | Missweisung (mit Richtung)
; | | | | | | Datum: 18.11.2002
; | | | | | Bewegungsrichtung in Grad (wahr)
; | | | | Geschwindigkeit über Grund (Knoten)
; | | | Längengrad mit (Vorzeichen)-Richtung (E=Ost, W=West)
; | | | 007° 39.3538' Ost
; | | Breitengrad mit (Vorzeichen)-Richtung (N=Nord, S=Süd)
; | | 46° 35.5634' Nord
; | Status der Bestimmung: A=Active (gültig); V=void (ungültig)
; Uhrzeit der Bestimmung: 19:14:10 (UTC-Zeit)