GPS Datenlogger

Hallo zusammen,

ich habe vom Arbeitgeber die Aufgabe bekommen, einen GPS Datenlogger zu bauen. Habe mir die Komponenten bestellt und wollte jetzt versuchen, Daten auf die SD Karte zu schreiben.

Habe den Arduino MEGA 2560. Das GPS-Shield und das microSD-Shield habe ich von sparkfun. Habe den Sketch hochgeladen, der GPS-Receiver hat auch Signal (er blinkt zumindest mal), jedoch auf die SD-Karte wird nichts geschrieben.

Auch wenn ich nur die SD-Karte testen will, wird im seriellen Monitor angezeigt: "Card failed or not present"

Habe die SD-Karte auf FAT16 formatiert, so wie gewünscht, allerdings komme ich nicht weiter.

Kann mir jemand helfen, weiß jemand vielleicht sogar wie das SD-Shield richtig angeklemmt wird? Bzw im besten Fall: hat jemand einen Schaltplan für einen GPS-Datenlogger?

Über Rückmeldung würde ich mich sehr freuen.

Liebe Grüße

mschmitt:
Habe den Arduino MEGA 2560. Das GPS-Shield und das microSD-Shield habe ich von sparkfun.

Welches microSD-Shield genau?

Hoffentlich keines, was nur zum Atmega328 (z.B. UNO) kompatibel ist!

Welches microSD-Shield genau?

Hoffentlich keines, was nur zum Atmega328 (z.B. UNO) kompatibel ist!

Dieses microSD-Shield habe ich

mschmitt:
SparkFun microSD Shield - DEV-12761 - SparkFun Electronics

Dieses microSD-Shield habe ich

Da hast Du Dir leider eine Tomate gekauft, wenn Du das Shield mit einem MEGA verwenden möchtest. In der Produktbeschreibung steht glasklar drin:
Communication with microSD cards is achieved over an SPI interface. The SCK, DI, and DO pins of the microSD socket are broken out to the ATmega168/328’s standard SPI pins (digital 11-13),

Du hast aber keinen Atmega328, sondern einen Atmega2560, und der hat andere Pin-Nummern für SPI.

Und das von Dir gekaufte Shield hat keinen 6poligen SPI-Pinheader, über den die SPI-Verbindung hergestellt wird.

Mögliche Abhilfen wären:
a) am einfachsten: Einen Arduino UNO mit dem vorhandenen SD-Shield verwenden
b) am teuersten: Ein anderes SD-Shield oder SD-Breakoutmodul kaufen
c) oder wenn Du bei Deinem Board auf die Verwendung der Pins 10, 11, 12 und 13 verzichten kannst, ggf. mit zusätzlichen Hilfsstrippen die tatsächlichen SPI-Pins des MEGA-Boards auf die Pins des Shields not-verkabeln.

Suche Dir was aus!

b) am teuersten: Ein anderes SD-Shield oder SD-Breakoutmodul kaufen

Ist das der passende Breakout?!

Nein.

Hab mir gerade die Shematic angeschaut, es sollte reichen, wenn er auf der Unterseite der Platine, zwischen den beiden parallel verlaufenden Leisten, die Leiterbahnen von D11, D12, D13 durchtrennt. Bitte korregieren, falls ich das falsch seh.

Ansonsten, wieso hast du dich für den Mega entschieden? Ich sehe gerade noch nicht, warum das notwendig sein soll, eine Uno würde es hier auch tun.

mschmitt:
Ist das der passende Breakout?!

https://www.sparkfun.com/products/12009

Nein, das ist ein reiner Pegelwandler.

Einen zusätzlichen Pegelwandler brauchst Du nicht, da Dein SD-Shield schon einen Pegelwandler mit drauf hat.

Wenn Du keine brauchbaren Teile hast, kannst Du versuchen, das Shield mit "Kurzschlussbrücken" neu zu verkabeln, so dass der SPI-Bus auf dem MEGA angesteuert wird. Überbrücke wie folgt mit möglichst eher kurzen als zu langen Kabeln:
pin11->pin51
pin12->pin50
pin13->pin52

Da das eine potentiell gefährliche Verkabelung ist, vorher unbedingt den "BareMinimum" Sketch kompilieren und auf das Board laden, BEVOR Du die Verkabelung herstellst!

Du müßtest dann peinlichst genau darauf achten:

  • die Pins 11, 12, 13, 50, 51, 52 im Sketch für nichts anderes zu verwenden
  • und dann sollten korrekt programmierte SD-Sketche funktionieren

