RTC ds3231 mit SH1106 Oled und SEesor.

Hallo ich beschäftige mich jetzt schon eine weile mit diesem Sketch und komme leider nicht weiter.
Grundsätzlich möchte ich ein Relay um ein bestimmte Uhrzeit anschalten und ausschalten,Allerdings nur wenn der Sensorwert <300 ist
Das funktioniert auch ohne probleme

Ist der Wert > 300 leuchtet ein Neopixel grün und auf dem Display steht Pumpe OFF pixel
Ist der Wert < 300 leuchtet ein Neopixel Rot und auf dem Display steht Pumpe wartet pixel
In dem Fall das der wert < 300 soll das Relay um 17:30:10 Uhr HIGH sein und 21:30:50 Uhr LOW
Bis Hierher funtioniert der code ohne Probleme.

Das Problem liegt bei dem teil wo Das Relay HIGH geschaltet wird,das Display sollte jetzt eigentlich Pumpe ON anzeigen und der pixel sollte gelb leuchten aber es blinkt nur einmal auf und ist denn wieder weg aber das Relay geht erst aus wenn es auch ausgehen soll.

mir ist noch aufgefallen,das wenn der Sensorwert von <300 auf >300 in der Zeit zwischen17:30:10 Uhr und 21:31:50 Uhr,das denn das Relay nicht ausgeht

Kann mir da jemand helfen? ich bin Maler und versuch mich Stück für Stück in diese Problematik einzufinden.

danke schonmal und ich hoffe das problem ist gut erklärt.
Kann ich das irgendwie anders schreiben?

Meinst Du, wir sind Hellseher? Wie sollen wir ohne Deinen Sketch darauf antworten?

Gruß Tommy

#include <Wire.h>
#define RTC_I2C_ADDRESS 0x68 // I2C Adresse des RTC  DS3231
#include <SPI.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SH1106.h>


#define OLED_MOSI   9
#define OLED_CLK   10
#define OLED_DC    11
#define OLED_CS    12
#define OLED_RESET 13
Adafruit_SH1106 display(OLED_MOSI, OLED_CLK, OLED_DC, OLED_RESET, OLED_CS);

#define RTC_I2C_ADDRESS 0x68 // I2C Adresse des RTC  DS3231
#include <Adafruit_NeoPixel.h>


#define PIN 6
#define NUM_LEDS 2

Adafruit_NeoPixel strip = Adafruit_NeoPixel(NUM_LEDS, PIN, NEO_GRBW + NEO_KHZ800);
int Bodenfeuchte = A1;
int sensorWert = 0;
int Einstellen;

int Relay = 2;
/*
  const int anstd = 6;
  const int anmin = 45;
  const int ansek = 6;

  const int ausstd = 6;
  const int ausmin = 6;
  const int aussek = 46;
*/
unsigned long startZeit1 = 0;
unsigned long startZeit2 = 0;
unsigned long startZeit3 = 0;
unsigned long startZeit4 = 0;

const int zeit1 = 1000;
const int zeit2 = 1000;
const int zeit3 = 100;
const int zeit4 = 0;






//Membervariablen
int jahr, monat, tag, stunde, minute, sekunde, wochentag;
int daysInMonth[12] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
String daysInWeek[7] = {"So", "Mo", "Di", "Mi", "Do", "Fr", "Sa"};
String monthInYear[12] = {"Januar", "Februar", "März", "April", "Mai", "Juni", "Juli", "August", "September", "Oktober", "November", "Dezember"};
String outputFormat = "%s, %02d.%s %04d %02d:%02d:%02d Uhr";

void rtcReadTime() {
  Wire.beginTransmission(RTC_I2C_ADDRESS);
  Wire.write(0);
  Wire.endTransmission();
  Wire.requestFrom(RTC_I2C_ADDRESS, 7);
  sekunde    = bcdToDec(Wire.read() & 0x7f);
  minute     = bcdToDec(Wire.read());
  stunde     = bcdToDec(Wire.read() & 0x3f);

  /* wochentag  =*/ bcdToDec(Wire.read());
  tag        = bcdToDec(Wire.read());
  monat      = bcdToDec(Wire.read());
  jahr       = bcdToDec(Wire.read()) + 2000;
}

