So versuche ja seit einer Woche bestimmte Zeichen aus einem NMEA
Datensatz,
welches mir das GPS Modul über Uart an meinem STM32 versendet,
zu filter. Als erstes Versuche ich die Datensätze zu separieren, damit
ich dann in meiner main Routine diese weiterbearbeiten kann.
nun, wenn ich
sendbyte_usart(data1[0]);
sendbyte_usart(data2[0]);
ausführe, sehe ich, dass beide nicht wie eigentlich erwartet das $
Zeichen zeigen (der NMEA Datensatz fängt mit $GP... an),
sondern data2 ist schon bereits bei G gelandet
also will heißen
1
data1[0]=='$';
2
data2[0]=='G';
Wo liegt denn der Fehler das beide nicht mit $ anfangen???
Mein Interrupt siehe unten
Ist das ein Versuch witzig zu sein?
Ich mein, ich habe da was, was auch funktioniert,
nur sehe ich den Fehler nicht,
und das ganze ist nicht gerade unwichtig.
>Ist das ein Versuch witzig zu sein?
Nö.
>Ich mein, ich habe da was, was auch funktioniert,>nur sehe ich den Fehler nicht,>und das ganze ist nicht gerade unwichtig.
Mir doch egal. Fang noch mal von vorne an.
GPS Strings hab ich schon mit 8051 und AVR
auseinandergefummelt. Wenn du das mit einem
Cortex M3 nicht schaffst, dann... Naja.
Guten morgen, erstmal danke für die ganzen Posts...
Also per RS232-TTL-Wandler hab ich das Modul bereits am PC anschließen
können,
das ist kein Problem.
Ich frag mich bloß,
unabhängig ob ich jetzt was genaueres Filter (z.B. $GPVTG),
was ich mit dem Code eh nicht mache,
wieso die Datensätze nicht vernünftg in den zwei data-Arrays
hin und her geschrieben werden.
Der Mikrocontroller ist so schnell das er die Datensätze mehrfalls
aufruft,
wo wenn beide Arrays nicht von der selben Stelle anfangen,
ist schon irgendwas falsch.
Oder wäre es expliziet falsch das ganze mit einem Interrupt aufzuziehen?
Nur zur kurzen Info:
Das ganze ist kein reiner GPS Logger,
die Daten müssen empfangen und zu weiteren
Berechnung weitergeführt werden
Das empfange nund sammel in Puffern kann man schon im RX Interupt machen
nur komplexere Berechnungen sollte man sein lassen. Aber ich versteh
immer noch nicht was dein STM32 so langsam macht läuft der mit nem
32768kHz Quarz ?
Ich denke das man sogar mit ner 72MHz version so um die 50MBit/s
Datendurchsatz mit einigen Komplexeren Rechenoperationen hinbekommt !
Warum schaft dein System keine 38,4 KBit/s ? Ein solches NMEA Protokoll
kann man sicherlich mit gutem Gewissen komplett im Interupt decodieren
ohne Probleme zu bekommen. Ich denke du solltest dir ein paar Kapitel zu
Zustandsautomaten (Statemachines) durchlesen kooperatives Multitasking
bzw. manche kleinen Echtzeitbetriebsysteme sind nach diesem Prinzip
aufgebaut.
Für dich wird das niemand programmieren wir helfen nur. Aber du mußt
auch die Stichworte Goo*ln und selber lesen. Zeichne doch einfach mal
nen Statechart einer Statemachine die du in C gebastelt hast dort siehst
du normalerweise schnell deine Fehler und kommst auch durch einfaches
über legen darauf wie du weitermachen mußt. Du mußt dir halt denken du
bist der Controller und deine Statemachine von anfang an durch gehen. Am
Anfang geht dies besser mit Statecharts. Und du brauchst auch einen
Resetzustand oder Anfangszustand in der die Staemachine einfach nur
wartet bis was zu tun ist.
Uwe, ich gebe dir da recht,
ich möchte es auch alleine schaffen,
auch wenn gerade unmut und verzweiflung gerade breit macht,
da ich es nichtmals schaffen,
die datensätze zwischen zwei buffer (data1 und data 2) zu toggeln
der stm32 ist schnell genug (so denke ich)
da ich beim aufrufen in main,
den momentanen datensatz mehrmals aufruft,
(da ich nur erstmal einen char anzeigen lasse,
habe ich z.B. zich LLLLLLL... (von GLL) bevor der zum nächsten Satz z.B.
MMMMMM... (von RMC) springt.
bis dieser geändert wird.
das geht z.B. wenn ich data2[4] senden lasse, bekomme ich das M wieder
(d.h. '$','G','P','R','M','C') was auch i.O. ist
bei data1[4], sendet er mir einmalig(!) das M, dannach nur die Cs
[natürlich wechseln die Datensätze durch, aber anhand der reihenfolge im
register, kann man diesen verlauf erkennen.]
der momentane Code sieht so aus
Wo wird überall 'Ucounter' verändert?
Wie sind 'data1' & 'data2' initialisiert?
-----
Anmerkungen falls ich zu undeutlich war:
-In deiner 1. Version wurde 'Ucounter' nicht resettet - jetzt ja schon
:). Hat sich was gebessert?
-Auch aus deinem 2. Code-Abschnitt ist nicht ersichtlich wie data1 + 2
initialisiert werden.
-Und was meinst du eigentlich mit "... wenn ich data2[4] senden lasse,
..."?. Ich dachte du willst empfangen?
-----
Deine 2 Code-Beispiele unterscheiden sich funktional sehr stark.
Version 1 kann nicht so funktionieren wie du erwartest.
Version 2 sieht auf den ersten Blick besser aus...
Hi Flo,
Deine zweite Lösung sieht eigentlich gut aus. Was ich aber ein wenig
seltsam finde ist deine Deklaration der beiden Puffer:
char data1[],data2[];
Hier fehlt aus meiner Sicht eine Größenangabe wie:
char data1[100],data2[100];
Wenn ichs gerade richtig im Kopf habe kann ein NMEA Frame max. 83
Character groß sein.
Ich habe gerade mal bei mir im Code eine solche deklaration ausprobiert.
Bei mir gibt es keine Compiler Warnung aber die Deklarierten Arrays
haben nur eine Größe von jew. einem Byte.
Schau bitte mal in deinem Map-File nach wie groß deine Puffer sind.
Heute Abend könnte ich Dir auch mal meinen NMEA Parser schicken.
Vieleicht kannst Du da was kupfern.
Gruß,
Ralf
@Ralf:
Nicht alles verraten!
Nur wenn man Probleme selber löst lernt man auch was dabei.
Außerdem finde ich abkupfern für eine Uni-Arbeit - lass es mich höflich
ausdrücken - eher suboptimal.
Und es scheitert hier aktuell nicht am Parser, sondern schon an der
Datenübernahme.
Bei nachfolgendem text möchte ich gerne wissen was die Funktion
"USART_ReceiveData(USART1)" macht.
Denn wenn das eine blockierende funktion ist die darauf wartet das ein
Zeichen empfangen wird dann kann das so nicht funktionieren.
Du solltest an nur einmal VOR der ganzen switch Funktion das UDR
Register
auslesen und in einer Variable speichern. Auf die Variable kannst du in
späteren "case" und "if" Funktionen zugreifen.
> switch(state)> {> case Warte_A:> if(USART_ReceiveData(USART1) =='$')> {> data1[Ucounter++] = USART_ReceiveData(USART1);> next_state = Sammel_A;> }> break;
also ich hatte noch ein Fehler im Programm, siehe Bemerkung.
also mio und ralf, ihr hattet anscheinend recht mit der initialisierung
von data1 und data2.
Ich wußte schon das ein NMEA Datensatz max83 Charterzeichen beinhalten
können,
wurde nur aufgrund meiner Misserfolge mißtrauisch,
und habs weggelassen.
bei aufruf im main programm lassen sich beide datastrings ohne
fehleranzeigen, und wenn sie direkt hintereinander geschrieben sind -_-
aber diese sind komplett, was schonmal wichtig ist.
(siehe anhang)
Also vielen Dank nochmal für den Hinweis.
Ralf, auch wenns Mio nicht gerne sieht, würdest du mir einen riesen
gefallen mit dem Parse Code machen,
ich verspreche auch das ich es erstmal alleine Versuche.
Mio, mit dem senden, das dient als kontrolle,
da ich nie wirlich den umgang mit dem debugger gelernt habe,
muss ich einwenig "erfinderisch" sein...
so sende ich das was ich gefiltert habe, um zu sehen obs korrekt ist,
wenns einmal läuft wird auch nichts mehr gesendet.
Wenn ich es richtig deute,
ließt dieser nur den register aus.
mit einer blockierenden funktion meinst
du schleifen etc.
*ich sehs kommen, gleich klatscht es gleich für mich,
aber kein beifall*
Punkt 1:
'USART_ReceiveData' liest aus dem UART-Datenregister 1 Byte aus.
Richtig?
D.h., mit deinen if-Abfragen hast du das 1. Byte schon gelesen, und
schreibst, aber das 2. in dein Array:
1
if(USART_ReceiveData(USART1)!='\r')
2
{
3
data1[Ucounter++]=USART_ReceiveData(USART1);
4
}
Entweder du übersiehst hier jedes 2. Byte, oder ich übersehe deine
Absicht :)
Punkt 2:
Wieviel Bytes kann dein UART-Datenregister puffern?
Du liest pro IRQ 2 Bytes aus. Unter Umständen enthält die Queue aber
noch mehr Daten. Evtl. gibt es in der STM32-API eine Funktion die dir
angibt wieviel Daten noch im Puffer enthalten sind.
ich komme nicht ganz dahinter was du mit punkt 1 meinst,
wenn du so meinst sind es zwei vorgänge.
meinst du damit mein mc käme damit in verzug?
müsste sich das nicht im terminal wiederspiegeln?
indem jedes zweite zeichen falsch wäre?
zu punkt zwei,
ich schau mal eben nach ;)
Ich lese im RM0008 von 8Bit Data Value.
Wenn ich es richtig verstanden habe,
kann man den Status anzeigen lassen,
ob RXNE noch gefüllt ist oder nicht.
Man kann diesen Status (Flag) auch aufheben,
somit müsste der MC wieder von vorne
das DR Register überschreiben können.
War das deine Idee gewesen? ^^
Quasi.
Du hast Recht:
"...Bit 5 RXNE: Read data register not empty
This bit is set by hardware when the content of the RDR shift register
has been transferred to the USART_DR register. An interrupt is generated
if RXNEIE=1 in the USART_CR1 register..."
Das macht der alles in Hardware.
Punkt 1 ist damit auch obsolet.
Ich habe mal deinen Einwand zu dem Thema Restbits berücksichtigt,
USART_ClearFlag(USART1, USART_FLAG_RXNE);
es machte keinen Unterschied.
Es ist auch die Frage ob es sinnvoll ist direkt das RXNE-InterruptFlag
mit zu löschen...
Ich habe den Code leicht überarbeitet,
laut Terminal überschreibt er eine Zeile zich mal,
Bis dieser einen Zeilensprung macht,
und sich wiederüberschreibt...
müsste er nicht jedes cr lf mitkriegen, und auch darstellen?
schließlich hat er in der Bedingung
wenn letztes Zeichen \r und das neuste Zeichen \t,
dann soll er noch das neue Zeichen übernehmen,
bevor er zum nächsten state wechselt, gell?
So ich bin endlich beim Parsen angelangt,
und bekomme eine Fehlermeldung,
die ich nicht ganz nachvollziehen kann
main.c(525): error: #167: argument of type "int" is incompatible with
parameter of type "const char *restrict"
die Fehlermeldung bekomme ich bei allen strtokunktionen,
dabei nutze ich garkein int?!
Hier der Quelltext
die Arrays sind als Char deklariert
Hi Flo,
machts dir was aus deinen Code hochzuladen?
Ich hab mein GPS modul an der USART2 hängen. Momentan lese ich noch in
einer Schleife alle Daten aus. Ich würde gerne wie du ein Interrupt
haben der mir mein "GPS-Buffer" füllt und sobal der NMEA Satz komplett
ist diesen auf mein Terminal (hab ich mit USB VCOM realisiert) ausgibt.
Viele Grüße
Hans P.