Beim Speicher auf SD karte werden mehrere Zeilen erstellt

Hallo zusammen!
Ich hab folgendes Problem:

Ich betreibe einen Datenlogger und dieser speichert die Werte auf der SD karte, ABER es werden dann fünft Zeilen mit den selben Daten erstellt. Habe schon einiges ausprobiert, aber leider ohne erfolg. Ich hoffe jemand kann mir da weiterhelfen.

#include <OneWire.h>                  // OneWire-Bibliothek einbinden
#include <DallasTemperature.h>        // DS18B20-Bibliothek einbinden
#include <SD.h>
#include <SPI.h>
#include <Wire.h>
#include "RTClib.h"

// Konstanten
const int owPin = 2;                   // Pin für OneWire Bus definieren
const int intervall = 1000;            // Intervall wie oft die Temperatur abgefragt wird (millisekunden)
int SELECTED_CHIP = 10;
int pushButton = 3;


float Messwert;
float Spannung;

// Variablen
unsigned long letzteMillis = 0;       // Speichert die letzte Zeit (millis) der Temperaturabfrage

OneWire oneWire(owPin);               // OneWire Referenz setzen
DallasTemperature sensors(&oneWire);  // DS18B20 initialisieren
RTC_DS1307 rtc;


byte sensor1[8] = {0x28, 0xFF, 0x64, 0x1E, 0x84, 0x08, 0x13, 0x9E};
byte sensor2[8] = {0x28, 0xFF, 0x64, 0x1E, 0x84, 0x01, 0x11, 0x90};
byte sensor3[8] = {0x28, 0xFF, 0x64, 0x1E, 0x84, 0x05, 0x22, 0xF7};
byte sensor4[8] = {0x28, 0xFF, 0x64, 0x1E, 0x84, 0x03, 0x10, 0x5F};
byte sensor5[8] = {0x28, 0xFF, 0x64, 0x1E, 0x84, 0x0F, 0x27, 0x2F};


void setup()
{
  Serial.begin(9600);      // Baudrate für die Ausgabe am Serial Monitor
  Wire.begin();
  rtc.begin();
  sensors.begin();         // DS18B20 starten

  //Anzahl der angeschlossenen Sensoren ausgeben
  Serial.print("Anzahl der Sensoren: ");
  Serial.println(sensors.getDeviceCount());


  if (SD.begin(SELECTED_CHIP)) {
    Serial.println("SD-Karte ist vorhanden");
  } else {
    Serial.println("SD-Karte fehlerhaft oder nicht vorhanden!");

    while (1)

      ; // Warte bis die serielle Schnittstelle verbunden ist. Nur für den nativen USB-Anschluss erforderlich
    if (! rtc.isrunning()) {
      Serial.println("RTC is NOT running!");
      // following line sets the RTC to the date & time this sketch was compiled
      rtc.adjust(DateTime(__DATE__, __TIME__));

      pinMode(pushButton, INPUT);

    }
  }
}


void loop()
{
  DateTime now = rtc.now();


  Serial.print(now.hour(), DEC);
  Serial.print(':');
  Serial.print(now.minute(), DEC);
  Serial.print(' ');


  Serial.print(now.day(), DEC);
  Serial.print('/');
  Serial.print(now.month(), DEC);
  Serial.print('/');
  Serial.print(now.year(), DEC);
  delay(1000);

  Serial.println();

  // Erfasst die aktuelle Zeit für den Abfrageinterval
  unsigned long aktuelleMillis = millis();

  // Löst bei erreichen der Intervalzeit die Temperaturerfassung aus
  if (aktuelleMillis - letzteMillis >= intervall)
  {
    letzteMillis = aktuelleMillis;   // speichert die Zeit der letzten Abfrage
    sensors.requestTemperatures();   // Temperatursensoren auslesen

    // Temperaturen der Sensoren auslesen
    for (int i = 0; i < sensors.getDeviceCount(); i++)
    {
      show_temperature(i + 1, sensors.getTempCByIndex(i));
    }
  }

  Messwert = analogRead(1);                  //Spannungswert am analogen Eingang 1 auslesen
  Spannung = map(Messwert, 0, 1023, 0, 250); //Umwandeln des Sensorwertes mit Hilfe des "map" Befehls. Da der Map-Befehl keine Kommastellen ausgibt, wird hier vorerst mit größeren Zahlen gearbeitet.
  Spannung = Spannung / 10;                  // Das Ergebnis wird nun durch 10 geteilt, um die Anzeige als korrekten Wert mit einer Nachkommastelle ausgeben zu können.
  Serial.print(Spannung, 2);                 //Endgültigen Spannungswert im seriellen Monitor anzeigen. Die Zahl "2" in der Klammer sorgt dafür, dass das Ergebnis mit zwei Nachkommastellen angezeigt wird. Eine "1" würde hier für eine Nachkommastellen sorgen etc.
  Serial.println("V");

  int buttonState = digitalRead(pushButton);
  // print out the state of the button:
  Serial.println(buttonState);

  delay(3000);




}

