SD-Karte: Dateiname als Variable funktioniert nicht

Hallo zusammen,

ich habe hier ein kleines Problem beim Schreiben auf eine SD-Karte. Der Beispiel-Sketch funktioniert; daher ist das Problem vermutlich auf einen Programmfehler / Verständnisfehler von von mir zurückzuführen.

Hintergrund:
Bei einem 10A Solar-Laderegler möchte ich täglich eine neue Logdatei auf der SD-Karte erstellen. Der Dateiname soll das Datum beinhalten --> Log_20191207.csv.

Ich verwende das Loggershield Wemos D1 mini in Verbindung mit einem Arduino Nano every welcher nebem dem Logging auch die Display-Ansteuerung, MPPT- und Laderegelung übernimmt.

Zum Fehler:
Das Programm funktioniert wenn ich den Dateinamen händisch eingebe:

File LogFile = SD.open("Log_12341212.csv", FILE_WRITE);

Wenn ich den Dateiname mit snprintf zusammensetze und als Variable übergebe tritt bei der SD.exists-Abfrage der Fehler auf und es wird nichts auf die SD-Karte geschrieben.

Könnte es sein, dass ich ein Fehler bei der Deklaration der Variable dateiName (char dateiName[16]; ) gemacht habe und die SD.open / SD.exists Funktion damit nicht klarkommt?

Hier mein aktueller Quellcode

Main:

/*
  SD card datalogger

  This example shows how to log data from three analog sensors
  to an SD card using the SD library.

  The circuit:
   analog sensors on analog ins 0, 1, and 2
   SD card attached to SPI bus as follows:
 ** MOSI - pin 11
 ** MISO - pin 12
 ** CLK - pin 13
 ** CS - pin 4 (for MKRZero SD: SDCARD_SS_PIN)

  created  24 Nov 2010
  modified 9 Apr 2012
  by Tom Igoe

  This example code is in the public domain.

*/

#include <SPI.h>
#include <SD.h>

#include "RTClib.h"
RTC_DS1307 rtc;
char daysOfTheWeek[7][12] = {"Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"};

const int chipSelect = 4;
File LogFile;
#define CSV_TRENNZEICHEN ";"

int loggingInterval = 300;    //Logginginterval in ms

void setup() {
  // Open serial communications and wait for port to open:
  Serial.begin(115200);
  while (!Serial) {
    ; // wait for serial port to connect. Needed for native USB port only
  }


  Serial.print("Initializing SD card...");

  // see if the card is present and can be initialized:
  if (!SD.begin(chipSelect)) {
    Serial.println("Card failed, or not present");
    // don't do anything more:
    while (1);
  }
  Serial.println("card initialized.");

  if (! rtc.begin()) {
    Serial.println("Keine RTC gefunden");
    //rtc_Fehler = true;
  }

  if (! rtc.isrunning()) {
    Serial.println("RTC is NOT running!");
  }


}

void loop() {
  writeSD(false); //Schreibe Daten nicht sofort -->Logginginterval
}

SD-Karte

//
// =======================================================================================================
// WRITE SD CARD
// =======================================================================================================
//

