Hallo
Ich habe einen RGM-2000 GPS Empfänger...
Dieser arbeitet einwandfrei und liefert auch brav seinen NMEA
Datenstrom...
Diesen habe ich in Arrays abgepackt und möchte diese nun weiter
verarbeiten.
Mein NMEA Datensatz:
$GPGGA,110447.099,4729.7067,N,00844.1100,E,1,04,20.6,526.2,M,48.0,M,0.0,
0000*4C<\r><\n>$GPVTG,,T,,M,0.00,N,0.0,K*7E<\r><\n>
Zur umrechnung verwende ich folgende formel
http://notinthemanual.blogspot.com/2008/07/convert-nmea-latitude-longitude-to.html
Das problem war erstmal die Zeichen im ASCII code aus dem Array in eine
Variable zum rechnen zu bekommen habe dies dann so gelöst
ufLatitude ist eine Float... gibt es eine möglichkeit dies ohne Float zu
lösen?
in ucN stehen die ASCII Zeichen von links nach rechts (links
höchstwertige zahl etc..)
Bisher konnte ich nicht überprüfen ob es richtig gerechnet wurde
Nun möchte ich die Float wieder per RS232 zum PC Senden die habe ich so
versucht:
1
string[0]=(ufLatitude/100);
2
string[1]=(ufLatitude/10);
3
string[2]=(ufLatitude/1);
4
string[3]='.';
5
string[4]=(ufLatitude/0.1);
6
string[5]=(ufLatitude/0.01);
7
string[6]=(ufLatitude/0.001);
8
string[7]=(ufLatitude/0.0001);
9
string[8]=(ufLatitude/0.00001);
10
11
12
ucCount=0;
13
while(ucCount!=9)
14
{
15
while(!(USR&(1<<UDRE)));
16
UDR=string[ucCount]+0x30;
17
ucCount++;
18
}
es kommt jedoch leider nur "müll" raus
^<15>?S?0009^????<23>04_^
Hoffe ihr könnt mir helfen...
Danke schonmal
- string[position] = 0 ist nicht das gleiche wie string[position] = '0'
letzteres ist aber eher, dass was du vermutlich willst (ASCII Code) Das
macht dir bereits Probleme beim einlesen. '0' = (char)48.
- du kannst nicht einfach eine Zahl durch die Wertigkeit einer Ziffer
teilen um die Ziffer zu ermitteln. Beispiel: 1.23: 1.23 / 0.01 = 123,
du willst aber vermutlich nur die 3 haben. (Division und Modulo, bzw
ftoa)
Überleg dir nochmal ganz genau, was du machen möchtest, wie du es von
Hand lösen würdest.
Hätte ich fast vergessen;)
string[0] = (ufLatitude / 100)+'0';
string[1] = (ufLatitude / 10)+'0';
string[2] = (ufLatitude / 1)+'0';
Aber wozu das ganze hin und hergerechne?
Sende dem PC doch einfach deine GPS-Strings
und popel dort dann die entsprechenden Daten raus.
Hallo
Vielen Dank für eure antworten...
Also weshalb ich es wieder zurück konvertiere liegt daran, das ich
ansonsten keine möglichkeit habe zu überprüfen ob er es intern korrekt
von String zu double konvertiert...
Ich habe meinen code nun so angepasst
ucNx und ucEx sind die vorderen stellen der längen und breitengrad
angaben welche danach addiert werden müssen (siehe link im ersten post)
ufLatitude und longtitude sind nun double variablen
wenn ich %d durch %s ersetze kommt er nie mehr von dieser stelle los
Wenn ich es so mache wie hier, kommt wieder mal müll zurück
19518<\0><\0><\0>4
Ich hoffe ihr seht meinen Fehler
Für optimierungen bin ich immer offen derzeit benötigt mein code wegen
Sprintf und double 5000bytes
Claudio H. schrieb:
> Ich hoffe ihr seht meinen Fehler
Bring mal etwas mehr.
Aber diesmal bitte mit Datentypen
> ufLatitude und longtitude sind nun double variablen> ucTemp = sprintf(buffer, "%d", ufLatitude);
Das kann dann aber nicht stimmen. %d bezeichnet einen int.
> Für optimierungen bin ich immer offen derzeit benötigt mein code wegen> Sprintf und double 5000bytes
Der Löwenanteil wird wohl für sprintf draufgehen.
> ufLatitude = ((ufLatitude / 60) ...
Das kann auch nicht stimmen.
0348
sind 3 Grad und 48 Minuten und nicht 348/60 ( = 5.8) Grad
0348 / 100 -> 3 3 ganze Grad ...
0348 % 100 -> 48 ... und 48 Minuten
48 Minuten sind 48 / 60 = 0.8 Grad
0348 sind daher 3 Grad 48 Minuten oder 3.8 Grad
Ich wollte beim teil der Längengrade (4729.7067) die ersten 2 zeichen
abschneden da ich diese am schluss addieren muss laut link (hab es
manuell gerechnet was im link steht klappt problemlos)
Diese ersten 2 zeichen beim Längen grad und 3 beim breitengrad stehen in
ucNx und uxEx
danach werden die restlichen zeichen in die variablen ucN und ucE
geschrieben
Mein Rat:
Trenne die Funktionalitäten voneinander.
Da gibt es zuallererst eine Funktion die eine komplette Zeile in einen
String einliest. Vom ersten $ bis zum abschliessenden \n.
Das kannst du leicht testen. String ausgeben lassen.
Dann brauchst du eine Funktion, die dir aus diesem kompletten String die
für dich interessanten Teile (Länge und Breite) herausholt. Die ','
führen dich durch den String und zeigen dir wo diese Teile im String
liegen. Genau dazu haben sie die Macher des NMEA Protokolls eingeführt,
damit man eben nicht Zeichen zählen muss. Wenn ich mir ansehe, was du im
Code alles an Annahmen über Zeichenlängen triffst, dann läuft es mir
kalt den Buckel runter.
Auch das kannst du leicht testen.
Du brauchst dir ja nur die beiden so erhaltenen Teil-Strings ausgeben
lassen
Und erst dann gehst du her und veranstaltest deinen arithmetischen
Klimbim.
(Aber vorher schnappst du dir noch einen Taschenrechner und probierst
noch ein wenig. Die Umrechnung hast du noch nicht wirklich verstanden)
Fazit: Altes Prinzip in der Programmierung. Nicht alles auf einmal
machen, sondern die Aufgabe in Teilaufgaben zerlegen, die jede für sich
einzeln testbar ist.
Und achte auch darauf, dass Strings in C immer mit einem '\0' Zeichen
abgeschlossen sind. Ansonsten wird dir nämlich strtod etwas husten.
Vielen Dank für die antwort...
Also das mit den einzelnen funktionalitäten habe ich ereits gemacht...
habe alles nach einander überprüft und getestet....
Bis hier hin hat alles funktioniert in den arrays stehen die richtigen
korrekten zeichen....
Auch wenn ich es nun mit komma suchen löse, weiss ich trozdem noch nicht
wie ich den nun die umrechnung anstellen kann...
Ich habe ja zb 02.7846 als ASCII zeichen im Array... diese zeichen muss
ich ja nun in eine Float oder double variabel schieben damit ich
02.7846 / 60 rechnen kann und die ersten beider oder ersten 3 zeichen
dazu addieren kann.
mein problem ist ja nun das ich nicht weiss ob er es richtig
konvertiert....
Was die konvertierung angeht bin ich noch anfänger deshalb noch die
frage wegen '\0' also jedes zeichen einzeln ans ende des arrays?
was meinst du mit husten? falsches resultat?
Wooow vielen dank für dein Code...
Habe ihn sogleich getestet.... aber leider kommt wie bei mir nichts
sinnvolles raus...
Hier das was ausgegebn wird...
Laenge = ?
<\0>67<\0>N<\0>00844.1100<\0>E<\0>1,04,20.6,526.2...<\0><\0><\0><\0><\0>
<\0><\0><\0><\0><\0><\0><\0><\0><\0><\0><\0><\0><\0><\0>_Breite = ? #
Senden tu ich nmea so:
1
ucCount=0;
2
while(ucCount!=81)
3
{
4
while(!(USR&(1<<UDRE)));
5
UDR=nmea[ucCount];
6
ucCount++;
7
}
kann es sein das hier die Optimierungen von GCC eine rolle spielen?
Claudio H. schrieb:
> kann es sein das hier die Optimierungen von GCC eine rolle spielen?
Nein.
Aber es kann sein, dass du C lernen solltest.
Mach dir eine Funktion
1
voiduart_putc(charc)
2
{
3
while(!(USR&(1<<UDRE)))
4
;
5
UDR=c;
6
}
und dann noch eine
1
voiduart_puts(constchar*string)
2
{
3
while(*string)
4
uart_putc(*string++);
5
}
(Ich kanns einfach nicht mehr sehen, wenn da die banalsten
Funktionalitäten immer wieder in die Funktionen hineingequetscht werden,
nur weil man zu faul ist, sich einmalig einen Grundstock an
Basisfunktionen zu schreiben. Wenn man mit der UART arbeitet braucht man
eine Basisfunktion um ein einzelnes Zeichen auszugeben und man braucht
praktisch immer eine Funktion um einen String auszugeben. uart_putc ...
c wie Character / uart_puts ... s wie String)
Aufgerufen wird das dann
Claudio H. schrieb:
> Laenge = ?> <\0>67<\0>N<\0>00844.1100<\0>E<\0>1,04,20.6,526.2...<\0><\0><\0><\0><\0>
<\0><\0><\0><\0><\0><\0><\0><\0><\0><\0><\0><\0><\0><\0>_Breite
> = ? #
Damit sind zwei Fehler im Programm.
1) Laenge = ?
Die Mathebibliothek ist nicht mit den übrigen Objektdateien zusammen zum
Programm gelinkt worden. Das ist ein Problem in deinem Projekt.
http://www.mikrocontroller.net/articles/FAQ#Aktivieren_der_Floating_Point_Version_von_sprintf_beim_WinAVR_mit_AVR-Studio
2) Ein Bufferoverflow ist aufgetreten
Das ist kann ein Fehler in meinem Code sein. Das kann ich erst heute
abend kontrollieren.
Oder du benutzt den Code falsch.
Stelle sicher, dass die Ausgabe von nmea beim ersten auftretenden '\0'
beendet wird.
Stefan B. schrieb:
> 2) Ein Bufferoverflow ist aufgetreten>> Das ist kann ein Fehler in meinem Code sein. Das kann ich erst heute> abend kontrollieren.>> Oder du benutzt den Code falsch.
Ich denke mal, da hat sich die Ausgabe eines empfangenen NMEA Strings
mitten in die Ausgabe der Ergebnisse eingemischt. Könnte vorkommen, wenn
der Empfang über Interrupt passiert und die ISR nach dem Empfang einer
Zeile die Zeile zu Kontrollzwecken ausgibt.
Der Ergebnisstring ist ja grundsätzlich vorhanden (wenn auch mit den ?),
nur mitten drinn taucht plötzlich ein NMEA String auf.
Edit: Ach, jetzt seh ichs erst.
Laenge = ?
<\0>67<\0>N<\0>00844.1100<\0>E<\0>1,04,20.6,526.2...<\0><\0><\0><\0><\0>
<\0><\0><\0><\0><\0><\0><\0><\0><\0><\0><\0><\0><\0><\0>_Breite
= ? #
Da ist einfach nur die Zuordnung zu den Zeilen falsch. Der Code, der den
NMEA String zu Kontrollzwecken ausgibt, gibt als erstes einen \n aus
(zumindest sieht es so aus). Könnte auch sein, dass das Terminal von
sich aus einen Zeilenumbruch macht, und den nach dem ? für Länge macht,
weil dort ein Leerzeichen ist.
sprintf(nmea, "\nBreite = %g # Laenge = %g\n", breite, laenge);
Ein \n nach den Ergebnissen schafft hier Klarheit und stellt die
Zeilenumbrüche richtig.
Vielen Dank an alle die mir hier so tatkräftig geholfen habe...
Es hat alles bestens geklappt... es war das problem mit der Floating
Point variable...
Danke :)