SD Shield Datenspeicherung Fehler nach 6-7 Stunden

Hey,
Ich bin neu hier und hoffe dass ich alle Regeln zum erstellen eines Posts eingehalten habe.
Ich bin derzeit dabei Windgeschwindigkeit und Temperatur zu messen und die Messwerte zusammen mit der zugehörigen Zeit mit Hilfe von einem SD-Shield auf eine SD Karte zu speichern.
Soweit ist alles das Standard Datalogger Projekt.
Ich habe den ganzen Aufbau zwei mal genau identisch, dabei misst der eine Arduino alle 15 min und der andere jede Minute.
Ich verwende einen Arduino UNO.
Als Bauteile verwende ich ein Schalenkreuzanemometer mit Reed-Switch:

Und zum messen der Temperatur einen DS18B20.
Leider habe ich für das SD Shield keinen Link.
Die Messwerte stimmen und werden auch zuverlässig gemessen bzw. in den ersten paar Stunden auch zuverlässig auf die SD Karte gespeichert.
Der Aufbau sieht folgendermaßen aus:


Der Code:

#include <SPI.h>
#include <SD.h>
#include <Wire.h>
#include "RTClib.h"
#include <OneWire.h>
#include <DallasTemperature.h>

//Variablen zur RTC:
RTC_DS1307 rtc;
char daysOfTheWeek[7][12] = {"Sonntag", "Montag", "Dienstag", "Mittwoch", "Donnerstag", "Freitag", "Samstag"};

//Variablen fuer die Pins:
const int pinSDKarte = 10;
const int pinWindmessung = 2;
const int pinTemperaturmessung = 4;

//Variablen fuer die Messungsdauer/-haeufigkeit:
const unsigned long zeitintervallMessung = 10000;
const unsigned long haeufigkeitMessung = 50000; //15 min: 890000; 1 min: 50000
const String logDatei = "/Daten.csv";

//Temperatursensor Variablen:
OneWire oneWire(pinTemperaturmessung);
DallasTemperature temperaturSensor(&oneWire);

//veraendert werdende Variablen:
volatile int rotations = 0;
float windgeschwindigkeit = 0;
float temperatur = 0;

void setup() {
  //Ueberpruefen ob SD Karte einsatzbereit
  if (!SD.begin(pinSDKarte)) {
    return;
  }
  //Ueberpruefen ob schon eine LogDatei vorhanden ist, sonst erstellen und Kopfzeile schreiben
  if (!(SD.exists(logDatei))) {
    File dateiMessungen = SD.open(logDatei, FILE_WRITE);
    if (dateiMessungen) {
      dateiMessungen.println("Zeitstempel; Windgeschwindigkeit in m/s; Temperatur in Grad C");
      dateiMessungen.close();
    }
  }

  //Ueberpruefen ob Real-Time-Clock vorhanden
  if (!rtc.begin()) {
    return;
  }
  //Ueberpruefen ob Real-Time-Clock einsatzbereit
  if (!rtc.isrunning()) {
    return;
  }
  temperaturSensor.begin();
  pinMode(pinWindmessung, INPUT);
  attachInterrupt(digitalPinToInterrupt(2), windmessung, FALLING);
}

void loop() {
  rotations = 0;
  delay(zeitintervallMessung);
  windgeschwindigkeit = berechnungWindgeschwindigkeit(rotations, zeitintervallMessung);
  temperatur = messungTemperatur();
  messwerteSpeichern(windgeschwindigkeit, temperatur);
  delay(haeufigkeitMessung);
}

//Liefert die Temperatur zurueck
float messungTemperatur() {
  temperaturSensor.requestTemperatures();
  return temperaturSensor.getTempCByIndex(0);
}

//Liefert die Windgeschwindigkeit in m/s zurueck
float berechnungWindgeschwindigkeit(int impulse, int zeitintervall) {
  float impulseProSekunde = impulse / (zeitintervall / 1000);
  if (impulseProSekunde > 0) {
    return (impulseProSekunde + 2) / 3;
  } else {
    return impulseProSekunde;
  }
}

//Schreibt die Messwerte auf die SD-Karte
void messwerteSpeichern(float windgeschwindigkeit, float temperatur) {
  String content = aktuelleZeit() + "; " + windgeschwindigkeit + "; " + temperatur;
  File dateiMessungen = SD.open(logDatei, FILE_WRITE);
  if (dateiMessungen) {
    dateiMessungen.println(content);
    dateiMessungen.close();
  }
}