void rtcWriteTime(int jahr, int monat, int tag, int stunde, int minute, int sekunde) {
  Wire.beginTransmission(RTC_I2C_ADDRESS);
  Wire.write(0);
  Wire.write(decToBcd(sekunde));
  Wire.write(decToBcd(minute));
  Wire.write(decToBcd(stunde));
  Wire.write(decToBcd(0));
  Wire.write(decToBcd(tag));
  Wire.write(decToBcd(monat));
  Wire.write(decToBcd(jahr - 2000));
  Wire.endTransmission();
}

byte calcDayOfWeek(int jahr, byte monat, byte tag) {
  static int t[] = {0, 3, 2, 5, 0, 3, 5, 1, 4, 6, 2, 4};
  jahr -= monat < 3;
  return ((jahr + jahr / 4 - jahr / 100 + jahr / 400 + t[monat - 1] + tag) % 7);
}

byte decToBcd(byte val) {
  return ( (val / 10 * 16) + (val % 10) );
}

byte bcdToDec(byte val) {
  return ( (val / 16 * 10) + (val % 16) );
}

int getIntFromString (char *stringWithInt, byte num) {
  char *tail;
  while (num > 0) {
    num--;

    while ((!isdigit (*stringWithInt)) && (*stringWithInt != 0)) {
      stringWithInt++;
    }
    tail = stringWithInt;

    while ((isdigit(*tail)) && (*tail != 0)) {
      tail++;
    }

    if (num > 0) {
      stringWithInt = tail;
    }
  }
  return (strtol(stringWithInt, &tail, 10));
}

void setup() {
  Wire.begin();
  Serial.begin(57600);
  Serial.println("Mit dem Befehl kann das Datum und die Uhrzeit gesetzt oder veraendert werden.");
  Serial.println("set 05.10.2019 14:54:00");
  display.begin(SH1106_SWITCHCAPVCC);
  pinMode(Relay, OUTPUT);
  digitalWrite(Relay, LOW);
  strip.begin();

}


void printRTCDateTime() {
  {
    long runtime = millis() / 1000;
    display.setTextSize(1);
    display.setTextColor(WHITE);
    display.setCursor(3, 55);

    char linebuf[60];
    int dOW = calcDayOfWeek(jahr, monat, tag);
    String wochentagC = daysInWeek[dOW];
    String monatC = monthInYear[monat];

    String result = "";
    result += wochentagC;
    result += ", ";
    result += tag;
    result += ".";
    result += monatC;
    result += " ";
    result += jahr;
    result += " ";
    display.println(result);
  }
  {
    display.setTextSize(1);
    display.setTextColor(WHITE);
    display.setCursor(40, 1);
    String result = "";

    if (stunde < 10) {
      result += "0";
    }
    result += stunde;
    result += ":";
    if (minute < 10) {
      result += "0";
    }
    result += minute;
    result += ":";
    if (sekunde < 10) {
      result += "0";
    }
    result += sekunde;
    display.println(result);
  }
  display.display();
  display.clearDisplay();
}