Hallo
auf dem shield sind über dem BordISP Position passende Lötpunkte für eine ISP Buchse (Weiblich) diese muss man auf der unterseite des Shields verkabeln und schon hat man auch beim Mega die SPI Verbindung. Auf dem Shird 11,12,13 raus dann hast du das was du willst mit der Verbindung.
Oberseite mit leerem ISP:
Unbenannt.JPG
Unterseite wo die Buchse Rein “muss”:

Unbenannt2.JPG

Dann ist das wie mit dem Ethernetshields umgesetzt

Danke schon mal für eure Antworten und eure Hilfe!

@jurs

Das mit deiner Pinbelegung hat schonmal funktioniert, habe die SD-Karte jetzt über verschiedene Sketche getestet, sie wird jetzt erkannt und beschrieben.

Wollte das ganze jetzt mit dem GPS-Shield verknüpfen, sodass die Daten, die die GPS-Antenne empfängt, auf die SD-Karte geschrieben und dort gespeichert werden. Dies funktioniert allerdings nicht.

Hab zuvor wie schon oben die Karte formatiert (FAT16) und eine DATA.TXT Datei erstellt, in die geschrieben werden soll (steht so im Sketch inkl. Beschreibung).

Allerdings funktioniert das nicht.

Was mache ich falsch?

mschmitt:
Allerdings funktioniert das nicht.

Was mache ich falsch?

Sorry, ich bin KEIN Hellseher!

Minimum bei so einer Frage wäre, dass Du den Code des verwendeten Sketches vorzeigst.

Eine Textdatei auf der Karte vorab erstellen brauchst Du nicht, das kann die SD-Library schon alleine machen: Wenn keine Datei existiert, dann Datei anlegen und Daten loggen. Wenn eine Datei existiert, dann die Daten am Ende der Datei dranhängen. Das ist gängige Praxis und auch mit der Arduino SD-Library kein Problem.

void setup()
{

pinMode(8, OUTPUT);

Serial.begin(9600);

if (!SD.begin(8)) {
Serial.println(“Card failed, or not present”);
}
}