//Liefert die aktuelle Zeit zurueck im Format: Tag, DD.MM.YYYY HH:MM:SS
String aktuelleZeit() {
  DateTime now = rtc.now();
  String aktuelleZeit = String(daysOfTheWeek[now.dayOfTheWeek()]) + ", " + (String(now.day())) + "." + now.month();
  aktuelleZeit += String(".") + now.year() + " " + now.hour() + ":" + now.minute() + ":" + now.second();
  return aktuelleZeit;
}

//Wird ausgefuehrt von attachInterrupt
void windmessung() {
  rotations++;
}

Soweit so gut. Jetzt habe ich aber folgendes Problem:
Wenn ich das ganze Messen lasse misst der Arduino mit den 15 min Messintervallen zuverlässig und schreibt alles auf die SD Karte. Die maximal ausprobierte Zeit waren dabei 96h mit ca 350 Datensätzen auf der SD Karte. Keine Probleme.

Die Probleme gibt es erst bei der 1 minütigen Messung. Hier schreibt der Arduino auch die richtigen Messwerte auf die SD Karte, aber nur ca 6-7h lang. Nach den 6-7h ist nix mehr auf der SD Karte.
Diese 6-7 Stunden sind relativ konstant. Ich habe jetzt ca. 10 mal gemessen und der 1 min Intervall hat immer zwischen 6 und 7 Stunden aufgehört auf die SD Karte zu schreiben. Anfangs hatte es mit dem gleichen Code schon 1-2 mal funktioniert über 24 Stunden hinweg. Aber seid dem nie wieder.

Habt ihr irgendeine Idee woran das liegen könnte?
Ich bin am verzweifeln, langsam fällt mir nix mehr ein.
Danke schonmal für die Hilfe.

LG Markus

Da ich als neuer Nutzer leider nur ein Bild in den Beitrag nehmen konnte hier noch der Aufbau als Bild:

Ich habe deinen Sketch jetzt nur mal schnell überflogen aber was mir auffällt, bzw ich nicht verstehe sind deine beiden delay in der loop.

delay(zeitintervallMessung);
delay(haeufigkeitMessung);

Ein delay blockiert deinen gesammten Ablauf und zwei delay direkt hintereinander machen eh keinen Sinn.
Schau dir mal das Beispiel "blinkwithoutdelay" an um einen Intervall erstellen ohne den Code zu blockieren.

Der 1. Delay wartet 10 sekunden in denen der Interrupt eine Variable hochzählt. Also im Prinzip mess ich in diesen 10 sekunden die Impulse vom Reed-Switch.
Der 2. Delay wartet bis zur nächstesn Messung. also 50000 Millisekunden im Falle der Msssung jede Minute und 890000 Millisekunden im Falle von alle 15 minuten Messen.

EDIT: Ich habe mir das Beispiel durchgelesen, aber wenn ich das richtig verstanden habe braucht man das um Code während dem delay auszuführen, aber ich brauche ja währenddessen nur den interrupt und der wird ja trotzdem ausgeführt. Oder hab ich da was falsch verstanden?

Hallo,
nehme dir ein bißchen Zeit und forsche im WWW nach der Verwendung und Problemen bei der Verwendung des Datentyps String im ARDUINO Biotop.

ich glaube auch deine String-Objekte Änderungen sind böse. Anhängen an Strings ohne String.reserve ist ganz böse.

Auch brauchst du eigentlich gar keinen Buffer, schreibe einfach jede Variable mit print in deine SD-Karte.

ungeprüft:

void messwerteSpeichern(float windgeschwindigkeit, float temperatur) {
  File dateiMessungen = SD.open(logDatei, FILE_WRITE);
  if (dateiMessungen) {
    dateiMessungen.print(daysOfTheWeek[now.dayOfTheWeek()]);
	dateiMessungen.print(", ");
	dateiMessungen.print(now.day());
	//usw
	//
	dateiMessungen.print(windgeschwindigkeit);
	dateiMessungen.print("; ");
	dateiMessungen.print(temperatur);
	dateiMessungen.println();  // Zeile abschließen
    dateiMessungen.close();
  }
}

und das erste String Objekt bekommst imho auch weg

//const String logDatei = "/Daten.csv";
const char logDatei[] = "/Daten.csv";

das ist zwar nicht böse - macht aber den Code kleiner.

Danke! Dann teste ich das mal :smiley:
Ich melde mich dann nochmal.

Diese Schaltung ist falsch. Pin 2 liegt direkt auf Masse. Der Reed-Kontakt kann Schalten soviel er will am Pin 2 wird nichts ankommen.
Pin 2 muß zwischen dem Reedkontakt und dem 10-kOhm Widerstand verbunden werden.

Laut Foto des Aufbaus ist die Verdratung des Reedkontakts aber richtig.

Grüße Uwe

Ja klar, sorry, ich hab mich wohl beim abmalen meiner fritzing-Schaltung vermalt. Selbstverständlich ist Pin 2 zwischen dem Reed-Kontakt und dem 10 kOhm Widerstand.