void setRTCTime() {

  char linebuf[30];
  byte counter;
  if (Serial.available()&& millis() > startZeit3 + zeit3) {
     startZeit3 = millis();
             
    memset(linebuf, 0, sizeof(linebuf));
    counter = 0;
    while (Serial.available()) {
      linebuf[counter] = Serial.read();
      if (counter < sizeof(linebuf) - 1) counter++;
    }
  }
  if (strstr(linebuf, "set") == linebuf) {
    tag = getIntFromString (linebuf, 1);
    monat = getIntFromString (linebuf, 2);
    jahr = getIntFromString (linebuf, 3);
    stunde = getIntFromString (linebuf, 4);
    minute = getIntFromString (linebuf, 5);
    sekunde = getIntFromString (linebuf, 6);
  } else {
    Serial.println("Befehl unbekannt.");
    return;
  }
  if (!checkDateTime(jahr, monat, tag, stunde, minute, sekunde)) {
    Serial.println(linebuf);
    Serial.println("Fehlerhafte Zeitangabe im 'set' Befehl");
    Serial.println("Beispiel: set 28.08.2013 10:54");
    return;
  }
  rtcWriteTime(jahr, monat, tag, stunde, minute, sekunde);
  Serial.println("Zeit und Datum wurden auf neue Werte gesetzt.");
}


boolean checkDateTime(int jahr, int monat, int tag, int stunde, int minute, int sekunde) {
  boolean result = false;
  if (jahr > 2000) {
    result = true;
  } else {
    return false;
  }
  // Schaltjahr prüfen
  if (jahr % 400 == 0 || (jahr % 100 != 0 && jahr % 4 == 0)) {
    daysInMonth[1] = 29;
  }

  if (monat < 13) {
    if ( tag <= daysInMonth[monat - 1] ) {
      result = true;
    }
  } else {
    return false;
  }


  if (stunde < 24 && minute < 60 && sekunde < 60 && stunde >= 0 && minute >= 0 && sekunde >= 0) {
    result = true;
  } else {
    return false;
  }

  return result;
}

void loop() {


  if (millis() > startZeit1 + zeit1) {
    rtcReadTime();
    printRTCDateTime();
    setRTCTime();
    startZeit1 = millis();
  }

  if (millis() > startZeit2 + zeit2) {
    sensorWert = analogRead(Bodenfeuchte);
    startZeit2 = millis();
  }
  else {

  }

  if (sensorWert < 300) {

    strip.setPixelColor(1, strip.Color(250, 0, 0));
    strip.show();
                                                                  // strip.clear();
    long runtime = millis() / 1000;
    display.setTextSize(1);
    display.setTextColor(WHITE);
    display.setCursor(20, 35);
    display.println("Pumpe wartet");



    if (millis() > startZeit4 + zeit4 && stunde == 17 && minute == 30&& sekunde == 10) {
      digitalWrite(Relay, HIGH);

      strip.setPixelColor(1, strip.Color(250, 250, 0));
      strip.show();

      {
        long runtime = millis();

        display.setTextSize(1);
        display.setTextColor(WHITE);
        display.setCursor(20, 35);
        display.println("Pumpe ON");
      }
      startZeit4 = millis();
    }


    else if  (stunde == 21 && minute == 30 && sekunde == 50) {
      digitalWrite(Relay, LOW);

    }
  }
  else
  {
    strip.setPixelColor(1, strip.Color(0, 250, 0));
    strip.show();
    display.setTextSize(1);
    display.setTextColor(WHITE);
    display.setCursor(20, 35);
    display.println("Pumpe OFF");
  }

  {
    display.setTextSize(1);
    display.setTextColor(WHITE);
    display.setCursor(35, 10);
    display.print("Boden  ");
    display.println(sensorWert);

  }

}

Tommy56:
Meinst Du, wir sind Hellseher? Wie sollen wir ohne Deinen Sketch darauf antworten?

Gruß Tommy

Sorry musste es seperat posten da es zuviele Zeichen. und zwischen den post muss ich 5 min warten

bei dem const int zeit4 = 6000;
sollte eigentlich keine Zeit stehen ich hatte es nur mal probiert ob es denn geht. es sollte solange stehen bis das Relay off geschaltet wird

Hi

Kommentare sind eigentlich kein Luxus - auch würde ich die 'zeitwerte' nicht durchnummerieren.
Momentag schreibst Du wie wild auf dem Display rum und setzt den Pixel, wenn der messwert < 300 ist - und Das in JEDEM Durchgang - unschön.
Deine Zeit-Berechnungen fallen Dir nach 47,x Tagen auf die Füße:

