Forum: Mikrocontroller und Digitale Elektronik Arduino Mega 2560 + GPS + auf SD schreiben


von St. P. (m6-crew)


Lesenswert?

Hallo Forum,

ich habe mal eine Frage zu Ports vom Mega 2560.
Ich habe einen GPS Sensor an das Mega 2560 an die Ports 52, 53, 5V, 
Ground angeschlossen. Der GPS-Sensor (NL-552ETTL) funktioniert 
wunderbar.


Nun wollte ich die Daten auf eine SD Karte schreiben, live übertragen.
Dazu benutzte ich ein Catalex 0.9b Micro(TF) SD Adapter.
Laut Anleitung werden die Ports 50-53 und Spannungsversorgung 5V/Ground 
verwendet.

Im Beispielsketch soll PinMode(53, Output);  verwendet werden.

Gibt es eine Alternative wie ich den GPS-Sensor oder die SD- Karte 
anders anschliessen kann?

Danke im Voraus.

von Jürgen S. (jurs)


Lesenswert?

Steffen Priem schrieb:
> Laut Anleitung werden die Ports 50-53 und Spannungsversorgung 5V/Ground
> verwendet.

Die Pins 50 bis 53 sind beim Arduino MEGA der "SPI-Bus".
SD-Karten kannst Du nur am SPI-Bus betreiben.

> Gibt es eine Alternative wie ich den GPS-Sensor oder die SD- Karte
> anders anschliessen kann?

GPS-Module geben ihre Daten meistens über eine serielle Schnittstelle 
aus. Der MEGA2560 hat vier serielle Schnittstellen, wovon die erste an 
Pin-0/1 über USB mit dem PC verbunden werden kann.

Die übrigen drei seriellen Schnittstellen (Serial1, Serial2, Serial3) 
kannst Du daher problemlos zusammen mit GPS-Modulen verwenden. Auf dem 
Arduino MEGA Board sind die Pins für Serial1 mit RX1/TX1 gekennzeichnet, 
Serial2 mit RX2/TX2 und Serial3 mit RX3/TX3.

von st (Gast)


Lesenswert?

Das liegt daran, weil pin50 bis 53 der SPI-Port sind.

SPI slaves haben normalerweie auch noch einen SlaveSelect mit dem 
mehrere am SPI-Bus betrieben werden könnten.

von spess53 (Gast)


Lesenswert?

Hi

>Die Pins 50 bis 53 sind beim Arduino MEGA der "SPI-Bus".
>SD-Karten kannst Du nur am SPI-Bus betreiben.

>Der MEGA2560 hat vier serielle Schnittstellen,

Und jede der vier serielle Schnittstellen kann auch SPI.

MfG Spess

von St. P. (m6-crew)


Lesenswert?

Danke für die Antworten!

Ich habe im Programm die neuen pins gesetzt trotzdem bekomme ich keine 
GPS-Daten mehr.
Das funktioniert nur einwandfrei wenn ich Pin 52,53 nehme.

Was muss ich am Programm ändern damit ich fortlaufend Daten bekomme?

#include "Arduino.h"
#include "SoftwareSerial.h"
#include <LiquidCrystal.h>

SoftwareSerial mySerial = SoftwareSerial(18, 19);

#define powerpin 7
#define BUFFSIZ 64

LiquidCrystal lcd(8, 13, 9, 4, 5, 6, 7);
int backLight=10;


char buffer[BUFFSIZ];        // Stringlänge
char *parseptr;
char buffidx;

int h;

// Daten- GPS
uint8_t hour, minute, second, year, month, date;
uint32_t latitude, longitude;
uint8_t groundspeed, trackangle;
char latdir, longdir;
char status;

