Hallo liebe Leut,
ich scheitere beim Versuch, NMEA-Datensätze von einem GPS-Modul über
einen ATmega auf einen PC zu schicken. Das Modul hängt an USART1, der PC
an USART0.
Die Sache treibt mich noch in den Wahnsinn, weil ich schon seit Tagen
dranhänge und nicht weiterkomme.
Den Code hänge ich unten dran.
Ich warte auf das Start-Symbol '$', lese bis zum Endsymbol <LF> und
schreibe dann das ganze gelesene NMEA-Ding auf den USART0. Dabei kommen
solche Sachen raus:
$GPGGA,204947.000,5012.5204,N,01325.0072,E,1,03,4.8,96.0,M,44.6,M,,0000*
63
$G,13,,,,,,,,,,4.9,4.8,1.0*3D
$G,204947.000,A,5012.5204,N,01325.0072,E,0.95,302.95,161209,,*06
$GPGGA,204948.000,5012.5206,N,01325.0068,E,1,00,50.0,96.0,M,44.6,M,,0000
*5F
Es klappt also fast. Aber irgendeine Schweinerei ist da noch am
Laufen.
Besonders fies: wenn ich ich anstelle des <LF> schon beim '*' aufhöre,
klappt alles wunderbar!!!
Über erlösende Antworten würde ich mich sehr freuen.
Viele Grüße
Schwebo
--
Hi
>Es klappt also fast. Aber irgendeine Schweinerei ist da noch am>Laufen.>Besonders fies: wenn ich ich anstelle des <LF> schon beim '*' aufhöre,>klappt alles wunderbar!!!
Taktquelle des AVR?
MfG Spess
Hallo,
sendet er denn überhaupt ein '\n' oder sendet er vielleicht ein '\r'.
Weil du ja sagst wenn du auf '*' prüfst funktioniert es.
Sendet er überhaupt etwas wenn du auf '\n' wartest ? Also wird die if
Abfrage ausgeführt ?
Gruß
Planst du eigentlich im AVR noch irgendeine Auswertung der NMEA Daten?
Hintergrund:
Aus welchem Grund willst du Datensätze als solche empfangen, wenn du
sowieso keine Auswertung damit am AVR machst.
Ein Zeichen kommt vom GPS Device und wird als solches ohne Ansehen des
Inhalts einfach an die andere UART durchgeschleust. -> Der PC empfängt
alles, was auch der AVR empfangen hat. Der AVR muss sich nicht mit einer
Auswertung rumärgern.
Du sendest und empfängst mit jeweils ein und demselben Buffer.
Schon mal dran gedacht was eigentlich passiert, wenn das GPS Gerät zu
senden anfängt während du noch zum PC überträgst?
Ich möchte später das Signal direkt auf dem AVR auswerten, trotzdem
möchte ich jetzt erstmal die Daten an den PC weiterleiten.
Wg. dem Buffer: natürlich habe ich das berücksichtigt. Sobald ich ein
'\n' empfange, schalte ich den RX-Interrupt aus, so dass die ISR nicht
mehr durchlaufen wird. In der Main-Loop schalte ich ihn wieder ein,
sobald ich mit dem Weiterleiten an den PC fertig bin.
Dennis Vonnebrink schrieb:
> Wg. dem Buffer: natürlich habe ich das berücksichtigt.
Entschuldigung. Mein Fehler.
Hab ich überlesen.
Hmm. Auf der anderen Seite.
Wenn du den Empfang einfach nicht mehr auswertest, verlierst du Zeichen.
Genau das zeigen auch deine Mitschriften.
2 Zeichen kommen noch, die sind von der UART gepuffert worden. Und dann
fehlen Daten. Höchst wahrscheinlich genau soviele, wie das GPS Gerät mit
4800 Baud in der Zeit senden konnte, die deine Nachricht mit 19200 Baud
zum PC brauchte.
Fazit: Du darfst dem GPS Gerät nicht die Leitung zwischenzeitlich
kappen. Wenn eine Nachricht da ist, den Buffer in einen 2-ten
umkopieren, aus dem heraus du senden kannst und den Empfang während des
Sendens in den jetzt wieder leeren Empfangsbuffer weiterlaufen lassen.
Anstelle von Umkopieren kann man auch mit 2 Buffern arbeiten die
abwechselnd jeweils Empfangs bzw. Sendebuffer sind.
Genau, aber bevor ich damit anfange, in den Buffer zu schreiben, warte
ich ja wieder auf das '$'. Es kann natürlich gut sein, dass ich so die
eine oder andere Message vom GPS-Modul verpasse.
> Ich möchte später das Signal direkt auf dem AVR auswerten, trotzdem> möchte ich jetzt erstmal die Daten an den PC weiterleiten.
Das kannst Du aber einfacher so machen: Jedes empfangene Zeichen wird
direkt auf der zweiten UART wieder ausgegeben (geht nur bei gleicher
oder höherer Baudrate als der zum GPS-Empfänger), und zusätzlich für
die AVR-interne Auswertung in einen Puffer geschrieben.
Noch simpler ist der Verzicht auf die zweite UART und der direkte
Anschluss des PCs (nur dessen RX-Leitung) parallel zur RX-Leitung des
AVRs (natürlich mit V24-Pegelwandler).
D.h. der AVR lauscht dem, was der GPS-Empfänger dem PC erzählt.
Dennis Vonnebrink schrieb:
> Genau, aber bevor ich damit anfange, in den Buffer zu schreiben, warte> ich ja wieder auf das '$'. Es kann natürlich gut sein, dass ich so die> eine oder andere Message vom GPS-Modul verpasse.
Die UART selbst buffert 2 Zeichen.
Wenn du den Interrupt abstellst, dann wird das nächste empfangene
Zeichen in der UART gespeichert. Und das wird nun mal meistens der $ für
die nächste Message sein. Dieses Zwischenspeichern in der UART findet
auf jeden Fall statt, egal ob du den Interrupt aktiviert hast oder
nicht.
Wenn es dir egal ist, ob eine Message verloren geht oder nicht, steht es
dir natürlich frei, die UART durch Lesen von UDR auszuleeren, ehe du den
Interrupt wieder freigibst. Dann wartest du auf jeden Fall tatsächlich
auf den nächsten $, dessen Datensatz du komplett empfangen kannst.
Dennis Vonnebrink schrieb:
> gps_disable_serial_rx();>> // flush cached bytes> for (uint8_t j = 0; j < 2; j++) {> while ( !(UCSR1A & (1<<RXC1)) )> ;> b = UDR1;> }>> gps_rx_within_message = FALSE;> gps_rx_complete = TRUE;> rx_buffer[i] = '\0';
Das ist nicht so schlau.
Jetzt wartest du in der ISR darauf, dass das nächste Zeichen eintrifft
(wenn noch keines gekommen ist). Brauchst du doch gar nicht.
Lies einfach UDR1 zweimal aus. Dir ist doch sowieso egal, ob und wenn ja
was da in der Zwischenzeit eingetroffen ist.
1
gps_disable_serial_rx();
2
3
// flush cached bytes
4
while(UCSR1A&(1<<RXC1))// solange Zeichen vorhanden sind
5
b=UDR1;// lies sie und mach nichts damit
6
7
gps_rx_within_message=FALSE;
8
gps_rx_complete=TRUE;
9
rx_buffer[i]='\0';
ausserdem bist du hier an der falschen Stelle. Du willst die UART
flushen, nachdem du an den PC geschickt hast und bevor du den Interrupt
wieder aktivierst.
1
while(TRUE){
2
// wait for complete NMEA record
3
if(gps_rx_complete){
4
write(rx_buffer);
5
6
// prepare for next read
7
gps_rx_complete=FALSE;
8
9
// flush cached bytes
10
while(UCSR1A&(1<<RXC1))// solange Zeichen vorhanden sind
Deinen ersten Einwand verstehe ich - das funktioniert so nur, wenn
ständig Daten nachkommen. Allerdings hatte ich das, glaube ich, mal so
probiert wie Du das schreibst, aber da hatte ich immer noch denselben
Fehler-Effekt.
Ich bin gerade bei der Arbeit, kann das also erst heute abend
ausprobieren.
Den zweiten Punkt verstehe ich aber nicht. Ich deaktiviere doch zuerst
den Empfang mit gps_disable_serial_rx(); und stelle so sicher, dass ich
noch maximal 2 gepufferte Zeichen flushen muss. Wenn ich in der
Main-Loop den Empfang wieder einschalte, sollten da nur frische,
zusammen gehörende Zeichen kommen, oder? Die Variante, die Du
vorschlägst, würde m.E. genauso gut funktionieren, aber keinen Vorteil
bieten.
Dennis schrieb:
> Den zweiten Punkt verstehe ich aber nicht. Ich deaktiviere doch zuerst> den Empfang mit gps_disable_serial_rx(); und stelle so sicher, dass ich> noch maximal 2 gepufferte Zeichen flushen muss. Wenn ich in der> Main-Loop den Empfang wieder einschalte, sollten da nur frische,> zusammen gehörende Zeichen kommen, oder? Die Variante, die Du> vorschlägst, würde m.E. genauso gut funktionieren, aber keinen Vorteil> bieten.
Was ist wenn das GPS-Device nicht sofort mit dem nächsten Datensatz
anfängt sondern, sagen wir mal erst dann mit dem nächsten loslegt, wenn
du bereits die Hälfte des ersten Datensatzes rausgebuttert hast?
Gut. Bei dir kann das momentan nicht passieren, weil du ja in der ISR
auf die nächsten 2 Zeichen wartest. Aber das ist ja eigentlich sowieso
nicht richtig. Du willst ja nicht auf genau 2 Zeichen warten. Du willst
Zeichen die möglicherweise eingetroffen sind, verwerfen.
Und wenn du das tust kann es natürlich sein, dass das Gerät noch gar
nicht mit dem Senden angefangen hat, wenn du den Buffer flusht.
Aber es kann natürlich mit dem Senden angefangen haben während du auf
den PC rausbutterst.
Damit hast du den Fall, dass du zwar die UART geflusht hast, dir das
aber nichts bringt, weil das GPS-Gerät noch gar nicht mit dem Senden
angfangen hat. Trotzdem bist du dann in der Situation, dass bereits
Zeichen im UART gelandet sind, wenn du den Interrupt dann wieder
freigibst.
Da hast Du natürlich recht, das könnte passieren.
Wie wäre es, wenn ich in den Funktionen gps_enable_serial_rx() bzw.
gps_disable_serial_rx() anstelle des RXCIE1 das RXEN1 setze bzw. lösche?
Beim Löschen wird doch der Buffer geleert und kann auch nicht mehr
befüllt werden, bis das RXEN-Bit wieder gesetzt wird, oder?