// ****
if (millis() > startZeit1 + zeit1) {
-->
if (millis() - startZeit1 > zeit1) {
// ****

Das ganze HIGH und LOW würde ich mir ebenfalls definieren - dieses Mal sogar wirklich mit define:
#define AN=LOW
#define AUS=!AN

So kannst Du im Sketch AN und AUS schreiben, und man sieht, was das Relais machen soll - egal, wie der Pin dafür wirklich steht.
Beim Wechsel von den chinesischen Relais zu SSRs muß man nämlich z.B. die Anstsuerung 'umdrehen' - die China-Relais sind zumeist Low-Aktiv, die SSRs brauchen aber ein HIGH zum Schalten.
Mit den #define tauscht man in einer Zeile ein LOW gegen ein HIGH und ist fertig.

Dein Problem konnte ich so direkt nicht nachvollziehen, liegt aber auch daran, daß ich den fremden Code erst komplett verstehen muß - so ganz ohne einen Kommentar wird's aber echt müßig.
Denke mir, daß Du Dich in den ganzen IFs verrennst - und einen logischen Fehler in Deinen Gedanken hast.
Du denkst, daß Du die Pumpe ausschalten musst, wenn die Zeit um ist UND der Sensorwert <300 ist - hier würde wohl ein ODER besser greifen - ggf. mit 'umgedrehtem' Sensor.
Da ich auch was von Bodenfeuchte gelesen habe, denke ich, daß die 300 der Feuchtewert des Boden ist - aber auch hier könntest Du meinem Ratespiel ein jähes Ende bereiten und mit Gewissheit füllen.

MfG

PS: const ist schon Mal gut - aber warum INT?
Hast Du negative Pin-Nummern?
Oder Nummern über 255?
Ich hatte Das bisher noch nicht und kam, zumindest dort, locker mit BYTE klar.
Wenn nix Negativ -> unsigned.
Zugegeben: Bei const wohl egal, da der Kompiler Das ausmerzt, aber gewöhne Dir an, einen passenden Datentyp zu benutzen - auch Dir wird der Speicher eines Tages knapp und Da freut man sich über jedes gesparte Byte (... ok, bei Dir ist noch viel zum Sparen vorhanden ... Das sieht in einem durchdachtem Code schon wieder schmaler aus ...)

Der ds3231 Sketch ist so übernommen allerdings hat der Sketch nur die Uhrzeit und Datum angezeigt und den Rest hab ich gemacht, aber das hast ja schon quasi gesehen.

Genau es Handelt sich um ein Feuchtigkeitssensor für den Garten.
Okay und mit dem codetext den du da reingestellt hast sollte mir das denn nicht auf die füße fallen?

das Relay geht auch an und aus.
nur in dem fall das wenn der Sensorwert von <300 auf >300 in der Zeit zwischen17:30:10 Uhr und 21:31:50 Uhr,das denn das Relay nicht ausgeht.

Das mit dem HIGH und LOW werd ich machen

das mit dem thema int kenn ich nicht anders,aber auch das werde ich ändern;)

const byte zeit1 = 1000;

sollte denn so aussehen.

das

Das Glaub ich dir gerne das bei mir noch einiges einzusparen wäre, aber das kann Ich nicht,bin froh das Ich überhaupt soweit gekommen bin, für Viele Hier wäre das wahrscheinlich kein Problem das Sauber und Ordentlich zu schreiben, aber Ich kann mich damit leider manchmal gar nicht so beschäftigen,da die arbeit ein so einnimmt;)
Hab erst vor knapp über einem Jahr gesehen das es sowas gibt und wo ich gesehen hab was man damit alles so machen kann,wurde ich Neugierig und hab immer Stück für Stück versucht. Und da ich keinen Kenne der sich mit sowas beschäftigt, muss ich alleine durchschlagen und wenn ich wirklich nicht weiterkomme denn erst frag ich hier nach.

Hi, nur kurz:

 const byte zeit1 1 = 1000

