Forum: Mikrocontroller und Digitale Elektronik GPS Sensor - UART Ausgabe


von gps (Gast)


Lesenswert?

Hallo,

ich lese GPS Daten von einem UP500 GPS Sensor und gebe die über UART auf 
einem Arduino Uno wieder aus.
Es funktioniert soweit, allerdings sind die Ausgaben manchmal 
verschoben:
1
$GPRMC,002150.426,V,8960.0000,N,00000.0000,E,0.00,0.00,060180,,,N*78
2
$GPGGA,002150.626,8960.0000,N,00000.0000,E,0,0,,137.0,M,13.0,M,,*47
3
4
5
$GPRMC,002150.626,V,8960.0000,N,00000.0000,E,0.00,0.00,060180,,,N*7A
6
$GPGGA,002150.826,8960.0000,N,00000.0000,E,0,0,,137.0,M,13.0,M,,*49
7
8
9
$GPRMC,002150.826,V,8960.0000,N,00000.0000,E,0.00,0.00,060180,,,N*74
10
$GPGGA,002151.027,8960.0000,N,00000000,N,00000.0000,E,0.00,0.00,060180,,,N*74
11
PG025290.0000,N,0000.0000,E,0,0,,137.0,M,13.0,M,,*41
12
13
14
$GPRMC,002151.027,V,8960.0000,N,00000.0000,E,0.00,0.00,060180,,,N*7C
15
$GPGGA,002151.227,8960.0000,N,00000.0000,E,0,0,,137.0,M,13.0,M,,*43

Mein Programm:
1
#include <SoftwareSerial.h>
2
3
SoftwareSerial mySerial(4, 5); // RX, TX
4
5
char buffer[512];  
6
char buffidx;
7
#define BUFFSIZ 90 
8
9
void setup()  
10
{
11
  // Open serial communications and wait for port to open:
12
  Serial.begin(115200);
13
14
  // set the data rate for the SoftwareSerial port
15
  mySerial.begin(38400);
16
  
17
  Serial.println("start");
18
}
19
20
void loop() // run over and over
21
{
22
  if (mySerial.available())
23
  {
24
    Serial.write(mySerial.read());
25
    readline();
26
    
27
    // check if $GPRMC (global positioning fixed data)
28
    if (strncmp(buffer, "$GPRMC",6) == 0 || strncmp(buffer, "$GPGGA",6) == 0) {
29
      Serial.write(buffer);
30
    }       
31
  }
32
}
33
34
void readline(void) {
35
  char c;
36
  
37
  buffidx = 0; // start at begninning
38
  while (1) {
39
      c = mySerial.read();
40
      if (c == -1)
41
        continue;
42
43
      if (c == '\n')
44
        continue;
45
        
46
      if ((buffidx == BUFFSIZ-1) || (c == '\r')) {
47
        buffer[buffidx] = 0;
48
        return;
49
      }
50
      buffer[buffidx++]= c;
51
  }
52
}

Jemand eine Idee, was ich falsch mache?

Danke

von Matthias S. (Firma: matzetronics) (mschoeldgen)


Lesenswert?

gps schrieb:
> // set the data rate for the SoftwareSerial port
>   mySerial.begin(38400);

Es ist recht mutig, eine Soft-Uart gleich mit 38400 fahren zu wollen. Da 
kann es beim Buffer-Umschlagen schon mal eng werden, vor allem, wenn du 
mit den Daten noch rummachst.
Du siehst ja selber, das was unvollständig ist, weil der kleine Kerl 
noch am Rechnen war. Entweder schreibst du dir selber eine schnelle 
Soft-UART, oder du tauschst die Schnittstellen, und fährst den PC Port 
dann einfach langsamer.
Am sinnvollsten ist vermutlich ein MC mit 2 UART.

von gps (Gast)


Lesenswert?

Ich könnte den GPS Sensor auf 19200 baud stellen.

Laut Doku:

$PMTK251,38400*27<CR><LF> Für 38400  --> 27 ist die Checksumme

Wie berechne ich die Checksumme für $PMTK251,19200 ?

von gps (Gast)


Lesenswert?

Ah klappt, gerade rausgefunden.

Interessanter Effekt: Wenn ich die Baudrate vom Hardwareserial auf 19200 
setze, ist die Ausgabe nicht mehr kaputt.

Wie kommt es`?

von W.S. (Gast)


Lesenswert?

Du könntest erstmal etwas Klarheit in deiner Quelle schaffen.

In loop rufst du mySerial.read auf, nachdem du getestet hast, daß da was 
zum Liefern vorliegt - und in readline tust du es ebenfalls, aber ohne 
vorherigen Test.

Und Serial.write rufst du mal mit nem char und mal mit nem char* auf? 
Sehe ich das richtig oder war das bloß einer der üblichen Tippfehler?

Eigentlich sehe ich den Zweck der ganzen Routinen nicht recht ein. Wird 
da in den aufgerufenen Routinen gepuffert?

Und bei dem
"if (strncmp(buffer, "$GPRMC",6) == 0 || strncmp(buffer, "$GPGGA",6) == 
0)"
sehe ich eine heftige Zeitblockade.

Ich würde es anders machen:

1. für den Ausgangsstrom einen Ringpuffer einrichten
2. all sowas wir strncmp und Konsorten weglassen

immerzu:
  SoftUART-Handler rufen
  if TXfastleer und Ringpuffer nicht leer
       dann Zeichen vom Ringpuffer zum TX transferieren
  if RxhatZeichen dann Zeichen abholen
  if Zeilenpuffer nicht voll, dann Zeichen in Zeichenpuffer tun
  if Zeichen war CR dann
     { Zeilenpufferanfang zeichenweise testen,
       wenn was nicht stimmt, Zeilenpuffer löschen und testen beenden.

       Inhalt vom Zeilenpuffer in den Ringpuffer tun
       Zeilenpuffer löschen
     }
  else Zeitausgleich falls Schleife zum Innenleben des Soft-UART gehört
goto immerzu;

etwa so ähnlich. Ist hier ja nur grob skizziert. Jedenfalls so, daß die 
CPU immer in der Schleife herumrödelt OHNE sich irgendwo mit Warten auf 
irgendwas aufzuhalten.

W.S.

von gps (Gast)


Lesenswert?

Ich habe es noch pragmatischer gelöst:

C:\Program Files 
(x86)\Arduino1.6.4\hardware\arduino\avr\libraries\SoftwareSerial\Softwar 
eSerial.h
 die Buffergröße von
 #define _SS_MAX_RX_BUFF 64 // RX buffer size
  auf
 #define _SS_MAX_RX_BUFF 256 // RX buffer size

Jetzt gibt es keine Probleme mehr.

Kann man den Buffer auch innerhalb von einem Sketch ändern? Ich würde es 
ungerne in der lib selbst ändern und vergessen...

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.