Forum: Compiler & IDEs Variables Feld für NMEA Protokoll


von Kleiner Uni Student (Gast)


Lesenswert?

Hallo Leute,

ich soll für meine Uni ein kleines Projekt realisieren das über einen 
Altera FPGA Daten von einem ublox 5 GPS Modul filtert und umwandelt.
Das mit dem FPGA ist jetzt soweit realisiert. Bloß ich hab da ein 
Problem das GPS Modul sendet mir daten im NMEA Protokoll Format, das 
packet $GPRMC will ich filtern welches ich auch mit „strstr“ geschafft 
habe und auslesen in ein Feld mache ich auch schon über eine einfach for 
schleife, da liegt schon mein Problem denn wenn ich die Antenne abklemme 
wird der gesendete string viel kleiner und des halb bräuchte ich eine 
Variable Feld, bloß leider weiß ich nicht wie ich das machen kann ? hab 
versucht über eine while schleife das Endzeichen welches mit gesendet 
wird zu erkennen, laut NMEA Protokollangabe ist es ein „ENTER“ also „\n“ 
bloß da klappt dann gar nichts mehr.
Und da der string Beispielsweiße so aussieht:
$GPRMC,191410,A,4735.5634,N,00739.3538,E,0.0,0.0,181102,0.4,E,A*19

Will ich gerne die Daten zwischen denn Kommas auslesen? aber mir ist 
leider noch nichts eingefallen wie dieses gehen könnte, vielleicht auch 
mit einer while schleife, aber vielleicht geht dieses dann auch 
irgendwie eleganter.

Über Tipps, Anregungen und Code beispiele / Schnippsel würde ich mich 
freuen.

Mit Freundlichem Gruß
Kleiner Uni Student

von Stefan B. (stefan) Benutzerseite


Lesenswert?

Ich würde die Bibliotheksfunktion strtok in einer Schleife z.B. while 
verwenden. Auf eine veränderliche Feldlänge (dynamischer Puffer statt 
statischer Puffer) würde ich mich nur unter Zwang einlassen.

Bsp: http://www.imb-jena.de/~gmueller/kurse/c_c++/c_strtok.html

von Kleiner Uni Student (Gast)


Lesenswert?

Hi,

ja da hast du auch irgend wie recht wollte das Feld auf 82 zeichen 
beschränken, laut NMEA Protokoll können nicht mehr zeichen auftreten, 
doch wie mache ich das, das es der einlesen in das Feld stoppt wenn ein 
fehler eintritt ? z.b. antenne unterbrochen ? denn dann kommt von diesem 
Stringpaar
$GPRMC,191410,A,4735.5634,N,00739.3538,E,0.0,0.0,181102,0.4,E,A*19
nur das an
$GPRMC,,V,,,,,,,,,,N*19 (ist nur als beispiel)
das V steht für Void und das N für not Valid .
Vielleicht ja wenn ich die beiden sachen überprüfe ob die auf V und N 
stehen wenn ja soll er nichts mehr machen ? aber wie mache ich das mit 
den kommas ? hab das mit dem strtok noch nicht ganz so verstanden.

vielen dank schon mal für die hilfe.

von Karl H. (kbuchegg)


Lesenswert?

Kleiner Uni Student schrieb:
> Hi,
>
> ja da hast du auch irgend wie recht wollte das Feld auf 82 zeichen
> beschränken, laut NMEA Protokoll können nicht mehr zeichen auftreten,

Nimm das Doppelte.
Solche Felder sollte man nie zu klein dimensionieren.
Du brauchst nur einen Übertragungsfehler haben und einen \n nicht 
richtig erkennen und schon läuft dir der String davon.

Bei solchen Sachen heißt die Devise: nicht kleckern sondern klotzen!

> fehler eintritt ? z.b. antenne unterbrochen ? denn dann kommt von diesem
> Stringpaar
> $GPRMC,191410,A,4735.5634,N,00739.3538,E,0.0,0.0,181102,0.4,E,A*19
> nur das an
> $GPRMC,,V,,,,,,,,,,N*19 (ist nur als beispiel)
> das V steht für Void und das N für not Valid .

du zerlegst dir den String anhand der ',' und siehst nach, ob im 
bewussten Feld ein N oder ein V steht?

> den kommas ? hab das mit dem strtok noch nicht ganz so verstanden.

Dann such dir im Web die Hilfe für strtok. Praktisch bei jeder 
Beschreibung der strtok Funktion ist immer ein Beispiel angegeben.

Google:   strtok C

und schon werden sie geholfen

von Kleiner Uni Student (Gast)


Lesenswert?

Hi,
ich werde es mal berücksichtigen das ich das feld jetzt größer machen 
werde, danke für den tipp.

Also hab mir das grade mal mit strtok() angeguckt
ich würde dann denn strink so als beispiel zerlegen:
1
char nmea_packet[]="$GPRMC,191410,A,4735.5634,N,00739.3538,E,0.0,0.0,181102,0.4,E,A*19";
2
char delimiter[] = ",*";
3
char *ptr;
4
5
// initialisieren und ersten Abschnitt erstellen
6
ptr = strtok(string, delimiter);
7
8
while(ptr != NULL) 
9
{
10
  printf("Abschnitt gefunden: %s\n", ptr);
11
  // naechsten Abschnitt erstellen
12
   ptr = strtok(NULL, delimiter);
13
}

kann das jetzt leider nicht am "Lebendem" Modell Testen denn bin grade 
nicht vorort aber das müsste doch so funktionieren oder ?
Ah ja wie sag ich ihm denn das er es mir in verschiedene felder 
schreiben soll ? und dann müsste ich ja noch die funktion atoi() 
einbinden um die zahlenwerte als integer zu haben. Köntet ihr mir da 
tipps geben wie man das so machen könnte ?

Jetzt habe ich noch eine frage wie sieht das jetzt aus wenn ich nur denn 
einen strin absuchen will ?
denn er fängt mit $.... an und endet mit <CR><LF> ? wie kann ich das 
suchen das er dort aufhört denn string zu "token" ?