Gut so.

Na dann mal ne Rechnung:
Jede Minute eine Schreiborperation für 6 Stunden:
6h60write = 360.
Das wäre das unterste Minimum.
7h
60write = 420.
Das wäre das Sichere.

In der Kurzvariante ist bei Dir nach 96h -> 350 write Schluss.
Du kannst also nicht davon ausgehen, das die Kurzvariante tut.
Wenn Du selbst nachrechnest, wird Dir das auffallen:
Jede Stunde 4 write * 96h macht: 384
Da fehlen also schon mal 34.

Schreibe mit jedem write der Werte zusätzlich einen Wert des benutzten Speicher auf die Karte, wenn Du keinen seriellen Monitor benutzen willst.

Ich hab das ganze jetzt 19,5h lang ausprobiert und es ist einwandfrei gelaufen.
Danke!

Mach ich, dann sollte ich ja auch sehen, ob es jetzt nur länger oder ewig läuft.

Brauchste nicht.
Die beiden jeweils neu initialisierten Strings brechen Dir den Hals.

@noiasca hat Dir den Weg gezeigt. Nimm ihn.

Beobachte und berichte.

ich habe momentan einen ähnlichen Sketch mit Ethernet-Shield, mit NTP Abfrage und alle 30 Sekunden einen SD Eintrag laufen aber alles nur mit char arrays und C++ strings. Das lief jetzt zwei Tage. Hab den nur jetzt neu programmieren müssen, weil noch ein Schönheitsfehler drinnen war. Aber eigentlich läuft das stabil meines Erachtens. Das Logfile hat aktuell 230KiB und gut 5000 Zeilen und ich kann das noch online runterladen...

Kann ich toppen.
Schalte zwischen mehreren Files um und schreibe seit gutgehend 2 Jahren....
:slight_smile:
Filename immer Datum und extension je nach Bedarf
Solar (zwei Wärmetauscher), Heizung-Gas, Heizung-Festbrennstoff, WW-Speisung, WW-Entnahme, FBH, HK.
Jeweils mit Uhrzeit (Datum ist Dateiname) Pumpenzustand(an/aus) + temp: Vorlauf + Rücklauf + Durchflussmesser und schalten von Dreiwegeventilen.
Aufnahme von Temp aus dem Speicher (4 Höhen), Gaszähler, Stromzähler nur für die Heizung, auf/zu der FBH-Ventile...

Die Zähler sind nicht ganz EMV-fehlerfrei, das Schreiben auf die Karte aber schon :wink:

(Original ARDUINO MEGA 2560, Original W5100/SD Modul)

Ich wollt nur mal schreiben, das es auch länger und aufwändiger funktioniert ...
Na dann...

Mit String oder char-Arrays? Diese wesentliche Aussage fehlt dabei.

Gruß Tommy

Also ich muss zugeben dass ich seit 6 Jahren einen Datenlogger mit bösen Strings im Betrieb habe der Werte aus 20 S7 Steuerungen über Profinet ausliest und mehrere Logdateien auf SD Karte schreibt . Bisher funktionierte alles ohne Probleme, musste nur einmal den Akku der RTC wechseln.
Aber sauber und schön programmiert ist das auch nicht, kann aber glücklicherweise auch mal funktionieren :sweat_smile:

OT:
Wir sagen ja nicht das das nicht gehen kann, aber viele Anfänger machen es halt falsch, daher rate ich eher davon ab.

Weist du sicher ob dein Code wirklich sauber durchläuft? Dann gratuliere - alles richtig gemacht. Aber es könnte auch sein dass heap mit stack kollidieren - Kaboom - Neustart und weiter gehts. Und für dich siehts aus es läuft weiter, Intervall passt weil du schön mit einem RTC arbeitest und du glaubst es läuft stabil...

https://learn.adafruit.com/memories-of-an-arduino/optimizing-sram

Da hast du völlig Recht! Ich benenne mich ja auch noch als Anfänger, Erfahrung bringen nicht die Jahre sondern die Intensität mit der man sich mit der Materie beschäftigt.

Aus dem Grund logge ich immer die millis() mit um zu sehen ob es zu ungeplanten Neustarts kam.
Aber dank euch lernt man ständig dazu :wink:

Oh, da @noiasca mit char arrays arbeitet hab ich nur seinen Wert toppen wollen - natürlich auch mit char array.
Wobei:
Vorher war es mit Strings, aber eben nicht wie beim TO jedes mal neu angelegt. Da gab es einen String, der nur inhaltlich verändert wurde.
Was sich später als völliger Blödsin erwies. Aber was gelernt :wink: