Daten auf SD-Karte speichern und lesen

Hallo zusammen

Ich versuche in meinem aktuellen Projekt, Daten auf einer SD-Karte zu speichern. Dazu nutze ich ein Arduino UNO mit einem Ethernet Shield 2. Das Speichern der Daten funktioniert soweit. Wenn ich das entsprechende File im bei einem Neustart im setup öffne (und wieder schliesse), kann ich das File später (im callback) nicht mehr öffnen.

Wenn ich das File im setup nicht öffne, kann ich es jedoch im callback beschreiben.

Vielen Dank schon im Voraus für eure Antworten :wink:

//SPI, Ethernet und SD Library
#include <FrameWorkHelper.h>

//Library für MQTT
#include <PubSubClient.h>

//MAC-Adresse wird festgelegt.
byte mac [] = {0xA8, 0x61, 0x0A, 0xAE, 0x51, 0x3F};
//Client und Server IP-Adressen werden festgelegt.
IPAddress server(192, 168, 1, 40);

//Arduino als Client festlegen
EthernetClient ethClient;
PubSubClient client (ethClient);

float x = 0;    //x für grosses Display
float y = 0;    //y für kleines Display

float xOUT = 0;
float yOUT = 0;

#define W5100_PIN 10
#define SDCS_PIN 4

File myFile;
File myFile2;

void setup () {

  pinMode(5, OUTPUT);
  pinMode(6, OUTPUT);

  Serial.begin (9600);                                //Serieller Monitor wird gestartet.

  // Enable SD Card
  pinMode(SDCS_PIN, OUTPUT);
  digitalWrite(SDCS_PIN, LOW);
  pinMode(W5100_PIN, OUTPUT);
  digitalWrite(W5100_PIN, HIGH);

 //SD-Karte starten
 if (!SD.begin(4)) {
    Serial.println("initialization failed!");
  }
  else {
    Serial.println("initialization done.");
  }

  myFile = SD.open("values_x.txt", FILE_READ);
  if (myFile) {
    Serial.print("x = ");
    Serial.println(myFile.read());
    myFile.close();
  }
  myFile2 = SD.open("values_y.txt", FILE_READ);
  if (myFile2) {
    Serial.print("y = ");
    Serial.println(myFile2.read());
    myFile2.close();
  }

  // Enable Ethernet
  digitalWrite(SDCS_PIN, HIGH);
  digitalWrite(W5100_PIN, LOW);

  //MQTT Parameter
  client.setServer(server, 1883);
  client.setCallback (callback);
 
  //Netzwerkverbindung aufbauen
  Ethernet.begin (mac);
  Serial.println (Ethernet.localIP());
  delay (2000);

  //MQTT-Login
  if (client.connect("Arduino3", "xy", "xy")) {
    Serial.println ("Verbindung erfolgreich");
    client.subscribe("topic");
    Serial.println("subscribed to 'topic'");
    Serial.println();
  }

}



//handle incoming messages:
void callback(char* topic, byte* payload, unsigned int length) {
  String messageTemp;

  for (int i = 0; i < length; i++) {
    Serial.print((char)payload[i]);
    messageTemp += (char)payload[i];
  }
  Serial.println();

  //topic überprüfen & Nachrichten verarbeiten
  if (String(topic) == "topic") {

    if (messageTemp == "x+") {
      x += 12.75;
    }
    else if (messageTemp == "x-") {
      x -= 12.75;
    }
    else if (messageTemp == "y+") {
      y += 12.75;
    }
    else if (messageTemp == "y-") {
      y -= 12.75;
    }
  }

  if (x < 0) {                                                   //verhindern, dass x unter 0 ist
    x = 0;
  }
  if (y < 0) {                                                   //verhindern, dass y unter 0 ist
    y = 0;
  }
  if (x > 255) {                                                 //verhindern, dass x über 255 ist
    x = 255;
  }
  if (y > 255) {                                                 //verhindern, dass y über 255 ist
    y = 255;
  }

  int yOUT = round(y);
  Serial.print ("kleines LCD (y)= ");
  Serial.println(yOUT);
  analogWrite(5, yOUT);

  int xOUT = round(x);
  Serial.print("grosses LCD (X)= ");
  Serial.println(xOUT);
  analogWrite(6, xOUT);

  // Enable SD Card
  pinMode(SDCS_PIN, OUTPUT);
  digitalWrite(SDCS_PIN, LOW);
  pinMode(W5100_PIN, OUTPUT);
  digitalWrite(W5100_PIN, HIGH);

  //File löschen, neu anlegen und beschreiben
  SD.remove("values_x.txt");
  myFile = SD.open("values_x.txt", FILE_WRITE);
  if (myFile) {
    Serial.println("writing to 'values_x'");
    myFile.seek(0);
    myFile.print(xOUT);
    myFile.close();
  }

  //File2 löschen, neu anlegen und beschreiben
  SD.remove("values_y.txt");
  myFile2 = SD.open("values_y.txt", FILE_WRITE);
  if (myFile2) {
    Serial.println("writing to 'values_y'");
    myFile2.seek(0);
    myFile2.print(yOUT);
    myFile2.close();
  }

  // Enable Ethernet
  digitalWrite(SDCS_PIN, HIGH);
  digitalWrite(W5100_PIN, LOW);
}


void loop() {
  client.loop();
}

Da ich MQTT nicht nutze, kann ich dein Problem nicht nachvollziehen.

Ich würde die SD-Card-Funktion erst mal testen, ohne MQTT und diese in einer weiteren Funktion aufbauen.

Danach erst die Anbindung an MQTT, dann ist eine Fehlersuche einfacher.

Hallo,

Was mir nur gerade auffällt, warum hast Du den Teil zwei mal drin

  // Enable SD Card
  pinMode(SDCS_PIN, OUTPUT);
  digitalWrite(SDCS_PIN, LOW);
  pinMode(W5100_PIN, OUTPUT);
  digitalWrite(W5100_PIN, HIGH);

vermute der gehört nur einmal ins Setup. Ansonsten sehe ich da auch nur die Möglichkeit das einzeln zu Testen

Heinz

Hallo,

pinMode(SDCS_PIN, OUTPUT);
digitalWrite(SDCS_PIN, LOW);

wenn schon, dann setzt man im setup() den Pin auf HIGH, also inaktiv,
genauso sicher auch beim W5100, das kenne ich nicht.
Um die Steuerung der Select-Signale kümmert sich normalerweise die jeweile Lib, auch die SD-Lib. Deshalb übergibt man ja auch den CS-Pin beim !SD.begin(4).
Warum eigentlich hier die Pinnummer und nicht Dein definiertes Label SDCS_PIN? Wäre lesbarer.

Im MQTT Callback gibt es keinen Grund, da an den Pins rumzufummeln.

ok, Rentner ist es inzwischen auch aufgefallen...

Gerade nochmal kurz über den Sd-Kram geschaut, den Pinmode für das übergeben CS-Pin setzt die Lib offenabr auch alleine, muß an also auch im setup() nicht selber machen.
Sieht man aber auch in den SD-Card-Beispielen der IDE.

Und noch aus Neugier: was macht #include <FrameWorkHelper.h>?

Gruß aus Berlin
Michael

HotSystems:
Da ich MQTT nicht nutze, kann ich dein Problem nicht nachvollziehen.

Ich würde die SD-Card-Funktion erst mal testen, ohne MQTT und diese in einer weiteren Funktion aufbauen.

Danach erst die Anbindung an MQTT, dann ist eine Fehlersuche einfacher.

Die SD-Karte funktioniert. Ich kann Daten speichern und diese auch auslesen, nur eben nicht im callback.

Rentner:
Hallo,