funktioniert nicht! die Variable vom Typ byte kan einen maximalen Wert von 255 aufnehmen,
Wenn der Wert also höher als 255 ist muss , dann doch ein int oder ein unsigned int her:

 const int zeit1 = 1000

oder, da zeit1 positiv ist, besser:

 const uint16_t zeit1 = 1000

oder auch:

 const unsigned int zeit1 = 1000

LG Stefan

Deltaflyer:
Hi, nur kurz:

 const byte zeit1 1 = 1000

Bei 1 = 1000 dürfte auch der Compiler streiken :wink:

Gruß Tommy

Hi

Andreas87:
Das Glaub ich dir gerne das bei mir noch einiges einzusparen wäre, aber das kann Ich nicht,bin froh das Ich überhaupt soweit gekommen bin, für Viele Hier wäre das wahrscheinlich kein Problem das Sauber und Ordentlich zu schreiben, aber Ich kann mich damit leider manchmal gar nicht so beschäftigen,da die arbeit ein so einnimmt;)
Hab erst vor knapp über einem Jahr gesehen das es sowas gibt und wo ich gesehen hab was man damit alles so machen kann,wurde ich Neugierig und hab immer Stück für Stück versucht. Und da ich keinen Kenne der sich mit sowas beschäftigt, muss ich alleine durchschlagen und wenn ich wirklich nicht weiterkomme denn erst frag ich hier nach.

Das war nicht als Kritik gemeint - da bei Dir der Code noch recht laienhaft ist, MUSS Da einfach mehr Einsparpotential enthalten sein, als bei einem der Cracks hier - zu Denen ich mich aber dennoch nicht zählen würde.
Wenn Du die Zeitabfrage umstellst, läuft millis() zwar auch weiterhin nach 49,x Tagen (nicht 47,x) über, aber auch während des Überlauf funktioniert die Berechnung fehlerfrei.
Den Nachweis hatte hier Mal Wer im Forum mit BYTE (0...255) gebracht - Du darfst Es aber auch einfach glauben: Das funktioniert auch am 50.ten Tag noch - Dein Code bekommt Da aber Bauchschmerzen und macht 'irgend welchen Mist'.

MfG

Das war hier.

Man kann auch testweise die if-Bedingung in dem Testscript mal umstellen und sieht damit, was nicht geht.

Gruß Tommy

Tommy56:
Das war hier.

Man kann auch testweise die if-Bedingung in dem Testscript mal umstellen und sieht damit, was nicht geht.

Gruß Tommy

Sorry aber ich weiß nicht wie?

 void loop() {


  if (millis() - startZeit1 > zeit1) {
    rtcReadTime();
    printRTCDateTime();
    setRTCTime();
    sensorWert = analogRead(Bodenfeuchte);
    startZeit1 = millis();

  }
  Einstellen = map(sensorWert,  1023, 0, 0, 1023 );
  /* if (millis() - startZeit1 > zeit1) {
     sensorWert = analogRead(Bodenfeuchte);
     startZeit1 = millis();
    }
  */

 if ( Einstellen >= 601) {
    strip.setPixelColor(1, strip.Color(250, 0, 0));
    strip.show();
    digitalWrite(Relay, HIGH);
    long runtime = millis();


    display.setTextSize(1);
    display.setTextColor(WHITE);
    display.setCursor(20, 35);
    display.println("Pumpe wartet");

  } else if (Einstellen <= 600 && Einstellen >= 301) {
    strip.setPixelColor(1, strip.Color(0, 0, 250));
    strip.show();
    long runtime = millis() / 1000;

    display.setTextSize(1);
    display.setTextColor(WHITE);
    display.setCursor(20, 35);
    display.println("Pumpe ON");

  } else if (Einstellen <= 300) {
    strip.setPixelColor(1, strip.Color(0, 250, 0));
    strip.show();
    digitalWrite(Relay, LOW);
    long runtime = millis();

    display.setTextSize(1);
    display.setTextColor(WHITE);
    display.setCursor(20, 35);
    display.println("Pumpe OFF");

  }

  
  { display.setTextSize(1);
    display.setTextColor(WHITE);
    display.setCursor(35, 10);
    display.print("Boden  ");
    display.println(Einstellen);
  }
}

