SD Shield zu viele Files werden erstellt

Hallo Leute !

Ich habe ein Programm, welches nach einem Button Druck eine .csv Datei mit dynamischen Ende erstellen soll. Das tut es auch aber es erstellt beim ersten betätigen gleich 3 gleichzeitig und das darf nicht sein. Wenn ich nach dem einem Druck noch einmal den Button drücke soll es das geöffnete file geschlossen werden. Wird dann der Button nochmals gedrückt soll es wieder ein File erstellen mit einer anderen Nummer hier kommt das Problem von oben wieder .

Wie kann ich das unterbinden das er 3.csv Files gleichzeitig erstellt und nur eines erstellt ? Ich habe es mit delay probiert aber keinen Erfolg gehabt.

Mein Code:

#include <SPI.h>
#include <SD.h>
// Base name must be six characters or less for short file names.
#define FILE_BASE_NAME "Data"

const int buttonPin = 4;    // the number of the pushbutton pin
const int ledPin = 5;      // the number of the LED pin

// Variables will change:
int ledState = HIGH;         // the current state of the output pin
int buttonState;             // the current reading from the input pin
int lastButtonState = LOW;   // the previous reading from the input pin
long lastDebounceTime = 0;  // the last time the output pin was toggled
long debounceDelay = 50;    // the debounce time; increase if the output flickers

const uint8_t CS_PIN = 53;

File file;

const uint8_t BASE_NAME_SIZE = sizeof(FILE_BASE_NAME) - 1;
char fileName[] = FILE_BASE_NAME "00.csv";


void setup() {
  Serial.begin(9600);
  pinMode(buttonPin, INPUT_PULLUP);
  pinMode(ledPin, OUTPUT);
  digitalWrite(ledPin, ledState);

    if (!SD.begin(CS_PIN)) {
    Serial.println(F("begin failed"));
    return;
  }
}

void loop() {
  
  int reading = digitalRead(buttonPin);
  if (reading != lastButtonState) {
    // reset the debouncing timer
    lastDebounceTime = millis();
  }

  if ((millis() - lastDebounceTime) > debounceDelay) {
    if (reading != buttonState) {
      buttonState = reading;
      if (buttonState == HIGH) {
        ledState = !ledState;
      }
    }
  }
  digitalWrite(ledPin, ledState);
  lastButtonState = reading;

  

  if((digitalRead(4) == LOW)&&(digitalRead(ledPin) == LOW)){ 
    Serial.println("ERFÜLLT");
      while (SD.exists(fileName)) {
        if (fileName[BASE_NAME_SIZE + 1] != '9') {
        fileName[BASE_NAME_SIZE + 1]++;
    }   else if (fileName[BASE_NAME_SIZE] != '9') {
        fileName[BASE_NAME_SIZE + 1] = '0';
        fileName[BASE_NAME_SIZE]++;
        } else {
        Serial.println(F("Can't create file name"));
        return;
      }
    }
    file = SD.open(fileName, FILE_WRITE);
    if (!file) {
      Serial.println(F("open failed"));
    return;
    }
    Serial.print(F("opened: "));
     Serial.println(fileName);

    if((digitalRead(4) == HIGH)&&(digitalRead(ledPin) == HIGH)){
      
    file.close();
    }
  } 
  
}

Und wie sieht der Inhalt der 3 Csv-Dateien danach aus?

Leer da ich noch nichts reinschreibe ich will nur mal das er nur eine Datei erstellt bevor ich etwas hineinschreibe =)

Wie kann ich das unterbinden das er 3.csv Files gleichzeitig erstellt

Kommt entprellen und "auch bei längerem Tastendruck nur 1 mal Datei erstellen" durcheinander ?

Ich habe Schwierigkeiten mit deinem debounce Code beim "trocken" nachvollziehen...

Ja es kommt auch so durcheinander ich weiß echt nicht was ich da machen kann

Hallo,

laut meinem Verständnis haut die gesamte "Struktur" der Dateinamenserstellung und Zuweisung überhaut nicht hin. Guck dir nochmal die Beispiele der SD Lib an. Wie lauten denn die Dateinamen auf der Karte?

Das sollte theoretisch schon gehen. ASCII Zeichen kann man auch direkt inkrementieren.
Ich kann mich aber nicht entscheiden ob es intelligent oder unnötig kompliziert ist. Jedoch braucht es weniger Speicher als Alternativen.

Hallo,

mit dem Code wird aus Data00.csv dann Data01.csv und Data02.csv ?
Kann ich mir nicht so ganz vorstellen. Man muß das doch extra behandeln und immer neu zusammensetzen.
Deswegen hätte ich gern gewußt wie die jetzigen erzeugten Dateinamen lauten.