Was mir nur gerade auffällt, warum hast Du den Teil zwei mal drin

  // Enable SD Card

pinMode(SDCS_PIN, OUTPUT);
 digitalWrite(SDCS_PIN, LOW);
 pinMode(W5100_PIN, OUTPUT);
 digitalWrite(W5100_PIN, HIGH);




vermute der gehört nur einmal ins Setup. Ansonsten sehe ich da auch nur die Möglichkeit das einzeln zu Testen 


Heinz

Ich habe von einem Bekannten den Tipp bekommen, dass die Pins für die SD- und die Ethernet-Library umgesetzt werden müssen.
Für Ethernet müsste demnach Pin 10 LOW sein und Pin 4 HIGH, um die SD-Karte zu nutzen umgekehrt. Daher auch:

  // Enable Ethernet
  digitalWrite(SDCS_PIN, HIGH);
  digitalWrite(W5100_PIN, LOW);

amithlon:
Und noch aus Neugier: was macht #include <FrameWorkHelper.h>?

Ist im Grunde einfach die SPI-, die SD- und die Ethernet Library.

dimitreerb:
[3 Antworten in 3 Postings]

Der Thread ist besser zu lesen, wenn Du mehrere Antworten zu einem Posting zusammenfasst, anstatt für jede Antwort ein neues Posting abzusetzen. Zitiere einfach, worauf Du Dich beziehst und/oder schreib „@denda:“ davor.

Gruß

Gregor

gregorss:
Der Thread ist besser zu lesen, wenn Du mehrere Antworten zu einem Posting zusammenfasst, anstatt für jede Antwort ein neues Posting abzusetzen. Zitiere einfach, worauf Du Dich beziehst und/oder schreib „@denda:“ davor.

Gruß

Gregor

@Gregor Danke für den Hinweis!

@alle
Ich habe nun noch ein wenig am Code geschrieben, das Problem bleibt jedoch das gleiche. in den beiden void savevalue frage ich ab, ob das jeweilige File vorhanden ist. Bei der ersten Abfrage ist es vorhanden, bei der zweiten (logischerweise) nicht. D.h. ich kann mit der SD-Karte kommunizieren. Nach diesen beiden Abfragen kann ich das File jedoch noch immer nicht öffnen. :frowning:

/*
    Definitionen der Pins:
    Pin 5 = PWM-Ausgang kleines LCD
    Pin 6 = PWM-Ausgnag grosses LCD
*/

//SPI, Ethernet und SD Library
#include <SPI.h>
#include <Ethernet.h>
#include <SD.h>

//Library für MQTT
#include <PubSubClient.h>

//MAC-Adresse wird festgelegt.
byte mac [] = {0xA8, 0x61, 0x0A, 0xAE, 0x51, 0x3F};
//Client und Server IP-Adressen werden festgelegt.
IPAddress server(192, 168, 1, 40);

//Arduino als Client festlegen
EthernetClient ethClient;
PubSubClient client (ethClient);

float x = 0;    //x für grosses Display
float y = 0;    //y für kleines Display

float xOUT = 0;
float yOUT = 0;

#define W5100_PIN 10
#define SDCS_PIN 4

File myFile;
File myFile2;

void setup () {

  pinMode(5, OUTPUT);
  pinMode(6, OUTPUT);

  Serial.begin (9600);

  if (!SD.begin(4)) {
    Serial.println("initialization failed!");
  }
  else {
    Serial.println("initialization done.");
  }

  myFile = SD.open("values_x.txt", FILE_READ);
  if (myFile) {
    Serial.print("x = ");
    Serial.println(myFile.read());
    myFile.close();
  }
  myFile2 = SD.open("values_y.txt", FILE_READ);
  if (myFile2) {
    Serial.print("y = ");
    Serial.println(myFile2.read());
    myFile2.close();
  }

  //MQTT Parameter
  client.setServer(server, 1883);
  client.setCallback (callback);

  Ethernet.begin (mac);
  Serial.println (Ethernet.localIP());
  delay (2000);

  if (client.connect("Arduino3", "xy", "xy")) {
    Serial.println ("Verbindung erfolgreich");
    client.subscribe("topic");
    Serial.println("subscribed to 'topic'");
    Serial.println();
  }
}