Ich hab das Gestern mal anders geschrieben und
so wie der Loop teil ist funktioniert es , aber egal was Ich mache mit der Zeit funktioniert es nicht .

Ich hab noch versucht das Stück Stück mit der zeit aufzubauen aber Ich komm immer auf der selbe Ergebnis wie der Erste Sketch

Andreas87:
Sorry aber ich weiß nicht wie?

Mache in dem verlinkten Beispiel doch mal aus:

if ((unsigned char)(aktuelleMillis - letzteMillis) >= dauer) {

Deine Variante

if (aktuelleMillis > unsigned char(letzteMillis + dauer)) {

Dann siehst Du in der Ausgabe den Unterschied.

Gruß Tommy

ich hab es ausprobiert nur verstehe ich nicht ganz was im Serial Monitor steht.
da steht nicht immer Aktion . manchmal stehen denn auch nur zahlen ist das denn das er nicht läuft?

if (aktuelleMillis -( unsigned char)(letzteMillis + dauer)) {      // tu was

Der scheint denn aber besser zulaufen wenn ich das richtig sehe

if (aktuelleMillis -( unsigned char)(letzteMillis > dauer)) {      // tu was

Genau das soll dieses zeitlich verkürzte Beispiel zeigen, dass die Variante

if (aktuelleMillis -( unsigned char)(letzteMillis > dauer)) {

den Überlauf richtig meistert, die andere nicht.

Gruß Tommy

if (aktuelleMillis -( unsigned char)(letzteMillis > dauer)) {

verstehe ich nicht:

(letzteMillis > dauer) ist entweder true oder false
( unsigned char)(letzteMillis > dauer) ist entweder 1 oder 0

Die if-Bedingung wird also in aller Regel als true ausgewertet.

Auch wenn du die Klammern sinnvoller setzt, sehe ich nicht, was der cast auf ein byte bewirken soll.

Die ganze Diskussion um einen beliebten Anfänger-Fehler, der eventuell mal kurzzeitig auftritt nachdem der Arduino über 49 Tage ohne Reset im Betrieb war, kommt mir übertrieben vor.

Hi

Mir nicht.
Man kann Das natürlich auch, wie die ganzen delay() in den Beispielen, gut heißen - wenn Jemand über das 49-Tage Problem stolpert, wird Er Sich wohl darum kümmern ... wie beim delay(), gell?
Warum die Leute dumm halten?
Man KANN Das verstehen, muß man aber nicht unbedingt, um Es richtig - Überlaufsicher!, zu machen.

Ich sehe jetzt keinen Vorteil darin, die falsche Variante als 'ach egal' hinzustellen, die korrekte Variante ist kein Deut mehr Aufwand, funktioniert aber immer.

MfG

Okay denn Hab ich das millis() aber schonmal verstanden :wink:

Und man muss die Leute nicht Dumm halten weil sonst kommen ja auch immer wieder die selben Fragen und das ist ja auch nicht sinn und zweck des Forum.

Aber wie mach ich das jetzt mit der AN und AUS zeit? der geändert LOOP teil Funktioniert ohne Probleme aber sofern ich anstatt die Sensorwerte,die Zeit eintrage läuft da nichts mehr.

michael_x:
(letzteMillis > dauer) ist entweder true oder false
( unsigned char)(letzteMillis > dauer) ist entweder 1 oder 0

Du hast Recht. Ich habe das einfach ohne groß nachzudenken aus seinem Code abgeleitet.
Ich finde es aber immer wieder gut, dass man auf solche Flüchtigkeiten hingewiesen wird.

Der Cast ist nur bei - notwendig, damit er nicht in int rechnet.

Gruß Tommy