void setup()
{
  pinMode(backLight, OUTPUT);
   digitalWrite(backLight, HIGH);  //LCD-Display einschalten
  // Spalten und Zeilen des LCDs einstellen und
  lcd.begin(16, 2);
  // Eine Meldung auf dem LCD ausgeben.
  lcd.clear ();
  digitalWrite(backLight, LOW);  //LCD-Display ausschalten

  if (powerpin) {
    pinMode(powerpin, OUTPUT);
 }

  pinMode(7, OUTPUT);

  // Verbindung mit seriellen Monitor
  Serial.begin(38400);

  // Verbindung mit GPS-Empfänger
  mySerial.begin(38400);

   digitalWrite(powerpin, LOW);


 Serial.println("LABEL, Format, Zeit UTC, Status A=OK, Lat (dd.mm.mmm), 
N/S, Long (dd.mm.mmm), E/W, Speed (Knoten), Curse, Datum,  ");

}

uint32_t parsedecimal(char *str) {
  uint32_t d = 0;

  while (str[0] != 0) {
   if ((str[0] > '9') || (str[0] < '0'))
     return d;
   d *= 10;
   d += str[0] - '0';
   str++;
  }
  return d;

}

void readline(void) {
  char c;

  buffidx = 0;
  while (1) {
      c=mySerial.read();
      if (c == -1)
        continue;
      Serial.print(c);
      if (c == '\n')
        continue;
      if ((buffidx == BUFFSIZ-1))// || (c == '\r'))
      {
        buffer[buffidx] = 0;
        return;
      }
      buffer[buffidx++]= c;
  }
}

void loop()
{

  Serial.print("DATA,");
  uint32_t tmp;

  readline(); //Ausgabe des GPS-Empfängers
  //Serial.print(",");
  Serial.println();

  if (strncmp(buffer, "$GPRMC",6) == 0) {

    // hhmmss time data
    parseptr = buffer+7;
    tmp = parsedecimal(parseptr);
    hour = tmp / 10000;
    minute = (tmp / 100) % 100;
    second = tmp % 100;

    parseptr = strchr(parseptr, ',') + 1;
    status = parseptr[0];
    parseptr += 2;


    // Daten: latitude
    latitude = parsedecimal(parseptr);
    if (latitude != 0) {
      latitude *= 10000;
      parseptr = strchr(parseptr, '.')+1;
      latitude += parsedecimal(parseptr);
  }
    parseptr = strchr(parseptr, ',') + 1;
    // N/S
    if (parseptr[0] != ',') {
      latdir = parseptr[0];
    }

    //Serial.print(latdir);

    // Daten: longitude
    parseptr = strchr(parseptr, ',')+1;
    longitude = parsedecimal(parseptr);
    if (longitude != 0) {
      longitude *= 10000;
      parseptr = strchr(parseptr, '.')+1;
      longitude += parsedecimal(parseptr);
  }
    parseptr = strchr(parseptr, ',')+1;
    // E/W
    if (parseptr[0] != ',') {
      longdir = parseptr[0];

      //Serial.print(longdir);
 }

    // Speed
    parseptr = strchr(parseptr, ',')+1;
    groundspeed = parsedecimal(parseptr);

    // track angle
    parseptr = strchr(parseptr, ',')+1;
    trackangle = parsedecimal(parseptr);


    // date
    parseptr = strchr(parseptr, ',')+1;
    tmp = parsedecimal(parseptr);
    date = tmp / 10000;
    month = (tmp / 100) % 100;
    year = tmp % 100;

delay (250);

}
  //Serial.println(buffer);

}

von Jürgen S. (jurs)


Lesenswert?

Steffen Priem schrieb:
> Ich habe im Programm die neuen pins gesetzt trotzdem bekomme ich keine
> GPS-Daten mehr.
> Das funktioniert nur einwandfrei wenn ich Pin 52,53 nehme.
>
> ...
> SoftwareSerial mySerial = SoftwareSerial(18, 19);

Oh, oh, oh.

Die Pins 18 und 19 SIND eine Hardware-Serial Schnittstelle, und zwar 
"Serial1". An den Pins wird daher natürlich keine serielle Schnittstelle 
per Software emuliert, sondern die vorhandene Serielle Schnittstelle 
wird einfach benutzt.

Du deklarierst daher keine "SoftwareSerial" als "mySerial", sondern 
verwendest stattdessen "Serial1" überall dort, wo bisher "mySerail" 
stand.

Also lösche als erstes die include-Zeile:
1
#include "SoftwareSerial.h"

Dann löschst Du die Deklaration der SoftwareSerial-Schnittstelle:
1
SoftwareSerial mySerial = SoftwareSerial(18, 19);

Und lasse dann "Suchen und Ersetzen" laufen und ersetze alle Vorkommen 
von "mySerial" durch "Serial1" im gesamten Sketch!

Außerdem beachten: Pin-19 ist der RX1-Pin und Pin-18 der TX1-Pin!

von St. P. (m6-crew)


Lesenswert?

Hallo Leute,

ich kann doch die digitalen Ports, z.B. 30-33 als SPI nutzen. Die Frage 
ist, wo ich deklariere, dass die Ports 30-33 aber auch die Ports 50-53 
SPI sind und darüber jeweils ein Gerät läuft.

Ich habe folgendes probiert zu ergänzen(in pins_Arduino.h):



#ifndef Pins_Arduino_h
#define Pins_Arduino_h

#include <avr/pgmspace.h>

#define NUM_DIGITAL_PINS            70
#define NUM_ANALOG_INPUTS           16
#define analogInputToDigitalPin(p)  ((p < 16) ? (p) + 54 : -1)
#define digitalPinHasPWM(p)         (((p) >= 2 && (p) <= 13) || ((p) >= 
44 && (p)<= 46))