void savevalue_x () {
  if (SD.exists("values_x.txt")) {
    Serial.println("exists1");
  }
  SD.remove("values_x.txt");
  if (SD.exists("values_x.txt")) {
    Serial.println("exists2");
  }
  myFile2 = SD.open("values_x.txt", FILE_WRITE);
  if (myFile2) {
    Serial.println("writing to 'values_x'");
    myFile2.print(xOUT);
    myFile2.close();
  }
}

void savevalue_y () {
  if (SD.exists("values_y.txt")) {
    Serial.println("exists1");
  }
  SD.remove("values_y.txt");
  if (SD.exists("values_y.txt")) {
    Serial.println("exists2");
  }
  myFile2 = SD.open("values_y.txt", FILE_WRITE);
  if (myFile2) {
    Serial.println("writing to 'values_y'");
    myFile2.print(yOUT);
    myFile2.close();
  }
}

//handle incoming messages:
void callback(char* topic, byte * payload, unsigned int length) {
  String messageTemp;

  for (int i = 0; i < length; i++) {
    Serial.print((char)payload[i]);
    messageTemp += (char)payload[i];
  }
  Serial.println();

  //topic überprüfen & Nachrichten verarbeiten
  if (String(topic) == "topic") {

    if (messageTemp == "x+") {
      x += 12.75;
      if (x > 255) {                                                 //verhindern, dass x über 255 ist
        x = 255;
      }
    }
    else if (messageTemp == "x-") {
      x -= 12.75;
      if (x < 0) {                                                   //verhindern, dass x unter 0 ist
        x = 0;
      }
    }
    else if (messageTemp == "y+") {
      y += 12.75;
      if (y > 255) {                                                 //verhindern, dass y über 255 ist
        y = 255;
      }
    }
    else if (messageTemp == "y-") {
      y -= 12.75;
      if (y < 0) {                                                   //verhindern, dass y unter 0 ist
        y = 0;
      }
    }
  }

  savevalue_x();
  savevalue_y();

  int yOUT = round(y);
  Serial.print ("kleines LCD (y)= ");
  Serial.println(yOUT);
  analogWrite(5, yOUT);

  int xOUT = round(x);
  Serial.print("grosses LCD (X)= ");
  Serial.println(xOUT);
  analogWrite(6, xOUT);
}


void loop() {
  client.loop();
}

Danke schon einmal für all Eure bisherigen Antworten!

Gruss
Dimitree

Ich hab mich mal mit dem minimalen auseinandergesetzt und das auf einen noch minimaleren umgebaut, weil ich MQTT nicht habe.

Vorher nur noch der Hinweis, das Du im setup myFile und MyFile2 benutzt; unten aber nur noch MyFile2.
Was da sonst noch passiert, kann ich nicht nachbauen.
Der Sketch als solches funktioniert.

/*
    Definitionen der Pins:
    Pin 5 = PWM-Ausgang kleines LCD
    Pin 6 = PWM-Ausgnag grosses LCD
*/

//SPI, Ethernet und SD Library
#include <SPI.h>
#include <Ethernet.h>
#include <SD.h>

//Library für MQTT
//#include <PubSubClient.h>

//MAC-Adresse wird festgelegt.
byte mac [] = {0xA8, 0x61, 0x0A, 0xAE, 0x51, 0x3F};
//Client und Server IP-Adressen werden festgelegt.
IPAddress server(192, 168, 1, 40);

//Arduino als Client festlegen
EthernetClient ethClient;
//PubSubClient client(ethClient);