void getgps(TinyGPS &gps)
{ float latitude, longitude;
int year;
byte month, day, hour, minute, second, hundredths;

gps.f_get_position(&latitude, &longitude);
File dataFile = SD.open(“DATA.TXT”, FILE_WRITE);

if(dataFile)
{
dataFile.print(“Lat:”);
dataFile.print(latitude,5);
dataFile.print(" “);
dataFile.print(“Long:”);
dataFile.print(longitude,5);
dataFile.print(” ");

gps.crack_datetime(&year,&month,&day,&hour,&minute,&second,&hundredths);

hour=hour+1;
if (hour>23)
{
hour=hour-24;
}
if (hour<10)
{
dataFile.print(“0”);
}
dataFile.print(hour, DEC);
dataFile.print(":");
if (minute<10)
{
dataFile.print(“0”);
}
dataFile.print(minute, DEC);
dataFile.print(":");
if (second<10)
{
dataFile.print(“0”);
}

dataFile.print(second, DEC);
dataFile.print(" ");
dataFile.print(gps.f_speed_kmph());
dataFile.println(“km/h”);
dataFile.close();
delay(1000);
}

}

void loop()
{
byte a;
if ( Serial.available() > 0 )
{ a= Serial.read();
if(gps.encode(a))
{
getgps(gps);
}

}
}

Das ist der verwendete Sketch! Hochladen, alles kein Problem, allerdings schreibt bzw speichert er nichts auf der SDcard

mschmitt:
Das ist der verwendete Sketch!

Wenn Du hier im Forum Code postest, sollte der Code stets in Code-Tags eingeschlossen werden. Code-Tags bekommst Du im Forums-Editor über einen Klick auf das </> Symbol in der Editor-Kopfleiste. Den anzuzeigenden Code dann dazwischen einfügen.

Anyway, diese Zeile ist natürlich ein böser Fehler

a= Serial.read();

Die Schnittstelle “Serial” ist Deine serielle Verbindung zwischen PC und Arduino!
Das ist NICHT die Verbindung zwischen Arduino und GPS-Modul!

Falls Du trotzdem das GPS-Modul an “Serial” (Pin-0/1) angeschlossen haben solltest, dann hast Du einen KURZSCHLUSS fabriziert und betreibst nun das GPS-Modul kurzgeschlossen mit der seriellen Schnittstelle zum PC. Das kann nicht funktionieren.

Das GPS-Module muß an eine der drei anderen Seriellen Schnittstellen angeschlossen werden, die beim Mega Serial1, Serial2 und Serial3 heißen. Bzw. eigentlich braucht nur der TX-Pin des GPS-Moduls an den RX-Pin von z.B. Serial1 angeschlossen werden.

Und die GPS-Daten werden dann von Serial1 gelsen, wenn da das Modul dranhängt:

  if ( Serial1.available() > 0 )
  {
     a= Serial1.read();
...

“Serial” kannst Du verwenden, um darüber serielle Debug-Meldungen an den PC zu senden. Also im setup() beide Schnittstellen initialisieren:

void setup() 
{
  pinMode(8, OUTPUT);
  Serial.begin(9600); // Serielle Schnittstelle PC-Arduino
  Serial1.begin(9600); // Serielle Schnittstelle Arduino-GPS
  if (!SD.begin(8)) {
    Serial.println("Card failed, or not present");
    }
}

Und in der loop() die Zeichen vom GPS-Modul auslesen, und zur Kontrolle die unverarbeiteten Rohdaten auch gleich auf Serial wieder ausgeben:

void loop()
{
  byte a;
  if ( Serial1.available() > 0 ) // Zeichen am GPS-Modul verfügbar
  { 
     a= Serial1.read(); // Zeichen am GPS-Modul auslesen
     Serial.write(a); // Zeichen zur Kontrolle an den seriellen Monitor senden
     if(gps.encode(a))
     { 
        getgps(gps);
     }
         
  }
}

(Code für ein GPS-Modul an Serial1).

Gut, dann nochmals vielen Dank!

Ich werde es heute morgen mal so versuchen...

Habe den Code jetzt so verändert wie du gesagt hast…
Wie wird das GPS-Shield denn genau angeklemmt?

Habe es jetzt wie folgt mit dem Arduino verbunden:

  • → +
    GND → GND
    TX → RX1

fehlt noch was? wenn ja: Wie muss ich das im Sketch vermerken?

#include <SPI.h>

#include <SD.h>

#include <TinyGPS.h>

TinyGPS gps;

void getgps(TinyGPS &gps);


void setup() 
{

  pinMode(8, OUTPUT);
  
  Serial.begin(9600);
  Serial1.begin(9600);
  
  if (!SD.begin(8)) {
    Serial.println("Card failed, or not present");
    }
}

void getgps(TinyGPS &gps)
{ float latitude, longitude;
  int year;
  byte month, day, hour, minute, second, hundredths;
  
  gps.f_get_position(&latitude, &longitude);
  File dataFile = SD.open("DATA.TXT", FILE_WRITE);
  
  if(dataFile)
    { 
      dataFile.print("Lat:");
      dataFile.print(latitude,5);
      dataFile.print(" ");
      dataFile.print("Long:");
      dataFile.print(longitude,5);
      dataFile.print(" ");
      
      gps.crack_datetime(&year,&month,&day,&hour,&minute,&second,&hundredths);
      
      hour=hour+1;
      if (hour>23)
        {
          hour=hour-24;
         }
      if (hour<10)
        {
          dataFile.print("0");
         }
       dataFile.print(hour, DEC);
       dataFile.print(":");
       if (minute<10)
       {
         dataFile.print("0");
        }
       dataFile.print(minute, DEC);
       dataFile.print(":");
       if (second<10)
       {
         dataFile.print("0");
        }
        
        dataFile.print(second, DEC);
        dataFile.print(" ");
        dataFile.print(gps.f_speed_kmph());
        dataFile.println("km/h");
        dataFile.close();
        delay(1000);
        }
        
}
  
void loop()
{
  byte a;
  if ( Serial1.available() > 0 )
    { 
       a = Serial1.read();
       Serial.write(a);
       if(gps.encode(a))
       {
        getgps(gps);
        
       }    
    }
}

mschmitt:
Habe es jetzt wie folgt mit dem Arduino verbunden:

  • -> +
    GND -> GND
    TX -> RX1

fehlt noch was?

Welches GPS-Modul hast Du denn?
Ist das ein 5V GPS-Modul?

Welches GPS-Modul hast Du denn?
Ist das ein 5V GPS-Modul?

Sparkfun GPS-Shield EM 406

GPS-Receiver EM 506

mschmitt:
Sparkfun GPS-Shield EM 406
SparkFun GPS Logger Shield - GPS-13750 - SparkFun Electronics

GPS-Receiver EM 506
GPS Receiver - EM-506 (48 Channel) - GPS-12751 - SparkFun Electronics

Auch dieses Shield ist für die Verwendung mit einem Arduino UNO vorgesehen. Wenn Du dieses Shield mit einem MEGA statt einem UNO verwenden möchtest, hast Du bei diesem Shield genau so ins Klo gegriffen wie beim SD-Shield. Wobei es mit einem UNO auch kaum besser wäre, denn der Hersteller des Shields nötigt Dich offenbar standardmäßig zur Verwendung der miesen SoftwareSerial Library an den Pins-2/3, was auch nicht das gelbe vom Ei ist.

Anyway.
Im Prinzip muss das TX-Signal vom GPS-Modul an den RX-Pin von Serial1 gelegt werden, also TX vom GPS an Arduino MEGA Pin-19 (RX1 gehört zu Serial1).

Der EM-506 Chipsatz ist ein ziemlich veralteter GPS-Chipsatz, der nicht die guten Empfangseigenschaften moderner GPS-Chipsätze aufweist. Einen guten GPS-Empfang wirst Du mit diesem Modul vermutlich nur unter freiem Himmel erreichen, während modernere Chipsätze oft auch Indoor-Empfang bekommen, z.B. bis zu 3 Metern Entfernung von einem Fenster, das grobe Richtung Süden zeigt.

Auch wenn das Modul kein gültiges GPS-Signal empfangen kann, sollte es aber über seine serielle Schnittstelle ungültige Datensätze senden. Dann kann Deine TinyGPS-Library zwar nichts damit anfangen, aber wenn Du die empfangenen Daten gleich an den seriellen Monitor weitersendest, solltest Du in einem geschlossenen Raum wenigstens die ungültigen Daten zeilenweise über den seriellen Monitor laufen sehen, wenn alles korrekt angeschlossen ist.

Gut ich versuche es trotzdem mal mit meinen vorhandenen Sachen.

D.h. wenn ich dich jetzt richtig verstanden habe wie folgt anklemmen:

  • SD-Shield wie gestern
  • TX von GPS an Pin 19 vom Arduino
  • Pin 2 an Pin 2
  • Pin 3 an Pin 3
    • an +
  • GND an GND

Dann noch die SoftwareSerial Library einfügen und es sollte laufen?!

Wird das GPS-Modul garnicht direkt an das SD-Modul geklemmt?

mschmitt:
D.h. wenn ich dich jetzt richtig verstanden habe wie folgt anklemmen:

  • SD-Shield wie gestern
  • TX von GPS an Pin 19 vom Arduino
  • Pin 2 an Pin 2
  • Pin 3 an Pin 3
    • an +
  • GND an GND

Was meinst Du mit "anklemmen"?

Du hast doch zwei Shields? Sind die beiden Shields nicht "stapelbar" (stackable)?
Haben beide Shields keine "langen" Pin-Header von Dir eingelötet bekommen, so dass sie stapelbar sind? Dann würdest Du die Shields einfach übereinander stecken wie ein Sandwich.

Dann noch die SoftwareSerial Library einfügen und es sollte laufen?!

Nein, so einen Scheißdreck wie "SoftwareSerial" verwenden allenfalls die Schreiberlinge von Arduino-Beispielprogrammen. Solange Du ein Board mit ausreichend HardwareSerial-Schnittstellen verwendest, verwendest Du natürlich eine davon, z.B. Serial1 vom MEGA2560 Board, wie ich es in den letzten Postings erklärt hatte.

Wird das GPS-Modul garnicht direkt an das SD-Modul geklemmt?

Das GPS-Modul (serielle Datenübertragung) und das SD-Modul (SPI-Datenübertragung) nutzen vollkommen verschiedene Pins. Daher sollte es problemlos sein, beide Shields übereinander zu stapeln. Jedenfalls wenn Du die richtigen Headerleisten angelötet hast, so dass es mechanisch möglich ist. Wobei das GPS-Shield ganz oben drauf gestapelt gehört, denn die GPS-Antenne benötigt "freie Sicht auf die GPS-Satelliten".

Er hier zeigt Dir in seinem Youtube-Video das Stapeln der Shields ab 11:05 min im Video. Zwar hat er mit einem UNO das dafür vorgesehene Board, aber auf einem MEGA funktioniert das Stapeln dieser beiden Shields genauso.

Wo liegt das Problem?

Der Zusammenbau hat soweit funktioniert. Haben jetzt wieder einen Sketch hochgeladen, der im seriellen Monitor folgendes angezeigt hat:

Lat:1000.00000 Long:1000.00000 185:96:72 -1.00km/h
Lat:1000.00000 Long:1000.00000 185:96:72 -1.00km/h
Lat:1000.00000 Long:1000.00000 185:96:72 -1.00km/h
Lat:1000.00000 Long:1000.00000 185:96:72 -1.00km/h
Lat:1000.00000 Long:1000.00000 185:96:72 -1.00km/h
Lat:1000.00000 Long:1000.00000 185:96:72 -1.00km/h
Lat:1000.00000 Long:1000.00000 185:96:72 -1.00km/h
Lat:1000.00000 Long:1000.00000 185:96:72 -1.00km/h
Lat:1000.00000 Long:1000.00000 185:96:72 -1.00km/h
Lat:1000.00000 Long:1000.00000 185:96:72 -1.00km/h
Lat:1000.00000 Long:1000.00000 185:96:72 -1.00km/h
Lat:1000.00000 Long:1000.00000 185:96:72 -1.00km/h
Lat:1000.00000 Long:1000.00000 185:96:72 -1.00km/h
Lat:1000.00000 Long:1000.00000 185:96:72 -1.00km/h
Lat:1000.00000 Long:1000.00000 185:96:72 -1.00km/h
Lat:1000.00000 Long:1000.00000 185:96:72 -1.00km/h
Lat:1000.00000 Long:1000.00000 185:96:72 -1.00km/h
Lat:1000.00000 Long:1000.00000 185:96:72 -1.00km/h
Lat:1000.00000 Long:1000.00000 185:96:72 -1.00km/h
Lat:1000.00000 Long:1000.00000 185:96:72 -1.00km/h
Lat:1000.00000 Long:1000.00000 185:96:72 -1.00km/h

Das haben wir mit folgendem Sketch bekommen:

#include <SPI.h>

#include <SoftwareSerial.h>

#include <SD.h>

#include <TinyGPS.h>

TinyGPS gps;

void getgps(TinyGPS &gps);


void setup() 
{

  pinMode(8, OUTPUT);
  
  Serial.begin(9600);
  Serial.print("Initializing SD card ...");
  
  if (!SD.begin(8)) {
    Serial.println("Card failed, or not present");
    }

  Serial.println("microSD card is ready");
}

void getgps(TinyGPS &gps)
{ float latitude, longitude;
  int year;
  byte month, day, hour, minute, second, hundredths;
  
  gps.f_get_position(&latitude, &longitude);
  File dataFile = SD.open("DATA.TXT", FILE_WRITE);

  Serial.print("Lat: ");
  Serial.print(latitude,5);
  Serial.print(" ");
  Serial.print("Long: ");
  Serial.print(longitude,5);
  Serial.print(" ");
  delay(1000);
  
  if(dataFile)
    { 
      dataFile.print("Lat:");
      dataFile.print(latitude,5);
      dataFile.print(" ");
      dataFile.print("Long:");
      dataFile.print(longitude,5);
      dataFile.print(" ");
      
      gps.crack_datetime(&year,&month,&day,&hour,&minute,&second,&hundredths);
      
      hour=hour+11;
      if (hour>23)
        {
          hour=hour-24;
         }
      if (hour<10)
        {
          dataFile.print("0");
         }
       dataFile.print(hour, DEC);
       dataFile.print(":");
       if (minute<10)
       {
         dataFile.print("0");
        }
       dataFile.print(minute, DEC);
       dataFile.print(":");
       if (second<10)
       {
         dataFile.print("0");
        }
        
        dataFile.print(second, DEC);
        dataFile.print(" ");
        dataFile.print(gps.f_speed_kmph());
        dataFile.println("km/h");
        dataFile.close();
        delay(1000);
        }
        
}
  
void loop()
{
  getgps(gps);
        
}

Das Ergebnis, das oben beschrieben im seriellen Monitor angezeigt wurde, wurde auch auf die microSD-Karte geschrieben und gespeichert.

Jetzt meine Frage: Warum bekomme ich keine richtigen Werte, sondern die Werte sind alle gleich?!

Wo liegt das Problem?