#define FILE_BASE_NAME "Data"
...

const uint8_t BASE_NAME_SIZE = sizeof(FILE_BASE_NAME) - 1;
char fileName[] = FILE_BASE_NAME "00.csv";
...

      while (SD.exists(fileName)) {
        if (fileName[BASE_NAME_SIZE + 1] != '9') {
        fileName[BASE_NAME_SIZE + 1]++;
    }   else if (fileName[BASE_NAME_SIZE] != '9') {
        fileName[BASE_NAME_SIZE + 1] = '0';
        fileName[BASE_NAME_SIZE]++;
    ...

Wieso muss man das? ein char ist in C nicht wirklich was besonders. Die kann man wie Integer addieren und subtrahieren. Und wenn er bei "09" ist geht es mit "10" weiter.

Hallo,

als ich mir den Code angeschauten hatte, dachte, kann gar nicht funktionieren wie gewünscht. Dabei kam ich mit der Schreibweise nicht zurecht. Hab das mal Abschnittsweise probiert, wie das überhaupt zählen soll.

hiermit werden die Einerstellen erhöht

fileName[BASE_NAME_SIZE + 1]++;
Serial.println(fileName);

und hiermit die Zehnerstellen

fileName[BASE_NAME_SIZE]++;
Serial.println(fileName);

genauso mit dem hier, wäre nie im Leben darauf gekommen das diese Schreibeweise 2 Strings zusammensetzen kann

char fileName[] = FILE_BASE_NAME "00.csv";

ich sehe ja das es funktioniert nur ist mir dennoch leider unklar wie das funktioniert. Entschuldigung dafür.
Ich hätte das getrennt behandelt und am Ende immer mit snprintf zusammengesetzt usw.

Das ist ein ganz normales C/C++ Feature:

Serial.println("Test1" "Test2");

Wo du das unbedingt brauchst ist bei sowas:

lcd.print("\xDF" "C");

Gradzeichen bei LCDs, wobei DF vielleicht nicht korrekt ist. Sonst versucht der Compiler das als \xDFC zu parsen was nicht in einen int passt.

Oder wenn du HTML Code in einen String packen willst:

char html[] =
"Zeile 1"
"Zeile 2"
"Zeile 3";

Wobei hier C++11 und Raw String Literals heutzutage wahrscheinlich besser sind

Hallo,

ist ja lustig. Genau beim °C Zeichen habe ich das getrennt behandelt. Ich dachte der Befehl kann nur mit einem Paar " " umgehen. :slight_smile:

lcd.print("\xDF");
lcd.print("C");

ja so ist das eben beim programmieren.

Edit:
Nur woher weis der was der inkrementieren soll, da nur von der Stringlänge die Rede ist?
Das die 00 von 00.csv erhöht werden soll erschließt sich mir nicht.

fileName[BASE_NAME_SIZE]++;
Serial.println(fileName);

Das hat rein ist nichts mit der Funktion zu tun auf die man das anwendet. Sondern mit dem Compiler. Der fügt beim Parsen des Codes einfach mehrere String Literale hintereinander zusammen. Die Funktion sieht dann nur ein einzelnes Literal.

Was inkrementiert werden soll wird hier berechnet:

const uint8_t BASE_NAME_SIZE = sizeof(FILE_BASE_NAME) - 1;

FILE_BASE_NAME ist "data". Hat also eine Größe von 5. Der Index der herauskommt ist 4. Und dem steht die erste Ziffer.

... aber das eigentliche Problem ist doch, dass mit 1 entprelltem Tastendruck 3 Dateien erzeugt werden ...

wo ist da der Wurm im Code ?

Hallo,

wenn ich mir das länger mit deiner Erklärung so anschaue, umso besser zünden mit der Zeit die Synapsen ... :slight_smile:
Danke.

Hier vielleicht:

if((digitalRead(4) == LOW)&&(digitalRead(ledPin) == LOW)){

Er entprellt oben und schaltet damit die LED. Aber bei der SD Sache wird einfach digitalRead() gemacht

michael_x:
... aber das eigentliche Problem ist doch, dass mit 1 entprelltem Tastendruck 3 Dateien erzeugt werden ...

wo ist da der Wurm im Code ?

weil das mit dem ledPin nicht hinhaut. Die Verrieglung mit dem ledPin bzw. dessen Status haut nicht hin, würde ich sagen. Das wird auch mit der Entprellung zusammenhängen.

Hallo,

ich habe das mal zum testen zusammengekürzt, auch weil ich derzeit kein SD Modul rumliegen habe. Die Reaktion auf den Tastendruck soll so sein wie es ist? Denn der Code schaltet um auf jeden Tastendruck hin. Behält also jederzeit seinen alten Status. Das wäre ein "Change Modus". Bei jedem 2. Tastendruck und ich halte diesen jeden 2., rasselt die serielle Ausgabe ohne Ende durch.

Und dann denke ich das ein paar von deinen returns ein paar zu viel sind im Code. Gerade im setup. Wo will er hin springen.

Vorschlag.

while Schleife ändern. Die Tasterabfrage würde ich so umbauen, dass ich nur auf ein entprelltes LOW hin eine Aktion ausführe und dann wieder auf ein entprelltes LOW warte für die nächste Aktion. Denn die Aktion soll sich sicherlich selbst beenden wenn sie fertig ist und nicht auf einen "leeren" Tastendruck warten.

// Base name must be six characters or less for short file names.
#define FILE_BASE_NAME "Data"

const int buttonPin = 4;    // the number of the pushbutton pin
const int ledPin = 13;      // the number of the LED pin

// Variables will change:
int ledState = HIGH;         // the current state of the output pin
int buttonState;             // the current reading from the input pin
int lastButtonState = LOW;   // the previous reading from the input pin
long lastDebounceTime = 0;  // the last time the output pin was toggled
long debounceDelay = 50;    // the debounce time; increase if the output flickers

const uint8_t CS_PIN = 53;

const uint8_t BASE_NAME_SIZE = sizeof(FILE_BASE_NAME) - 1;
char fileName[] = FILE_BASE_NAME "00.csv";


void setup() {
  Serial.begin(9600);
  pinMode(buttonPin, INPUT_PULLUP);
  pinMode(ledPin, OUTPUT);
  digitalWrite(ledPin, ledState);

}

void loop() {
 
  int reading = digitalRead(buttonPin);
  if (reading != lastButtonState) {
    // reset the debouncing timer
    lastDebounceTime = millis();
  }

  if ((millis() - lastDebounceTime) > debounceDelay) {
    if (reading != buttonState) {
      buttonState = reading;
      if (buttonState == HIGH) {
        ledState = !ledState;
      }
    }
  }
  digitalWrite(ledPin, ledState);
  lastButtonState = reading;

 

  if((digitalRead(4) == LOW)&&(digitalRead(ledPin) == LOW)){
    Serial.println("geht los");
    
    if((digitalRead(4) == HIGH)&&(digitalRead(ledPin) == HIGH)){
      Serial.println("fert'sch");
    }
  }
 
}

Hallo nochmal,

möchte zwar keinen halb toten Thread ständig aufwärmen, aber vielleicht hilft dir ein anderer Ansatz.

Auszug aus meinem Datalogger Projekt.
Ich erzeuge an Hand vom Datum einen Dateinamen und schaue ständig vorm schreiben ob eine Datei mit diesem Namen schon existiert. Wenn nicht, wird eine Datei mit dem Namen angelegt und eine Kopfzeile darin erstellt. Danach werden nur noch Daten reingeschrieben für diesen Tag

void refresh_SD_Dateiname ()
{
  static char old_SD_Dateiname[13];
  snprintf_P(_SD_Dateiname,13, PSTR("%04d%02d%02d.csv"), _Jahr, _Monat, _Tag);  // spart etwas RAM
  if (strcmp(old_SD_Dateiname, _SD_Dateiname) != 0)  {  // wenn der char array Vergleich "ungleich" ergibt, dann
    strcpy(old_SD_Dateiname, _SD_Dateiname);            // setze old_SD... mit _SD_Dateiname gleich    
    if (!SD.exists(_SD_Dateiname))  {   // prüfe dessen Existens, wenn Datei nicht vorhanden, erstelle sie und ...
      myFile = SD.open(_SD_Dateiname, FILE_WRITE);   
	  // erzeuge Kopfzeile in der neuen Datei
		myFile.print(F("Datum ; Zeit ; ms_over ; ")); 
		myFile.write(181);  // ASCII Sonderzeichen µ
		//                C runtime ; 1.DS1820 ; 2.DS1820; 3.DS1820 ; RTC-Temp ; MCP3428-1 ; MCP3428-2 ; MCP3428-4 ; Arduino Ub
		myFile.println(F("C runtime ; 1.DS1820 ; 2.DS1820; 3.DS1820 ; RTC-Temp ; USB_Ub ; KFZ_Bat ; USB_Akku ; Arduino Ub")); 
		myFile.print(F(";  ;  ;  ; ")); 
		myFile.write(176); myFile.print(F("C ; ")); myFile.write(176); myFile.print(F("C ; ")); myFile.write(176); myFile.print(F("C ; ")); myFile.write(176); myFile.print(F("C ; "));  // ASCII Sonderzeichen °
		myFile.println(F("V ; V ; V ; V")); 
      myFile.close();     
    }  
  }
}