float x = 0;    //x für grosses Display
float y = 0;    //y für kleines Display

float xOUT = 0;
float yOUT = 0;

#define W5100_PIN 10
#define SDCS_PIN 4

File myFile;
File myFile2;

void setup()
  {
  pinMode(5, OUTPUT);
  pinMode(6, OUTPUT);
  Serial.begin(115200);
  if (!SD.begin(4))
    {
    Serial.println("initialization failed!");
    }
  else
    {
    Serial.println("initialization done.");
    }
  myFile = SD.open("values_x.txt", FILE_READ);
  if (myFile)
    {
    Serial.print("x = ");
    Serial.println(myFile.read());
    myFile.close();
    }
  myFile2 = SD.open("values_y.txt", FILE_READ);
  if (myFile2)
    {
    Serial.print("y = ");
    Serial.println(myFile2.read());
    myFile2.close();
    }
  /*
    //MQTT Parameter
    client.setServer(server, 1883);
    client.setCallback(callback);
    Ethernet.begin(mac);
    Serial.println(Ethernet.localIP());
    delay(2000);
    if (client.connect("Arduino3", "xy", "xy"))
      {
      Serial.println("Verbindung erfolgreich");
      client.subscribe("topic");
      Serial.println("subscribed to 'topic'");
      Serial.println();
      }
  */
  randomSeed(analogRead(0));
  }



void savevalue_x()
  {
  if (SD.exists("values_x.txt"))
    {
    Serial.println("exists1");
    }
  SD.remove("values_x.txt");
  if (SD.exists("values_x.txt"))
    {
    Serial.println("exists2");
    }
  myFile2 = SD.open("values_x.txt", FILE_WRITE);
  if (myFile2)
    {
    Serial.print("writing to 'values_x'");
    Serial.println(xOUT);
    myFile2.print(xOUT);
    myFile2.close();
    }
  }

void savevalue_y()
  {
  if (SD.exists("values_y.txt"))
    {
    Serial.println("exists1");
    }
  SD.remove("values_y.txt");
  if (SD.exists("values_y.txt"))
    {
    Serial.println("exists2");
    }
  myFile2 = SD.open("values_y.txt", FILE_WRITE);
  if (myFile2)
    {
    Serial.print("writing to 'values_y'");
    Serial.println(yOUT);
    myFile2.print(yOUT);
    myFile2.close();
    }
  }

void loop()
  {
  static int i = 0;
  xOUT = random(1, 126);
  yOUT = random(127, 254);
  savevalue_x();
  savevalue_y();
  i++;
  if (i > 10) while (1); // Hier bleibt alles stehen, Karte kann entfernt und mit Kartenleser ausgelesen werden
                              // Danach Karte wieder rein und seriellen Monitor neu starten - Neue Werte in den Dateien
  }

Wenn aber an irgendeiner anderen Stelle in Deinem Code die dateien behandelt und ein file.close() fehlt, geht die ganze Geschichte den Bach runter.

Kannst Du vollständig ausschliessen, das die Datei(en) an anderer Stelle im Code angesprochen werden?

my_xy_projekt:
Ich hab mich mal mit dem minimalen auseinandergesetzt und das auf einen noch minimaleren umgebaut, weil ich MQTT nicht habe.

Vorher nur noch der Hinweis, das Du im setup myFile und MyFile2 benutzt; unten aber nur noch MyFile2.
Was da sonst noch passiert, kann ich nicht nachbauen.
Der Sketch als solches funktioniert.

/*

Definitionen der Pins:
    Pin 5 = PWM-Ausgang kleines LCD
    Pin 6 = PWM-Ausgnag grosses LCD
*/

//SPI, Ethernet und SD Library
#include <SPI.h>
#include <Ethernet.h>
#include <SD.h>

//Library für MQTT
//#include <PubSubClient.h>