static const uint8_t SS   = 53 && 33;
static const uint8_t MOSI = 51 && 31;
static const uint8_t MISO = 50 && 30;
static const uint8_t SCK  = 52 && 32;

static const uint8_t SDA = 20;
static const uint8_t SCL = 21;
static const uint8_t LED_BUILTIN = 13;

static const uint8_t A0 = 54;
static const uint8_t A1 = 55;
static const uint8_t A2 = 56;
static const uint8_t A3 = 57;
static const uint8_t A4 = 58;
static const uint8_t A5 = 59;
static const uint8_t A6 = 60;
static const uint8_t A7 = 61;
static const uint8_t A8 = 62;
static const uint8_t A9 = 63;
static const uint8_t A10 = 64;
static const uint8_t A11 = 65;
static const uint8_t A12 = 66;
static const uint8_t A13 = 67;
static const uint8_t A14 = 68;
static const uint8_t A15 = 69;

// A majority of the pins are NOT PCINTs, SO BE WARNED (i.e. you cannot 
use them as receive pins)
// Only pins available for RECEIVE (TRANSMIT can be on any pin):
// (I've deliberately left out pin mapping to the Hardware USARTs - 
seems senseless to me)
// Pins: 10, 11, 12, 13,  50, 51, 52, 53,  62, 63, 64, 65, 66, 67, 68, 
69

#define digitalPinToPCICR(p)    ( (((p) >= 10) && ((p) <= 13)) || \
                                  (((p) >= 50) && ((p) <= 53)) || \
                                  (((p) >= 30) && ((p) <= 33)) || \
                                  (((p) >= 62) && ((p) <= 69)) ? 
(&PCICR) : ((uint8_t *)0) )//davor die Zeile neu

#define digitalPinToPCICRbit(p) ( (((p) >= 10) && ((p) <= 13)) || (((p) 
>= 50) && ((p) <= 53))|| (((p) >= 30) && ((p) <= 33)) ? 0 : \
                                ( (((p) >= 62) && ((p) <= 69)) ? 2 : \
                                0 ) )//Abschnitt mit 30-33 ist neu

#define digitalPinToPCMSK(p)    ( (((p) >= 10) && ((p) <= 13)) || (((p) 
>= 50) && ((p) <= 53))|| (((p) >= 30) && ((p) <= 33)) ? (&PCMSK0) : \
                                ( (((p) >= 62) && ((p) <= 69)) ? 
(&PCMSK2) : \
                                ((uint8_t *)0) ) )//Abschnitt mit 30-33 
ist neu

#define digitalPinToPCMSKbit(p) ( (((p) >= 10) && ((p) <= 13)) ? ((p) - 
6) : \
                                ( ((p) == 50 || 30) ? 3 : \
                                ( ((p) == 51 || 31) ? 2 : \
                                ( ((p) == 52 || 32) ? 1 : \
                                ( ((p) == 53 || 33) ? 0 : \
                                ( (((p) >= 62) && ((p) <= 69)) ? ((p) - 
62) : \
                                0 ) ) ) ) ) )//davor die Zeilen sind neu