void writeSD(boolean noDelay) {
  static unsigned long lastLog;
  static byte letzteSekunde = 0;
  static byte SD_SekundenZusatz = 0;

  char dateiName[16];

  byte SD_Tag, SD_Monat, SD_Minute, SD_Stunde, SD_Sekunde;
  int SD_Jahr;

  if (millis() - lastLog >= loggingInterval || noDelay) {
    lastLog = millis();

    DateTime now = rtc.now();

    SD_Tag = now.day();
    SD_Monat = now.month();
    SD_Jahr = now.year();

    SD_Stunde = now.hour();
    SD_Minute = now.minute();
    SD_Sekunde = now.second();


    snprintf(dateiName, 17, "Log_%04d%02d%02d.csv", SD_Jahr, SD_Monat, SD_Tag);
    Serial.print ("Dateiname: ");
    Serial.println (dateiName);

    //Prüfen ob Datei vorhanden ist, wenn nicht wird eine Datei mit "Kopf" erstellt
    if (!SD.exists(dateiName)) {                    //Wenn Datei noch nicht vorhanden ist
      File LogFile = SD.open(dateiName, FILE_WRITE);     //Logfile im CSV-Formaterstellen

      if (LogFile) {

        LogFile.print("Datum");
        LogFile.print(CSV_TRENNZEICHEN);

        LogFile.print("Zeit");
        LogFile.print(CSV_TRENNZEICHEN);

        LogFile.print("Input Voltage");
        LogFile.print(CSV_TRENNZEICHEN);

        LogFile.print("Input Current");
        LogFile.print(CSV_TRENNZEICHEN);

        LogFile.print("Input Power");
        LogFile.print(CSV_TRENNZEICHEN);

        LogFile.print("Battery Voltage");
        LogFile.print(CSV_TRENNZEICHEN);

        LogFile.print("Battery Current");
        LogFile.print(CSV_TRENNZEICHEN);

        LogFile.print("Battery Power");
        LogFile.print(CSV_TRENNZEICHEN);

        LogFile.print("Converter Mode");
        LogFile.print(CSV_TRENNZEICHEN);

        LogFile.print("targetPanelVoltage");
        LogFile.print(CSV_TRENNZEICHEN);

        LogFile.println("DutyCycle");


        LogFile.close();
        //sd_Fehler = false;
      }

      else {
        //sd_Fehler = true;
        Serial.println("SD-Fehler 1 Kopf schreiben");
      }
    }

    LogFile = SD.open(dateiName, FILE_WRITE);
    LogFile.close();

    LogFile = SD.open(dateiName, FILE_WRITE);     //Logfile im CSV-Format


    if (LogFile) {
      //Datum
      LogFile.print(SD_Tag);
      LogFile.print(SD_Monat);
      LogFile.print(SD_Jahr);
      LogFile.print(CSV_TRENNZEICHEN);

      //Zeit

      /*
        Da die RTC 1307 keine Millisekunden liefert wird über einen kleine Workaround geprüft,
        ob in der selben Sekunde mehrere Messwerte angefallen sind. Wenn ja, wird ein Zähler hochgezählt (Variable SD_SekundenZusatz)
      */
      LogFile.print(SD_Stunde);
      LogFile.print(SD_Minute);
      LogFile.print(SD_Sekunde);


      if (SD_Sekunde == letzteSekunde) {
        SD_SekundenZusatz++;
      }
      else
      {
        SD_SekundenZusatz = 0;
        letzteSekunde = SD_Sekunde;
      }

      Serial.println(SD_SekundenZusatz);
      letzteSekunde = SD_Sekunde;
      LogFile.print(CSV_TRENNZEICHEN);

      //El. Werte

      LogFile.print("12");
      LogFile.print(CSV_TRENNZEICHEN);

      LogFile.print("1");
      LogFile.print(CSV_TRENNZEICHEN);

      LogFile.print("12");
      LogFile.print(CSV_TRENNZEICHEN);

      LogFile.print("13.4");
      LogFile.print(CSV_TRENNZEICHEN);

      LogFile.print("2");
      LogFile.print(CSV_TRENNZEICHEN);

      LogFile.print("23");
      LogFile.print(CSV_TRENNZEICHEN);

      LogFile.print("1");
      LogFile.print(CSV_TRENNZEICHEN);

      LogFile.print("targetPanelVoltage");
      LogFile.print(CSV_TRENNZEICHEN);

      LogFile.println("DutyCycle");


      LogFile.close();

      Serial.println("SD geschrieben!!!");

    }
    else {
      //sd_Fehler = true;
      Serial.println("SD-Fehler 2");
    }
  }

Ich bin Dankbar für jede Antwort und jeden Hinweis.
Grüße Ben

char dateiName[16]; kann 15 Nutzzeichen aufnehmen +den Abschluß '\0', du stopfst aber 16+1 rein.

Mach es 17 lang.

Gruß Tommy

Hallo Tommy,

danke für Deinen Hinweis. Diesen Fehler habe ich verbessert.

Im Fehlerbild und in der Debug-Ausgabe hat sich nichts verändert.

12:59:06.335 -> Dateiname: Log_20191207.csv
12:59:06.335 -> SD-Fehler 1 Kopf schreiben
12:59:06.335 -> SD-Fehler 2

Danke und Gruß
Ben

Die Größe sollte man übrigens mit sizeof() übergeben. Nicht als magische Zahl die unabhängig vom eigentlichen Array existiert

Hallo,
ich hab da bisher immer mit Dateinamen 8.3 Zeichen verwendet.

Nachtrg

die standard lib kann nur 8.3

Heinz

Lass Dir doch mal den gebildeten Dateinamen ausgeben. Kann die SD-Lib lange Dateinamen?

Gruß Tommy

Habe gerade noch mal in die Referenz geschaut. "Rentner" hat vollkommen Recht.
Die SD-Lib akzeptiert nur 8.3 Dateinamen.

SD Library
The SD library allows for reading from and writing to SD cards, e.g. on the Arduino Ethernet Shield. It is built on sdfatlib by William Greiman. The library supports FAT16 and FAT32 file systems on standard SD cards and SDHC cards. It uses short 8.3 names for files. The file names passed to the SD library functions can include paths separated by forward-slashes, /, e.g. "directory/filename.txt". Because the working directory is always the root of the SD card, a name refers to the same file whether or not it includes a leading slash (e.g. "/file.txt" is equivalent to "file.txt"). As of version 1.0, the library supports opening multiple files.

Also ist "Log_20191207.csv" eindeutig zu lang und wird nicht verarbeitet.

LG, Rudi

Hatte ich mir auch gleich gedacht. Die Frage ist dann wieso es aber mit direkt Einsetzen angeblich geht

Hallo zusammen,

vielen Dank für eure Hilfe. Da wäre ich so schnell nicht darauf gekommen.

Es lag Tatsächlich an der Länge des Dateinamen.

Serenifly:
Hatte ich mir auch gleich gedacht. Die Frage ist dann wieso es aber mit direkt Einsetzen angeblich geht

Du hast Recht, ich habe Sinnfreierweise nicht den gesamten Dateiname verwendet sondern eine Test.txt erstellen lassen. Meine Angaben waren in dem Punkt etwas "flapsig", bitte entschuldige die hieraus hervorgegangene Verwirrung.

Die Lösung ist den Dateinamen einzukürzen:

snprintf(dateiName, 13, "%04d%02d%02d.csv", SD_Jahr, SD_Monat, SD_Tag);
    Serial.print ("Dateiname: ");
    Serial.println (dateiName);

Ergibt eine Ausgabe von:
14:08:05.225 -> SD geschrieben!!!
14:08:05.525 -> Dateiname: 20191207.csv

Serenifly:
Die Größe sollte man übrigens mit sizeof() übergeben. Nicht als magische Zahl die unabhängig vom eigentlichen Array existiert

Daran mache ich mich jetzt und werde die größe nicht als Festwert übergeben.

Nochmals vielen Dank für die schnelle Hilfe. Ich wünsche euch ein schönes Restwochenende!

Grüße Ben

Die SD-Lib des ESP8266 soll aber ein Wrapper auf die SdFat sein und die dürfte lange Dateinamen kennen.
Es hängt aber auch davon ab, wie die SD formatiert ist.

Der TO sollte es aber sicherheitshalber mal mit L191207.csv probieren.

Gruß Tommy