//Temperatur am Seriellen Monitor ausgeben
void show_temperature(byte num, float temp)
{

  DateTime now = rtc.now();

  Serial.print("Sensor ");
  Serial.print(num);
  Serial.print(": ");
  Serial.print(temp);
  Serial.print(" ");
  Serial.println("C");

  float tempC1 = sensors.getTempC(sensor1);
  float tempC2 = sensors.getTempC(sensor2);
  float tempC3 = sensors.getTempC(sensor3);
  float tempC4 = sensors.getTempC(sensor4);
  float tempC5 = sensors.getTempC(sensor5);




  //Speichervorgang
  File dataFile = SD.open("TEMP.csv", FILE_WRITE);
  if (dataFile) {

    dataFile.print(now.hour(), DEC); dataFile.print(':'); dataFile.print(now.minute(), DEC); dataFile.print(";"); dataFile.print(now.day(), DEC); dataFile.print('.'); dataFile.print(now.month(), DEC); dataFile.print('.'); dataFile.print(now.year(), DEC); dataFile.print(";");

    dataFile.print(tempC1); dataFile.print(";");
    dataFile.print(tempC2); dataFile.print(";");
    dataFile.print(tempC3); dataFile.print(";");
    dataFile.print(tempC4); dataFile.print(";");
    dataFile.print(tempC5); dataFile.print(";"); dataFile.print(Spannung); dataFile.print(";"); dataFile.print(digitalRead(pushButton)); dataFile.print(";");
    dataFile.println();

    dataFile.close();                                    // Datei schließen und speichern
    
    //Fehlermeldung
  } else {
    Serial.println("Fehler beim Speichern der Datei!");
  }
}

Sei froh, das Du nur 5 hast.
Wenn Du Deine ganzen delay() rausnimmst, ist die Karte schnell voll..

Du musst Dir merken, wann Du das letzte Mal geschrieben hast und erst wieder schreiben, wenn die Zeit abgelaufen ist.

Der speichert 1x je Minute

//Temperatur am Seriellen Monitor ausgeben
void show_temperature(byte num, float temp)
{
  static byte lastWrite = 0;
  DateTime now = rtc.now();
  Serial.print("Sensor ");
  Serial.print(num);
  Serial.print(": ");
  Serial.print(temp);
  Serial.print(" ");
  Serial.println("C");
  float tempC1 = sensors.getTempC(sensor1);
  float tempC2 = sensors.getTempC(sensor2);
  float tempC3 = sensors.getTempC(sensor3);
  float tempC4 = sensors.getTempC(sensor4);
  float tempC5 = sensors.getTempC(sensor5);
  //Speichervorgang
  if (lastWrite != now.minute())
  {
    File dataFile = SD.open("TEMP.csv", FILE_WRITE);
    if (dataFile)
    {
      dataFile.print(now.hour(), DEC); dataFile.print(':'); dataFile.print(now.minute(), DEC); dataFile.print(";"); dataFile.print(now.day(), DEC); dataFile.print('.'); dataFile.print(now.month(), DEC); dataFile.print('.'); dataFile.print(now.year(), DEC); dataFile.print(";");
      dataFile.print(tempC1); dataFile.print(";");
      dataFile.print(tempC2); dataFile.print(";");
      dataFile.print(tempC3); dataFile.print(";");
      dataFile.print(tempC4); dataFile.print(";");
      dataFile.print(tempC5); dataFile.print(";"); dataFile.print(Spannung); dataFile.print(";"); dataFile.print(digitalRead(pushButton)); dataFile.print(";");
      dataFile.println();
      dataFile.close();                                    // Datei schließen und speichern
      lastWrite = now.minute();
      //Fehlermeldung
    }
    else
    {
      Serial.println("Fehler beim Speichern der Datei!");
    }
  }
}
1 Like

Du bist Dir schon im Klaren, dass dieser Code nie erreicht wird, oder?

Wieso weisst Du,dass der OP nur einmal pro Minute speichern will?

Was hast Du denn erwartet? Temperaturwerte ändern sind selten innerhalb von Sekunden. Bitte beschreibe genau, was Dein Programm tun sollte.

Habe ich das behauptet?

Nein, nicht direkt, aber Dein Code impliziert es.