Ah ja dann wollte ich noch die checksume bestimmen mit XOR und so dafür 
muss ich von diesem string
$GPRMC,191410,A,4735.5634,N,00739.3538,E,0.0,0.0,181102,0.4,E,A*19
nur das haben umes zu berechen
GPRMC,191410,A,4735.5634,N,00739.3538,E,0.0,0.0,181102,0.4,E,A
wie übergebe ich nur einen teilstring ? der bei $ anfängt und bei * 
aufhört ?

Vielen danke schon mal an euch und schon an die Hilfe die ihr mir 
gegeben habt.

von Stefan B. (stefan) Benutzerseite


Lesenswert?

Deine Einlesefunktion sollte eine Maximalzahl von Zeichen einlesen 
können, die von der Größe des Puffers abhängt und sie sollte einen 
Rückgabewert haben - korrekt eingelesen, d.h. Zeilenende erkannt bzw. 
nicht korrekt eingelesen d.h. Maximalzahl überschritten und kein 
Zeilenende erkannt. Das Zeilenende muss die Funktion nicht unbedingt 
speichern.

Die Weiterverarbeitung sollte nur korrekt eingelesene Zeilen bearbeiten.

strtok verändert den String. An die Stelle eines delimiters wird 
ein '\0' geschrieben. Wenn die zu berechnende Prüfsumme also die ',' 
einschliesst (NMEA Standard nachsehen), solltest du die Prüfsumme vor 
dem Zerlegen berechnen. Das '$' für den Stringanfang kannst du mit 
strchr suchen und das '*' für das Stringende mit strrchr.

Tipp: Schau dir die Funktionsgruppe str... in string.h an und stöbere 
etwas im Netz oder im Manual. Da sind nützliche Funktionen dabei.

von Lowtzow .. (lowtzow)


Lesenswert?

Kleiner Uni Student schrieb:

ich habe es mal so ähnlich gelöst, habe es schnell mal versucht es für 
dein bsp anzupassen. hoffe es gelingt ;-)
1
  char nmea_packet[]="$GPRMC,191410,A,4735.5634,N,00739.3538,E,0.0,0.0,181102,0.4,E,A*19";
2
 char delimiter[] = ",*";
3
 char *ptr;
4
 
5
 // initialisieren und ersten Abschnitt erstellen
6
  strtok( nmea_packet, "," ); // $GPRMC
7
 
8
  //und dann weiter zb. wobei mit jedem strtok der string weiter zerlegt wird und daher nur noch NULL geschrieben werden muss
9
10
  xy = strtok( NULL, "," ); // 191410
11
  xyz = strtok( NULL, "," ); // A
12
  xyzq  = strtok( NULL, "," ); // 4735.5634

von Karl H. (kbuchegg)


Lesenswert?

Kleiner Uni Student schrieb:

> kann das jetzt leider nicht am "Lebendem" Modell Testen denn bin grade
> nicht vorort aber das müsste doch so funktionieren oder ?

Ja. Die grundsätzliche Funktion von strtok ist erkennbar.

> Ah ja wie sag ich ihm denn das er es mir in verschiedene felder
> schreiben soll ?
1
char nmea_packet[]="$GPRMC,191410,A,4735.5634,N,00739.3538,E,0.0,0.0,181102,0.4,E,A*19";
2
3
  char * Kennung;
4
  char * Time;
5
  char * Latitude;
6
  char * NorthSouth;
7
  char * Longitude;
8
9
  Kennung    = strtok( nmea_packet, "," ); // $GPRMC
10
  Time       = strtok( NULL, "," );
11
  KeinAhnung = strtok( NULL, "," );
12
  Latitude   = strtok( NULL, "," );
13
  NorthSouth = strtok( NULL, "," );
14
  Longitute  = strtok( NULL, "," );
15
16
  ...
17
18
  // Dies Strings weiter behandeln, zb aus den 'Zahlenwerten' echte
19
  // Zahlen machen, sofern(!) in den jeweilgen Variablen keine NULL
20
  // Pointer sind.
21
  ...

> und dann müsste ich ja noch die funktion atoi()
> einbinden um die zahlenwerte als integer zu haben. Köntet ihr mir da
> tipps geben wie man das so machen könnte ?

Ja,
Mach ein paar C Vorübungen auf dem PC. Ein wenig C Grundkentnisse 
solltest du schon haben, ehe du dich in die µC Hölle mit ihren 
beschränkten Debug-Möglichkeiten wagst.

von Kleiner Uni Student (Gast)


Lesenswert?

Stefan B. schrieb:
> Deine Einlesefunktion sollte eine Maximalzahl von Zeichen einlesen
> können, die von der Größe des Puffers abhängt und sie sollte einen
> Rückgabewert haben - korrekt eingelesen, d.h. Zeilenende erkannt bzw.
> nicht korrekt eingelesen d.h. Maximalzahl überschritten und kein
> Zeilenende erkannt. Das Zeilenende muss die Funktion nicht unbedingt
> speichern.