#ifdef ARDUINO_MAIN

von Jürgen S. (jurs)


Lesenswert?

Steffen Priem schrieb:
> ich kann doch die digitalen Ports, z.B. 30-33 als SPI nutzen. Die Frage
> ist, wo ich deklariere, dass die Ports 30-33 aber auch die Ports 50-53
> SPI sind und darüber jeweils ein Gerät läuft.

Hardware-SPI liegt bei den Arduino MEGA Boards auf den Pins 50 bis 53. 
An anderen Pins als diesen gibt es keine Hardware SPI-Unterstützung vom 
Controller.

Lediglich eine "Software SPI" Emulation kannst Du auf anderen Pins 
laufen lassen.

Irgendwie hast Du es damit, Hardware in Software emulieren zu wollen? 
Schon eine zusätzliche serielle Schnittstelle wolltest Du weiter oben in 
Software emulieren, obwohl ein Atmega2560 bereits vier in Hardware 
verfügbare serielle Schnittstellen mitbringt.

Nun möchtest Du eine SPI-Schnittstelle auf anderen Pins per Software 
emulieren, obwohl es eine SPI-Schnittstelle als Hardware auf dem 
Atmega2560 gibt.

Es ist mir alles unbegreiflich, was Du da machen möchtest.

von St. P. (m6-crew)


Lesenswert?

Ich versuche über SPI(Ports50-53) TF Card Adapter 
anzuschließen,funktioniert auch. GPS Modul war vorher an den Pins 52 und 
53. Nun musste ich halt für GPS andere Ports suchen. Die Ports 18 und 19 
können zwar genutzt werden,aber GPS schickt nun Teile von Zeichenketten, 
die völlig unverständlich sind. Die Vermutung liegt darin,dass der 
Speicher so ausgelesen wird,dass alte Daten noch nicht weg sind, jedoch 
bereits mit neuen überschrieben werden. Da ich nicht am Speicher fummeln 
wollte, dachte ich, dass es einfacher wäre, einen zweiten SPI zu 
emulieren.

Ich habe auch etwas vom UART Buffer gelesen, habe aber leider nicht so 
viel Ahnung davon.

Daher bitte um Hilfe

von Jürgen S. (jurs)


Lesenswert?

Steffen Priem schrieb:
> Die Ports 18 und 19
> können zwar genutzt werden,aber GPS schickt nun Teile von Zeichenketten,
> die völlig unverständlich sind. Die Vermutung liegt darin,dass der
> Speicher so ausgelesen wird,dass alte Daten noch nicht weg sind, jedoch
> bereits mit neuen überschrieben werden. Da ich nicht am Speicher fummeln
> wollte, dachte ich, dass es einfacher wäre, einen zweiten SPI zu
> emulieren.

Hast Du die von mir in Posting 
Beitrag "Re: Arduino Mega 2560 + GPS + auf SD schreiben" vorgeschlagenen 
Änderungen gemacht und verwendest Serial1 als HardwareSerial?

Wenn nein, und wenn Du immer noch SoftwareSerial verwendest, dann kann 
der eintrudelnde Datenmatsch auch an SoftwareSerial liegen.

Wenn Du HardwareSerial nutzt und trotzdem Datenmüll reinbekommst, dann 
liest Du die Schnittstelle tatsächlich zu langsam aus. Bei 38400 Baud 
empfängst Du bis zu 3840 Zeichen pro Sekunde. Der serielle 
Eingangspuffer kann 63 Zeichen zwischenpuffern, also mußt Du den 
Eingangspuffer SPÄTESTENS alle 63/3840s = 0,0164s = 16,4 ms auslesen.

Falls Dir der serielle Eingangspuffer bei längerdauernden Aktionen 
überläuft, z.B. weil die Speicheraktion auf SD-Karte mal wieder 60 
Millisekunden dauert, dann mußt Du im Prinzip den kompletten 
Eingangspuffer leerlesen und verwerfen und neu auf einen Zeilenanfang 
synchronisieren.

: Bearbeitet durch User
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.