Dann ist es ja gut.
Im Übrigen sind da ganz andere Böcke drin als seine NichtRTC-Routine.
Über die hätte ich mir eher Gedanken gemacht und Kritik geäussert.

Danke für eure Beiträge zum Sketch. Die eigentlich Funktion ist, dass diese kleine "Messstation" fünf Temperaturen und eine Spannung misst, sowie einen Kontakt, ob er geschlossen ist oder nicht. Also sollte ich statt delay() eine while() Schleife verwenden? Was ist mit der RTC routine gemeint ? Habt Ihr noch Anmerkungen zu dem Sketch?

Viele Dank im Voraus für Eure Antworten! :slight_smile:

Der Code macht das, was du programmiert hast. In der loop() hast du eine for()-Schleife, die von 0 bis zur Anzahl der Temperatursensoren läuft. Hier rufst du jeweils show_temperature auf.
Gehen wir in diese Funktion, sammelst du hier - also bei jedem Funktionsaufruf! - wieder alle Temperaturwerte der Sensoren ein. Bei 5 Sensoren kommt man daher auf 5 überwiegend identische Zeilen, die gespeichert werden. Theoretisch könnte sich ja ein Sensorwert während der Laufzeit ändern.

1 Like

Moin zusammen,
hab nun versucht Eure Tips umzusetzen, aber leider ohne Erfolg.
Was genau sollte geändert werden. Würde gerne den Sketch umschreiben, weil der wirkt in der Funktionalität sehr klobig.

Danke für Eure Antworten und Anregungen im Voraus!

Was der Code machen soll:
Im setup erstmal kurz stehen bleiben, das man die Meldungen sieht :wink:
die Uhrzeit wird ständig geholt
Die Spannung wird geholt
dann wird die Temperaur geholt

  • in der Funktion wird nach dem holen(!) eine neue Messung angestossen
  • dann wird einmal ausgegeben

saveTemperature schreibt einmal pro Minute auf die SD.
genau das, was in den SensorArray drinsteht.

#include <OneWire.h>                  // OneWire-Bibliothek einbinden
#include <DallasTemperature.h>        // DS18B20-Bibliothek einbinden
#include <SD.h>
#include <SPI.h>
#include <Wire.h>
#include "RTClib.h"

// Konstanten
const int owPin = 2;                   // Pin für OneWire Bus definieren
const int intervall = 1000;            // Intervall wie oft die Temperatur abgefragt wird (millisekunden)
int SELECTED_CHIP = 10;
int pushButton = 3;

float Messwert;
float Spannung;

// Variablen
unsigned long letzteMillis = 0;       // Speichert die letzte Zeit (millis) der Temperaturabfrage

OneWire oneWire(owPin);               // OneWire Referenz setzen
DallasTemperature sensors(&oneWire);  // DS18B20 initialisieren
RTC_DS1307 rtc;
DateTime now;

const byte sensorAnzahl = 5;
/*
  //   Das benutzt Du nicht!
  byte sensor[sensorAnzahl][8] =
  {
  {0x28, 0xFF, 0x64, 0x1E, 0x84, 0x08, 0x13, 0x9E},
  {0x28, 0xFF, 0x64, 0x1E, 0x84, 0x01, 0x11, 0x90},
  {0x28, 0xFF, 0x64, 0x1E, 0x84, 0x05, 0x22, 0xF7},
  {0x28, 0xFF, 0x64, 0x1E, 0x84, 0x03, 0x10, 0x5F},
  {0x28, 0xFF, 0x64, 0x1E, 0x84, 0x0F, 0x27, 0x2F}
  };
*/
float tempC[sensorAnzahl];

void setup()
{
  delay(500);
  Serial.begin(9600);      // Baudrate für die Ausgabe am Serial Monitor
  Wire.begin();
  rtc.begin();
  sensors.begin();         // DS18B20 starten
  //Anzahl der angeschlossenen Sensoren ausgeben
  Serial.print(F("Anzahl der Sensoren: "));
  if (sensors.getDeviceCount() != sensorAnzahl)
  {
    Serial.print(sensorAnzahl);
    Serial.print(F(" erwartet! - nur: "));
  }
  Serial.print(sensors.getDeviceCount());
  Serial.println(F(" gefunden"));
  if (SD.begin(SELECTED_CHIP))
  {
    Serial.println("SD-Karte ist vorhanden");
  }
  else
  {
    Serial.println(F("SD-Karte fehlerhaft oder nicht vorhanden!"));
    while (1);
  }
  if (!rtc.isrunning())
  {
    Serial.println("RTC is NOT running!");
    // following line sets the RTC to the date & time this sketch was compiled
    rtc.adjust(DateTime(__DATE__, __TIME__));
    pinMode(pushButton, INPUT);
  }
  showTime();
  delay(3000);
}