//MAC-Adresse wird festgelegt.
byte mac [] = {0xA8, 0x61, 0x0A, 0xAE, 0x51, 0x3F};
//Client und Server IP-Adressen werden festgelegt.
IPAddress server(192, 168, 1, 40);

//Arduino als Client festlegen
EthernetClient ethClient;
//PubSubClient client(ethClient);

float x = 0;    //x für grosses Display
float y = 0;    //y für kleines Display

float xOUT = 0;
float yOUT = 0;

#define W5100_PIN 10
#define SDCS_PIN 4

File myFile;
File myFile2;

void setup()
  {
  pinMode(5, OUTPUT);
  pinMode(6, OUTPUT);
  Serial.begin(115200);
  if (!SD.begin(4))
    {
    Serial.println("initialization failed!");
    }
  else
    {
    Serial.println("initialization done.");
    }
  myFile = SD.open("values_x.txt", FILE_READ);
  if (myFile)
    {
    Serial.print("x = ");
    Serial.println(myFile.read());
    myFile.close();
    }
  myFile2 = SD.open("values_y.txt", FILE_READ);
  if (myFile2)
    {
    Serial.print("y = ");
    Serial.println(myFile2.read());
    myFile2.close();
    }
  /*
    //MQTT Parameter
    client.setServer(server, 1883);
    client.setCallback(callback);
    Ethernet.begin(mac);
    Serial.println(Ethernet.localIP());
    delay(2000);
    if (client.connect("Arduino3", "xy", "xy"))
      {
      Serial.println("Verbindung erfolgreich");
      client.subscribe("topic");
      Serial.println("subscribed to 'topic'");
      Serial.println();
      }
  */
  randomSeed(analogRead(0));
  }

void savevalue_x()
  {
  if (SD.exists("values_x.txt"))
    {
    Serial.println("exists1");
    }
  SD.remove("values_x.txt");
  if (SD.exists("values_x.txt"))
    {
    Serial.println("exists2");
    }
  myFile2 = SD.open("values_x.txt", FILE_WRITE);
  if (myFile2)
    {
    Serial.print("writing to 'values_x'");
    Serial.println(xOUT);
    myFile2.print(xOUT);
    myFile2.close();
    }
  }

void savevalue_y()
  {
  if (SD.exists("values_y.txt"))
    {
    Serial.println("exists1");
    }
  SD.remove("values_y.txt");
  if (SD.exists("values_y.txt"))
    {
    Serial.println("exists2");
    }
  myFile2 = SD.open("values_y.txt", FILE_WRITE);
  if (myFile2)
    {
    Serial.print("writing to 'values_y'");
    Serial.println(yOUT);
    myFile2.print(yOUT);
    myFile2.close();
    }
  }

void loop()
  {
  static int i = 0;
  xOUT = random(1, 126);
  yOUT = random(127, 254);
  savevalue_x();
  savevalue_y();
  i++;
  if (i > 10) while (1); // Hier bleibt alles stehen, Karte kann entfernt und mit Kartenleser ausgelesen werden
                              // Danach Karte wieder rein und seriellen Monitor neu starten - Neue Werte in den Dateien
  }




Wenn aber an irgendeiner anderen Stelle in Deinem Code die dateien behandelt und ein file.close() fehlt, geht die ganze Geschichte den Bach runter.

Kannst Du vollständig ausschliessen, das die Datei(en) an anderer Stelle im Code angesprochen werden?

Vielen Dank für deine Antwort.

Wenn ich die Funktionen, um die Werte abzuspeichern, im loop abrufe, dann werden die Werte ja sehr oft auf die SD-Karte geschrieben, was für diese ja nicht unbedingt gut ist. Daher rufe ich die Funktionen im callback auf, dass die Werte nur bei Änderungen geschrieben werden.

Hallo,

dann setze eben im callback() ein globales Flag, frage das im loop() ab, schreibe die Daten und setze das Flag zurück.

Gruß aus Berlin
Michael