Danke für den guten ansatz bloß bei mir harperts irgend wie an der 
realisierung, dieses punktes ich weiß nicht wie ich das machen soll ?
Also ich habe mir überlegt ich frage denn daten string die byte für byte 
ab und sage wenn der anfang also '$' kommt soll er die ersten 5 zeichen 
einlesen in das daten feld und sie nach den buchstageb "RMC" überprüfen, 
also um zu prüfen ob das Richtige packet kommt in etwa so:
1
char nmea_data[164];
2
3
int main()
4
{
5
.
6
.
7
.
8
if(send_data = '$')
9
{
10
 if(strstr(nmea_data,"RMC")==&nmea_data[3])
11
{
12
.
13
.
14
.
15
// Hier dann die for schleife
16
.
17
.
18
.

wie mache ich das denn jetzt mit der abfrage

Lowtzow .... schrieb:
> ich habe es mal so ähnlich gelöst, habe es schnell mal versucht es für
> dein bsp anzupassen. hoffe es gelingt ;-)
>   char nmea_packet[]="$GPRMC,191410,A,4735.5634,N,00739.3538,E,0.0,0.0,181102,0 
.4,E,A*19";
>  char delimiter[] = ",*";
>  char *ptr;
>
>  // initialisieren und ersten Abschnitt erstellen
>   strtok( nmea_packet, "," ); // $GPRMC
>
>   //und dann weiter zb. wobei mit jedem strtok der string weiter zerlegt wird 
und daher nur noch NULL geschrieben werden muss
>
>   xy = strtok( NULL, "," ); // 191410
>   xyz = strtok( NULL, "," ); // A
>   xyzq  = strtok( NULL, "," ); // 4735.5634

Vielen danke werde es gleich morgen ausprobieren und, dann hier mal mein 
ergebniss preis geben.

Karl heinz Buchegger schrieb:
> Mach ein paar C Vorübungen auf dem PC. Ein wenig C Grundkentnisse
> solltest du schon haben, ehe du dich in die µC Hölle mit ihren
> beschränkten Debug-Möglichkeiten wagst.

Vielen dank für das Code beispiel werde es mal auch so ausprobieren, 
grundkenntnisse in c habe ich ja schon, nur mir fällt es schwer diese 
praktisch auf mein problem anzuwenden, denn habe das ja schon 2 semester 
Studiert. Aber Deine und Eure Hilfe hier ist super so gehen mir überall 
kleine lichter auf :) .

von Karl H. (kbuchegg)


Lesenswert?

Kleiner Uni Student schrieb:

> Danke für den guten ansatz bloß bei mir harperts irgend wie an der
> realisierung, dieses punktes ich weiß nicht wie ich das machen soll ?
> Also ich habe mir überlegt ich frage denn daten string die byte für byte
> ab und sage wenn der anfang also '$' kommt soll er die ersten 5 zeichen
> einlesen in das daten feld und sie nach den buchstageb "RMC" überprüfen,
> also um zu prüfen ob das Richtige packet kommt in etwa so:

Das ist imho schon der falsche Ansatz.
Deine Empfangsroutine soll sich mit Ausnahme des \n und  \r nicht um den 
Inhalt kümmern. \n und \r auch nur deswegen, weil sie das Ende einer 
Zeile kennzeichnen.

Solange das empfangene Zeichen nicht \n ist (\r wird einfach ignoriert) 
wird das Zeichen ohne Ansehen des Zeichens im Buffer hinten angehängt 
(solange noch Platz ist). Ist das Zeichen ein \n, so wird in den Buffer 
noch ein \0 hinten drann gehängt um das Ganze zu einem gültigen C-String 
zu machen und ein globales Flag gesetzt, welches anzeigt, dass eine 
fertige Zeile Text zur Weiterverarbeitung ansteht. Und erst dort geht es 
dann an die Feinarbeit.


Der entscheidende Punkt ist:
Trennen von
  * Empfang einer Textzeile
  * Auswertung der Textzeile

Das sind 2 Dinge die direkt nichts miteinander zu tun haben (ausser das 
das Ergebnis des ersten die Basis für das zweite bildet)

von Karl H. (kbuchegg)


Lesenswert?

Kleiner Uni Student schrieb:

>> Mach ein paar C Vorübungen auf dem PC. Ein wenig C Grundkentnisse
>> solltest du schon haben, ehe du dich in die µC Hölle mit ihren
>> beschränkten Debug-Möglichkeiten wagst.
>
> Vielen dank für das Code beispiel werde es mal auch so ausprobieren,
> grundkenntnisse in c habe ich ja schon,


Mit Verlaub: Das Thema "Stringverarbeitung" scheint für dich noch ein 
Buch mit 7 Siegeln zu sein. Da schwimmst du ordentlich. C bringt einige 
Funktionen im Header string.h mit, die man schon kennen sollte und auch 
wie sie angewendet werden.

von Kleiner Uni Student (Gast)


Lesenswert?

Aha.... also erst einlesen egal was kommt bis halt das zeichen \n kommt 
und dann soll er erst filtern.
Aber was ist wenn er mitten im string anfängt zu speichern ?
und wie kann ich denn sowas realisieren das er weis das das zeichen \n 
kommt ?
vielleicht so ?
1
char nmea_data[164];
2
.
3
.
4
.
5
int nmea_stream_buffer()
6
{
7
int i=0;
8
9
while(data != "\n")
10
{
11
 nmea_data[i] = IORD (GPS daten stream);
12
 i++;
13
}
14
15
data[i]='\0';
16
.
17
.
18
.
19
.

von Kleiner Uni Student (Gast)


Lesenswert?

Karl heinz Buchegger schrieb:
> Mit Verlaub: Das Thema "Stringverarbeitung" scheint für dich noch ein
> Buch mit 7 Siegeln zu sein. Da schwimmst du ordentlich. C bringt einige
> Funktionen im Header string.h mit, die man schon kennen sollte und auch
> wie sie angewendet werden.

Da hast du natürlich recht das wurde bei mir im Studium nicht so 
intensiv behandelt und ich habe mich damit noch nicht ganz so 
auseinander gesetzt, außerdem wusste ich auch noch nicht das es so viele 
funktionen im Header string.h gibt die mir das leben erleichtern. 
Deshalb frage ich hier ja ob man mir so, da oder da mal etwas unter die 
arme greifen kann, weil es an einigen stellen Recht mühsählig ist, drauf 
zu kommen welche funktion jetzt die richtige ist und welche gibt es die 
ich vielleicht anwenden kann.

von Karl H. (kbuchegg)


Lesenswert?

Kleiner Uni Student schrieb:
> Aha.... also erst einlesen egal was kommt bis halt das zeichen \n kommt
> und dann soll er erst filtern.

richtig

> Aber was ist wenn er mitten im string anfängt zu speichern ?

Dann findet das die Auswertefunktionalität sofort raus, indem die Zeile 
nicht mit einem $ anfängt. Die Auswertung verwirft dann die Zeile sofort 
und macht nichts weiter damit.

(*)

> und wie kann ich denn sowas realisieren das er weis das das zeichen \n
> kommt ?

Das kommt jetzt daraufan, wie in deinem µC die serielle Schnittstelle 
bedient wird und wie man dort konkret 1 Zeichen von der seriellen 
Schnittstelle einliest, sofern eines verfügbar ist. Im Idealfall kann 
man sich eine Interrupt-Funktion bauen, die im Hintergrund Zeichen 
einliest und wegspeichert. Ist die Zeile fertig, dann benachrichtigt sie 
(mit einem globalen Flag) das restliche Programm, dass eine Zeile 
verfügbar ist und legt sich weiter auf die Lauer

> int nmea_stream_buffer()
> {
> int i=0;
>
> while(data != "\n")

wo hat data denn seinen Wert her?

> {
>  nmea_data[i] = IORD (GPS daten stream);
>  i++;
> }
>
> data[i]='\0';

wieso auf einmal data?

Bitte achte auch bei Programm-Skizzen auf Sinnhaftigkeit.
Aber grundsätzlich: Ja, kann man auch machen. Das ist halt die Polling 
Methode. Da muss man eben darauf aufpassen, dass man nicht jedesmal den 
Zeilenanfang verschläft, sonst kriegt man keine einzige gültige Zeile 
rein. Interrupt hat den Vorteil, dass man prinzipbedingt (solange 
Interrupts enabled sind natürlich) schon kein Zeichen verpassen kann.

(*) Das ist 1 Möglichkeit.
Eine Abwandlung davon könnte natürlich auch noch das Wissen, das jede 
Zeile mit $ beginnt in die Empfangsroutine reintragen. Die 
Empfangsroutine stellt dann fest, dass sie auf den Zeilenanfang wartet 
und verwirft alle Zeichen bis sie ein $ empfängt. Und erst dann gehts 
mit der Zeile los, solange bis der \n daher kommt, der die Zeile wieder 
abschliesst.
Ist auch eine Möglichkeit. Manchmal kann man es sich leisten, nicht 
päpstlicher als der Papst zu sein :-) Wenn das Protokoll soweit fix ist, 
dass Zeilenanfang und Zeilenende fix definiert sind, dann spricht nichts 
dagegen, dieses Wissen in der Empfangsroutine zu benutzen. Und sei es 
nur um sich potentiellen Bufferoverflows zu entziehen (wenn auch nicht 
allen).

von Kleiner Uni Student (Gast)


Lesenswert?

Oh je da ist mir ja mal was nicht ganz so optimales passiert moment ich 
mach es hier nochmal:
1
char nmea_data[164];
2
.
3
.
4
.
5
int nmea_stream_buffer()
6
{
7
int i=0;
8
9
while(nmea_data != "\n")
10
{
11
 nmea_data[i] = IORD (GPS daten stream);
12
 i++;
13
}
14
15
nmea_data[i]='\0';
16
.
17
.
18
.
19
.
jetzt müsste es Richtig sein.

Karl heinz Buchegger schrieb:
> Interrupt hat den Vorteil, dass man prinzipbedingt (solange
> Interrupts enabled sind natürlich) schon kein Zeichen verpassen kann.

Leider habe ich mit interrupts noch nicht gearbeitet und das müsste ich 
dann noch freischalten in meinem FPGA.

Ich wollte erstmal eine relativ "Einfache" Lösung für das einlesen und 
auswerten realisieren und sie dann später optimieren mit den interrupts 
und dann mit der check_sum.

Also wenn ich das jetzt soweit richtig verstanden habe, soll das 
programm etwa so aussehen (nur schematisch):

1) Einlesen des Strings bis "\n"
2) String überprüfen ob am anfang "$"
3) wenn nicht dann neunen string einlesen 1) wenn ja
4) string auf zeichenfolge "RMC" über prüfen wenn nicht zurück zu 1) 
wenn ja
5) die einzelnen teile mit strtok aufsplitten
6) dann mit atoi die werte umwandeln

ich hoffe mal nicht das der µc denn zeilen anfang verschläft bei dieser 
"Polling methode" denn der GPS daten transfär ist recht langsam mit 
9600baud

von Karl H. (kbuchegg)


Lesenswert?

Das hier
> das über einen Altera FPGA
ist noch interessant.

Offenbar bist du ja nicht auf einem klassischen µC.
Inwiefern beeinflusst der FPGA die C-Progammierung?

(Sorry, aber mit FPGA oder Prozessorkernen auf FPGA hab ich keine 
Erfahrung)

von Kleiner Uni Student (Gast)


Lesenswert?

Karl heinz Buchegger schrieb:
> Eine Abwandlung davon könnte natürlich auch noch das Wissen, das jede
> Zeile mit $ beginnt in die Empfangsroutine reintragen. Die
> Empfangsroutine stellt dann fest, dass sie auf den Zeilenanfang wartet
> und verwirft alle Zeichen bis sie ein $ empfängt. Und erst dann gehts
> mit der Zeile los, solange bis der \n daher kommt, der die Zeile wieder
> abschliesst.
> Ist auch eine Möglichkeit. Manchmal kann man es sich leisten, nicht
> päpstlicher als der Papst zu sein :-) Wenn das Protokoll soweit fix ist,
> dass Zeilenanfang und Zeilenende fix definiert sind, dann spricht nichts
> dagegen, dieses Wissen in der Empfangsroutine zu benutzen. Und sei es
> nur um sich potentiellen Bufferoverflows zu entziehen (wenn auch nicht
> allen).

Diese Möglichkeit finde ich wesentlich eleganter und diese könnte doch 
dann in etwa so aussehen oder ?

[c]

char nmea_data[164];
.
.
.
char data;

data = IORD ( GPS daten empfang);

if ( data == '$')
{
.
.
// Hier Fängt die Empfangsroutine an
int nmea_stream_buffer()
{
int i=0;

while(nmea_data != "\n")
{
 nmea_data[i] = IORD (GPS daten stream);
 i++;
}

.
.

von Kleiner Uni Student (Gast)


Lesenswert?

sorry hier nochmal der queltext gehigh lighted
1
char nmea_data[164];
2
.
3
.
4
.
5
char data;
6
7
data = IORD ( GPS daten empfang);
8
9
if ( data == '$')
10
{
11
.
12
.
13
// Hier Fängt die Empfangsroutine an
14
int nmea_stream_buffer()
15
{
16
int i=0;
17
18
while(nmea_data != "\n")
19
{
20
 nmea_data[i] = IORD (GPS daten stream);
21
 i++;
22
}
23
24
.
25
.

von Karl H. (kbuchegg)


Lesenswert?

Kleiner Uni Student schrieb:
> Oh je da ist mir ja mal was nicht ganz so optimales passiert moment ich
> mach es hier nochmal:
>
>
1
> char nmea_data[164];
2
> .
3
> .
4
> .
5
> int nmea_stream_buffer()
6
> {
7
> int i=0;
8
> 
9
> while(nmea_data != "\n")
10
> {
11
>  nmea_data[i] = IORD (GPS daten stream);
12
>  i++;
13
> }
14
> 
15
> nmea_data[i]='\0';
16
> .
17
> .
18
> .
19
> .
20
>
> jetzt müsste es Richtig sein.

Das kann schon nicht stimmen

> while(nmea_data != "\n")

nmea_data ist ein character Array. Arrays kann man nicht vergleichen und 
schon gar nicht so. Ausserdem: Wer garantiert, dass in nmea_data nicht 
zufällig der String "\n" enthalten ist? Nach Betreten der Funktion hast 
du ja gar nichts mit nmea_data gemacht, weißt daher gar nicht welchen 
Inhalt dieses Array hat. Ausserdem willst du ja gar nicht wissen, was in 
nmea_data drinnen steht, sondern du willst die Schleife beenden wenn 
'das nächste empfangene Zeichen' ein \n ist. nmea_data ist aber nicht 
das nächste empfangene Zeichen.


IORD, ist das eine Funktion die auf das nächste Zeichen wartet?

1
int nmea_stream_buffer()
2
{
3
  int  i = 0;
4
  char c;
5
6
  c = IORD( GPS daten stream );
7
  while( c != '\n' )
8
  {
9
    if( c != '\r' )      // \r wird kommentarlos einfach ignoriert
10
      nmea_data[i++] = c;
11
    c = IORD( GPS daten stream );
12
  }
13
 
14
  nmea_data[i] = '\0';
15
16
  return i;
17
}

von Kleiner Uni Student (Gast)


Lesenswert?

Also das mit dem FPGA ist so ganz interessant, da ist ein standart 
NIOSII prozessor von Altera implementiert, im prinzip beeinfluß dieser 
nur die ein und ausgangs bezeichnungen weil diese alle frei wählbar sind 
und die UART schnittstelle muss auch noch parametriert werden, aber 
sonst ist es wie ein normaler µc.

von Kleiner Uni Student (Gast)


Lesenswert?

IORD ist eine Funktion die mich mit dem UART daten stream verbindet, so 
das wenn ich IORD aufrufe mit der base adresse und dem anschluss es mir 
die daten von dort holt.
1
IORD (Base_adresse, UART-Connection)

ob neue daten gesendet werden bestimme ich mit einer while schile
1
while(read_uart ==0){}

Die funktion read_uart gibt mir eine "1" raus wenn ein Byte gesendet 
wird so springt der dann aus der schleife und liest mir die daten in 
eine variable bsp:
1
char data;
2
3
while(1)
4
{
5
while(read_uart == 0) {}
6
data = IORD (Base_adresse, UART-Connection);
7
}

von Kleiner Uni Student (Gast)


Lesenswert?

Karl heinz Buchegger schrieb:
> int nmea_stream_buffer()
> {
>   int  i = 0;
>   char c;
>
>   c = IORD( GPS daten stream );
>   while( c != '\n' )
>   {
>     if( c != '\r' )      // \r wird kommentarlos einfach ignoriert
>       nmea_data[i++] = c;
>     c = IORD( GPS daten stream );
>   }
>
>   nmea_data[i] = '\0';
>
>   return i;
> }

hmm... also würde es dann in etwa so klappen müssen, okay bin ich mit 
einverstanden, bloß wie frage ich jetzt ab ob der stream '\0' enthält ?

und wie so "return i" und nicht z.b. return (1) ? um zu kennzeichnen das 
ich daten im buffer habe bzw. einen string?

von Kleiner Uni Student (Gast)


Lesenswert?

Kleiner Uni Student schrieb:
> hmm... also würde es dann in etwa so klappen müssen, okay bin ich mit
> einverstanden, bloß wie frage ich jetzt ab ob der stream '\0' enthält ?

okay die frage war überflüssig sorry.

von Karl H. (kbuchegg)


Lesenswert?

Kleiner Uni Student schrieb:

> und wie so "return i"

wofür wird sich der Aufrufer wohl interessieren?

zb. für die Länge des empfangenen Strings. i ist aber an dieser Stelle 
diese Länge. Der Aufrufer kann dann zb eine komplett leere Zeile ganz 
einfach ohne langes Testen verwerfen, indem er eine Zeile nur dann 
zulässt, wenn ihre Länge größer 0 ist.

Du kannst natürlich auch etwas anderes als deinen Return Wert benutzen, 
wenn du etwas sinnvolles dafür hast.

> z.b. return (1)

das ..... ist nicht wirklich sinnvoll. Wenn die Funktion sowieso dauern 
1 zurückliefert, dann ist das für den Aufrufer keine sinnvolle 
Information.

von Simon K. (simon) Benutzerseite


Lesenswert?

Viel wichtiger ist es, dass du den Sourcecode entsprechend einrückst. 
Damit erleichterst du dir und Anderen das Leben.

von Kleiner Uni Student (Gast)


Lesenswert?

Karl heinz Buchegger schrieb:
>> z.b. return (1)
>
> das ..... ist nicht wirklich sinnvoll. Wenn die Funktion sowieso dauern
> 1 zurückliefert, dann ist das für den Aufrufer keine sinnvolle
> Information.

Da hast du natürlich recht, das habe ich mir garnicht so überlegt, das 
mit dem rückgabe wert wie lang der string ist, ist eigentlich ganz gut 
so kann ich dann später das übergabe feld passend dafür bestimmen, bloß 
wie kann ich es denn jetzt machen das ich weiß, ob der string jetzt 
fertig ist ?
wie kann ich z.b. von der Einlese routine der überprüfungs routine 
irgend wie sagen , so ich bin fertig nun komm Prüfroutine guck mal ob 
ich das richtige ins feld geschrieben habe?
meine erste überlegung währe einfach unter die
1
 nmea_data[i] = '\0';
bedingung die überprüfung schreiben aber das würde die funktion nur 
unnötig verschandeln.

von Karl H. (kbuchegg)


Lesenswert?

Kleiner Uni Student schrieb:

> so kann ich dann später das übergabe feld passend dafür bestimmen, bloß
> wie kann ich es denn jetzt machen das ich weiß, ob der string jetzt
> fertig ist ?

Ganz einfach.
Du bist momentan auf Polling aus.

Wenn deine Funktion zurückkehrt, dann ist der String fertig.
Andernfalls wäre sie ja nicht aus der while Schleife rausgekommen und 
nie zum return gekommen.
1
int main()
2
{
3
  ...
4
5
  while( 1 ) {
6
7
    // warte auf eine komplette Zeile    
8
    nmea_stream_buffer();
9
10
    // jetzt ist die Zeile vollständig, werte sie aus
11
12
  }
13
}

Dieses Polling ist nicht der Weisheit letzter Schluss. Aber ehrlich 
gesagt denke ich, dass du erst mal damit genug zu tun hast, ehe man sich 
komplexeren Konzepten zuwendet, die ein gewisses Mass an Multitasking 
und Multithreading im Programm erlauben.

von Kleiner Uni Student (Gast)


Lesenswert?

Karl heinz Buchegger schrieb:
> Dieses Polling ist nicht der Weisheit letzter Schluss. Aber ehrlich
> gesagt denke ich, dass du erst mal damit genug zu tun hast, ehe man sich
> komplexeren Konzepten zuwendet, die ein gewisses Mass an Multitasking
> und Multithreading im Programm erlauben.

Ja das mit dem Pooling da hast du recht, da habe ich echt schon genug 
mit zu tun, mit den komplexen sachen weiß ich erstmal garnichts 
anzufangen, werde mich dort aber noch einarbeiten müssen wegen dem 
weiteren verlauf meines studiums welches dann wohl solcher methoden 
bedarf.


Vielen dank für die Hilfe werde morgen das ganze mal ausprobieren und 
mal schauen wie es läuft / Funktioniert.
Werde mich dann mal morgen melden mit "ergebnissen" und wohl tausend 
weiteren fragen vielleicht hast du / ihr ja tipps was ich mir unbedingt 
durchlesen sollte oder welche tutorials ich durcharbeiten sollte um da 
noch tiefer in die materie einzusteigen um irgend wann mal dann mit den 
komplexen sachen anzufangen.

von Kleiner Uni Student (Gast)


Lesenswert?

Hi,

auf ein neues, also ich habe das jetzt mal an mein project angepasst 
leider funktioniert das noch nicht ganz so mit den strtok() Funktion

habe diese so wie oben beschrieben:

Kleiner Uni Student schrieb:
1
> char * Kennung;
2
> 
3
>   char * Time;
4
> 
5
>   char * Latitude;
6
> 
7
>   char * NorthSouth;
8
> 
9
>   char * Longitude;
10
> 
11
> 
12
> 
13
>   Kennung    = strtok( nmea_packet, "," ); // $GPRMC
14
> 
15
>   Time       = strtok( NULL, "," );
16
> 
17
>   KeinAhnung = strtok( NULL, "," );
18
> 
19
>   Latitude   = strtok( NULL, "," );
20
> 
21
>   NorthSouth = strtok( NULL, "," );
22
> 
23
>   Longitute  = strtok( NULL, "," );
24
> 
25
> 
26
> 
27
>   ...
28
> 
29
> 
30
> 
31
>   // Dies Strings weiter behandeln, zb aus den 'Zahlenwerten' echte
32
> 
33
>   // Zahlen machen, sofern(!) in den jeweilgen Variablen keine NULL
34
> 
35
>   // Pointer sind.
36
> 
37
>   ...

für mein progrämchen angepasst wenn ich jetzt die daten mit antenne 
ausgebe kommt das raus:

GPRMC,092933.00,A,5133.61527,N,00806.84301,E,0.233,,290710,,,A*7E

Header: GPRMC
Time: 092933.00
Status: A
Latitude: 5133.61527
NorthSouth: N
Longitude: 00806.84301
EastWest: E
Speed: 0.233
Date: 290710
checksum: A*7E

scheint soweit alles ok zu sein bloß wenn ich diese ohne antenne ausgebe 
kommt das:

GPRMC,,V,,,,,,,,,,N*53
Header: GPRMC
Time: V
Status: N*53
Latitude: (null)
NorthSouth: (null)
Longitude: (null)
EastWest: (null)
Speed: (null)
Date: (null)
checksum: (null)

das ist nicht gut, scheint so als ob der wenn zwischen zwei kommas keine 
daten sind auch nichts ausgibt in die token. wie kann ich dieses problem 
beheben das er mir da trotzdem was rein schreibt?
und dann habe ich da noch was, ich habe um nur die checksume zu 
beckumen, also die beiden zeichen z.b. "7E" die vor dem "*" stehen 
folgendes angewendet
1
checksum  = strtok( NULL, "*" );

leider bekomme ich dann als ausgabe denn header raus
GPRMC
wie so kommt das ?

über hilfe währe ich sehr dankebar.

von Karl H. (kbuchegg)


Lesenswert?

Kleiner Uni Student schrieb:


> für mein progrämchen angepasst wenn ich jetzt die daten mit antenne
> ausgebe kommt das raus:

soweit so gut.
Damit denke ich, hast du verstanden wie strtok funktioniert.


> scheint soweit alles ok zu sein bloß wenn ich diese ohne antenne ausgebe
> kommt das:
>

Du hast soeben entdeckt, wo der Schwachpunkt (in meinen Augen) bei 
strtok liegt: strtok sucht beim nächsten Feld auf jeden Fall nach einem 
Anfang, leere Felder gibt es nicht.

> das ist nicht gut, scheint so als ob der wenn zwischen zwei kommas keine
> daten sind auch nichts ausgibt in die token. wie kann ich dieses problem
> beheben das er mir da trotzdem was rein schreibt?

ein eigenes strtok schreiben.
Da es nicht so flexibel sein muss wie das echte (nur 1 Delimiter), ist 
das auch nicht weiter schwer.

> und dann habe ich da noch was, ich habe um nur die checksume zu
> beckumen, also die beiden zeichen z.b. "7E" die vor dem "*" stehen
> folgendes angewendet
>
1
> checksum  = strtok( NULL, "*" );
2
>
>
> leider bekomme ich dann als ausgabe denn header raus
> GPRMC
> wie so kommt das ?

das müsste man jetzt im Zusammenhang sehen. Würd ich allerdings so gar 
nicht machen.

von Stefan B. (stefan) Benutzerseite


Lesenswert?

Karl heinz Buchegger schrieb:

> Du hast soeben entdeckt, wo der Schwachpunkt (in meinen Augen) bei
> strtok liegt: strtok sucht beim nächsten Feld auf jeden Fall nach einem
> Anfang, leere Felder gibt es nicht.

strsep wäre dann die Funktion der Wahl.
http://manpages.courier-mta.org/htmlman3/strsep.3.html

Offtopic: Ist in der avr-libc enthalten
http://www.nongnu.org/avr-libc/user-manual/group__avr__string.html#gff88adec2ad0446259766197ec3863de

von Christoph S. (kleinerunistudent)


Lesenswert?

Karl heinz Buchegger schrieb:
> das müsste man jetzt im Zusammenhang sehen. Würd ich allerdings so gar
> nicht machen.

hmm... ich überlege grade ich ich sowas realisierin könnte also ein 
strtok() funktion selber schreiben...

würde das mit einer while schleife machen wie beim string einlesen und 
dann noch eine die überprüft ob ich am ende angekommen bin oder nicht 
wenn ja springt die raus wenn nicht dann nicht?
sind die überlegungen so schonmal okay ?

Stefan B. schrieb:
> strsep wäre dann die Funktion der Wahl.

Danke für den tipp dieses werde ich auch mal ausprobieren, ich habe die 
Funktion doch richtig verstanden ich muss doch einfach nur das strtok() 
gegen strsep() bei mir austauschen und dann läuft es oder habe ich da 
irgend was übersehen ?
kann es genau wie gestern nicht ausprobieren weil ich nicht vorort bin 
und es erst morgen machen kann...

habt vielen dank für die hilfe und anregungen so wie die ganzen tipps.

von Stefan B. (stefan) Benutzerseite


Lesenswert?

Dein Beispielprogramm 
Beitrag "Re: Variables Feld für NMEA Protokoll" wäre gem. Manual so 
abzuändern
1
{
2
  char **stringp = nmea_packet; // Inhalt von nmea_packet wird verändert!
3
  Kennung    = strsep( stringp, "," ); // $GPRMC
4
  Time       = strsep( stringp, "," );
5
  KeinAhnung = strsep( stringp, "," );
6
  Latitude   = strsep( stringp, "," );
7
  NorthSouth = strsep( stringp, "," );
8
  Longitude  = strsep( stringp, "," );
9
  // usw.
10
}

Oder schleifenmäßig:
1
{
2
  char **stringp = nmea_packet; // Inhalt von nmea_packet wird verändert!
3
  while ( *stringp )
4
  {
5
    static int i = 0;
6
    char *token; 
7
    token = strsep( stringp, "," );
8
    printf("Token #%d = [%s]", i, token ? : "NULL");
9
    i++;
10
  }
11
}

von Andreas H. (andreas31)


Lesenswert?

Es gibt hier [http://vancouver-webpages.com/pub/peter/mfcnmea.zip] eine 
Klasse für das NMEA0183-Protokoll. Ist zwar in C++ aber vielleicht hilft 
es Dir ja weiter. Auf dem PC habe ich die Klasse schon verwendet.

Grüße
Andreas

von ... (Gast)


Lesenswert?

Stefan B. schrieb:
> Dein Beispielprogramm
> Beitrag "Re: Variables Feld für NMEA Protokoll" wäre gem. Manual so
> abzuändern
> {
>   char **stringp = nmea_packet; // Inhalt von nmea_packet wird verändert!
>   Kennung    = strsep( stringp, "," ); // $GPRMC
>   Time       = strsep( stringp, "," );
>   KeinAhnung = strsep( stringp, "," );
>   Latitude   = strsep( stringp, "," );
>   NorthSouth = strsep( stringp, "," );
>   Longitude  = strsep( stringp, "," );
>   // usw.
> }
>
> Oder schleifenmäßig:
> {
>   char **stringp = nmea_packet; // Inhalt von nmea_packet wird verändert!
>   while ( *stringp )
>   {
>     static int i = 0;
>     char *token;
>     token = strsep( stringp, "," );
>     printf("Token #%d = [%s]", i, token ? : "NULL");
>     i++;
>   }
> }
>

Das haut so NICHT hin!
So wirds besser:
1
{
2
  char *stringp = nmea_packet; // Inhalt von nmea_packet wird verändert!
3
  Kennung    = strsep( &stringp, "," ); // $GPRMC
4
  Time       = strsep( &stringp, "," );
5
  KeinAhnung = strsep( &stringp, "," );
6
  Latitude   = strsep( &stringp, "," );
7
  NorthSouth = strsep( &stringp, "," );
8
  Longitude  = strsep( &stringp, "," );
9
  // usw.
10
}
bzw.
1
{
2
  char *stringp = nmea_packet; // Inhalt von nmea_packet wird verändert!
3
  while ( stringp )
4
  {
5
    static int i = 0;
6
    char *token; 
7
    token = strsep( &stringp, "," );
8
    printf("Token #%d = [%s]", i, token ? : "NULL");
9
    i++;
10
  }
11
}

von Stefan B. (stefan) Benutzerseite


Angehängte Dateien:

Lesenswert?

Danke ..., du hast natürlich Recht! Im Anhang ist ein komplettes 
Beispiel.

von Kleiner Uni Student (Gast)


Lesenswert?

So Leute,
habe die tage etwas an dem Projekt rumgedoktort und es in einigen sachen 
verändert und modifiziert, jetzt stört mich irgend wie die strsep() 
funktion weil diese zu überdimensioniert ist, kann ich diese nicht 
irgend wie selber realisieren ? währ das nicht einfacher ? also vom 
handling her ? irgend wie mit einer while schleife ?
über einen tipp oder programm beispiel währe ich sehr dank bar.

mein vorschalg währe etwa so:
1
char *stringp=nmea_packet;
2
int count,a,b;
3
while (stringp != '\n')
4
{
5
  y = 0;
6
  while (stringp != ',')
7
  {
8
    nmea_packet[count]= string[x][y];
9
    count ++;
10
  }
11
  x++;
12
  count++;
13
}

von Karl H. (kbuchegg)


Lesenswert?

Kleiner Uni Student schrieb:
> So Leute,
> habe die tage etwas an dem Projekt rumgedoktort und es in einigen sachen
> verändert und modifiziert, jetzt stört mich irgend wie die strsep()
> funktion weil diese zu überdimensioniert ist

Für deine Zwecke ist sie das auch.
Die Überdimensionierung rührt daher, dass strsep mit mehr als einem 
Delimiter gleichzeitig klar kommen muss. Da du nur 1nen hast, könnte man 
sich ein strsep Derivat schreiben, das grundsätzlich gleich 
funktioniert, aber als Delimiter lediglich einen einzelnen char anstelle 
eines Strings nimmt. Damit fällt dann in strsep schon mal mehr als die 
Hälfte Code raus.

>, kann ich diese nicht
> irgend wie selber realisieren ?

Wenn du es kannst, sicher

> währ das nicht einfacher ? also vom
> handling her ?

Nicht wirklich.
Die Grundidee, die hinter strtok, strsep steckt, ist grundsätzlich nicht 
schlecht. Auch vom Handling der Funktionen her. Sie sind schnell, 
kopieren keine Strings unnötig durch die Gegend und ihr Interface ist so 
gestaltet, dass die typischen Anwendungsfälle einfach abzudecken sind.
Einziger Nachteil: der Originalstring wird verändert, sie sind nicht 
reentrant geschrieben. Zumindest letzter Punkt ist durch strtok_r 
behoben.

> über einen tipp oder programm beispiel währe ich sehr dank bar.

Der Tipp.
Lern endlich C Stringverarbeitung von der Pieke auf. Es ist nicht 
trivial aber auch nicht so schwer.

>
1
> char *stringp=nmea_packet;
2
> int count,a,b;
3
> while (stringp != '\n')
4
> {
5
>   y = 0;
6
>   while (stringp != ',')
7
>   {
8
>     nmea_packet[count]= string[x][y];
9
>     count ++;
10
>   }
11
>   x++;
12
>   count++;
13
> }
14
>

Das wird nichts.

von Kleiner Uni Student (Gast)


Lesenswert?

Karl heinz Buchegger schrieb:
> Der Tipp.
>
> Lern endlich C Stringverarbeitung von der Pieke auf. Es ist nicht
>
> trivial aber auch nicht so schwer.

Hast du vielleicht ein gutes tutorial dazu ? oder vll ein buch ?

von Karl H. (kbuchegg)


Lesenswert?

Kleiner Uni Student schrieb:
> Karl heinz Buchegger schrieb:
>> Der Tipp.
>>
>> Lern endlich C Stringverarbeitung von der Pieke auf. Es ist nicht
>>
>> trivial aber auch nicht so schwer.
>
> Hast du vielleicht ein gutes tutorial dazu ? oder vll ein buch ?

Wie immer: Die C-Bibel

Kernighan&Ritchie
Programmieren in C


Allerdings: Stringverarbeitung steht und fällt damit, dass man die 
C-Vereinbarung "Ein C-String ist: solange Zeichen bis ein '\0' Zeichen 
kommt" ernst nimmt. Alles andere ist reines Arbeiten mit Arrays. Kann 
man mit Arrays arbeiten (umkopieren, vergleichen, ein Element in einem 
Array suchen, etc.) und nimmt noch dieses '\0' Zeichen als Abschluss mit 
dazu, dann ist man bei C-Stringverarbeitung.

Dieses '\0' Zeichen hat 2 Implikationen
* zum einen ist es das Stoppschild, das einem sagt
  "Hier ist der String zu Ende"
* zum anderen ist es das Zeichen, dass man bei jeglicher
  Stringverarbeitung niemals vergessen darf an das Ende eines
  Strings anzuhängen

Was strtok bzw. strsep im Grund machen, ist nichts anderes als in einen 
String entsprechende '\0' Zeichen einzufügen (indem der Delimiter durch 
'\0' ersetzt wird), um so den kompletten String in Teilstrings zu 
zerlegen. Und damit man auch von aussen wieder an die jeweiligen Anfänge 
dieser Teilstrings herankommt, machen sie das in mehreren Durchgängen, 
wobei bei einem Durchgang immer nur der nächste Teilstring identifiziert 
wird. Das ist alles was diese Funktionen machen.


Um es nochmal klar zu sagen:
Stringverarbeitung ist einfach nur eine kleine Erweiterung des Arbeiten 
mit Arrays. Die Erweiterung besteht darin, dass es ein spezielles 
Zeichen gibt.

Einen Character in einem String suchen unterscheidet sich in nichts 
davon, den Wert x in einem Array zu suchen. Nur dass man im 2ten Fall 
die Arraylänge kennen muss, während bei Stringverarbeitung das '\0' 
Zeichen die Aufgabe übernimmt, die Schleife vor Überlauf zu schützen.

von Kleiner Uni Student (Gast)


Lesenswert?

ah so ist das, hmm... dann muss ich mir mal was überlegen wie ich das 
realisieren würde.... mit der ersetzung des delimeters durch '\0' und 
dann dieses noch in felder zu schreiben....

danke für das buch werde mal gucken ob es sowas hier in der uni gibt.

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.