void loop()
{
  now = rtc.now();
  getSpannung();
  getTemperatur();
  saveTemperature();
 // int buttonState = digitalRead(pushButton);
 // Serial.println(buttonState);
}

void getSpannung()
{
  Messwert = analogRead(1);                  //Spannungswert am analogen Eingang 1 auslesen
  Spannung = map(Messwert, 0, 1023, 0, 250); //Umwandeln des Sensorwertes mit Hilfe des "map" Befehls. Da der Map-Befehl keine Kommastellen ausgibt, wird hier vorerst mit größeren Zahlen gearbeitet.
  Spannung = Spannung / 10;                  // Das Ergebnis wird nun durch 10 geteilt, um die Anzeige als korrekten Wert mit einer Nachkommastelle ausgeben zu können.
  Serial.print(Spannung, 2);                 //Endgültigen Spannungswert im seriellen Monitor anzeigen. Die Zahl "2" in der Klammer sorgt dafür, dass das Ergebnis mit zwei Nachkommastellen angezeigt wird. Eine "1" würde hier für eine Nachkommastellen sorgen etc.
  Serial.println("V");
}

void getTemperatur()
{
  const unsigned long intervall = 1000;
  static unsigned long letzteMillis = 0;
  if (millis() - letzteMillis >= intervall)
  {
    for (byte b = 0; b < sensors.getDeviceCount(); b++)
    {
      tempC[b] = sensors.getTempCByIndex(b);
    }
    letzteMillis = millis(); // speichert die Zeit der letzten Abfrage
    sensors.requestTemperatures();
    showTemperature();
  }
}

void showTime()
{
  static byte lastSecond = 61;
  if (lastSecond != now.second())
  {
    lastSecond = now.second();
    Serial.print(now.hour(), DEC);
    Serial.print(':');
    Serial.print(now.minute(), DEC);
    Serial.print(' ');
    Serial.print(now.day(), DEC);
    Serial.print('/');
    Serial.print(now.month(), DEC);
    Serial.print('/');
    Serial.println(now.year(), DEC);
  }
}


void showTemperature()
{
  for (byte b = 0; b < sensorAnzahl; b++)
  {
    Serial.print("Sensor ");
    Serial.print(b);
    Serial.print(": ");
    Serial.print(tempC[b]);
    Serial.print(" ");
    Serial.println("C");
  }
}

void saveTemperature()
{
  byte lastMinute = 61;
  if (lastMinute != now.minute())
  {
    lastMinute = now.minute();
    File dataFile = SD.open("TEMP.csv", FILE_WRITE);
    if (dataFile)
    {
      dataFile.print(now.hour(), DEC); dataFile.print(':'); dataFile.print(now.minute(), DEC);
      dataFile.print(";"); dataFile.print(now.day(), DEC); dataFile.print('.'); dataFile.print(now.month(), DEC);
      dataFile.print('.'); dataFile.print(now.year(), DEC); dataFile.print(";");
      for (byte b = 0; b < sensorAnzahl; b++)
      {
        dataFile.print(tempC[b]); dataFile.print(";");
      }
      dataFile.print(Spannung); dataFile.print(";"); dataFile.print(digitalRead(pushButton)); dataFile.print(";");
      dataFile.println();
      dataFile.close();                                    // Datei schließen und speichern
    }
    else
    {
      Serial.println("Fehler beim Speichern der Datei!");
    }
  }
}
1 Like

Guten Morgen, wow, nun funktioniert es wie es soll! Besten Dank!!! :slight_smile:

Nun setze ich mich mal mit dem Code auseinander, um diesen vollständig zu verstehen.

Das ist nur der von Dir gelieferte ein wenig umgeschrieben, damit es übersichtlicher wird.

Der große Knackpunkt sind die DS-Sensoren.
Du liest die Sensoren nicht anhand der ID , sondern über den Index aus.
Geht ein Sensor dabei verloren, verschieben sich die Einträge.
Ich benutze für meine Sensoren eine selbst erstellte ID.
Diese kann abgefragt und dann dem entsprechendem Sensorwert zugeordet werden.
Geht der Sensor kaputt, wird ein neuer mit der selben ID versehen und getauscht. fertig.
Brauch ich im Code nicht die eindeutige ID des Sensors ändern.

Sieh Dir dazu die Beispiele UserDataDemo und UserWriteBatch unter DallasTemperature an und nen Blick ins Datenblatt kann nicht schaden.
Ansonsten ist nur einn Array für die Sensoren gebaut worden - alles andere blieb wie es war :wink:

1 Like

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.