Zeitschaltuhr pin schaltet nach der zeit nicht mehr aus

Hallo Zusammen, ich habe folgenden Code mir zusammen gebastelt.
Leider komme ich da nicht weiter. das Problem ist das Zeitintervall von 2 min.
Der pin wird zwar geschaltet aber schaltet danach nicht mehr aus.
hat jemand eine Idee?

#include <Wire.h>
#include <NoiascaLiquidCrystal.h>
#include <NoiascaHW/lcd_PCF8574.h>

constexpr byte cols = 20;
constexpr byte rows = 4;
constexpr byte addr = 0x27;
LiquidCrystal_PCF8574 lcd(addr, cols, rows);

const int pin = 2; // Der Pin, den Sie steuern möchten

//#define RELAY_PIN 2
#define INTERVALL_BEGIN 8
#define INTERVALL_END 20
#define DS3231_ADDRESSE 0x68

void setup() {
  Wire.begin();
  lcd.init();
  lcd.clear();
  lcd.backlight(); 
  Serial.begin(9600);
  pinMode(pin, OUTPUT);

}

void loop() {
  zeigeZeit();
  schalteRelaisImIntervall();
  delay(1000);
}

void zeigeZeit() {
  byte sekunde, minute, stunde, wochentag, tag, monat, jahr;
  leseDS3231zeit(&sekunde, &minute, &stunde, &wochentag, &tag, &monat, &jahr);
  lcd.clear();
  lcd.setCursor(0, 0);
  lcd.print("1");
  lcd.setCursor(0, 2);
  if (stunde >= INTERVALL_BEGIN && stunde < INTERVALL_END) {
    lcd.print("Pumpe: EIN");
    digitalWrite(pin, HIGH); // Relais einschalten
  } else {
    lcd.print("Pumpe: AUS");
    digitalWrite(pin, LOW); // Relais ausschalten
  }
  lcd.setCursor(0, 1);
  lcd.print("Uhrzeit: ");
  if (stunde < 10) {
    lcd.print("0");
  }
  lcd.print(stunde, DEC);
  lcd.print(":");
  if (minute < 10) {
    lcd.print("0");
  }
  lcd.print(minute, DEC);
  lcd.print(":");
  if (sekunde < 10) {
    lcd.print("0");
  }
  lcd.print(sekunde, DEC);
}

void leseDS3231zeit(byte *sekunde, byte *minute, byte *stunde, byte *wochentag, byte *tag, byte *monat, byte *jahr) {
  Wire.beginTransmission(0x68);
  Wire.write(0);
  Wire.endTransmission();
  Wire.requestFrom(0x68, 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());
}

void schalteRelaisImIntervall() {
  static unsigned long previousMillis = 0;
  static bool relayOn = false;

  byte stunde, minute;
  leseDS3231zeit(NULL, &minute, &stunde, NULL, NULL, NULL, NULL);
  unsigned long currentMillis = millis();

  if (stunde >= INTERVALL_BEGIN && stunde < INTERVALL_END) {
    if (minute == 0) {
      if (!relayOn) {
        // Relais einschalten, wenn es nicht schon eingeschaltet ist
        digitalWrite(pin, HIGH);
        relayOn = true;
        previousMillis = currentMillis;
      }

      if (currentMillis - previousMillis >= 120000) {
        // Wenn 2 Minuten vergangen sind, schalt das Relais aus
        digitalWrite(pin, LOW);
        relayOn = false;
      }
    }
  } else {
    // Relais außerhalb des Intervalls ausschalten
    digitalWrite(pin, LOW);
    relayOn = false;
  }
}



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

Das ist nach 2 minuten nicht mehr true

Eine Idee.
Bitte beachte, dass ich Dir eine Variable geklaut habe. Das vereinfacht das Ganze

void schalteRelaisImIntervall()
{
  static unsigned long previousMillis = 0;
  byte stunde, minute;
  leseDS3231zeit(NULL, &minute, &stunde, NULL, NULL, NULL, NULL);
  unsigned long currentMillis = millis();
  if (stunde >= INTERVALL_BEGIN && stunde < INTERVALL_END)
  {
    if (digitaRead(pin) == LOW)
    {
      if (minute == 0)
      {
        // Relais einschalten, wenn es nicht schon eingeschaltet ist
        digitalWrite(pin, HIGH);
        previousMillis = currentMillis;
      }
    }
    else if (currentMillis - previousMillis >= 120000)
    {
      // Wenn 2 Minuten vergangen sind, schalt das Relais aus
      digitalWrite(pin, LOW);
    }
  }
  else
  {
    // Relais außerhalb des Intervalls ausschalten
    digitalWrite(pin, LOW);
    relayOn = false;
  }
}

Edit - code getauscht, weil Bedingungen abhängiger gemacht

danke das hat mich schon weiter gebracht.
leider blinkt die led nach der zeit...

#include <Wire.h>
#include <NoiascaLiquidCrystal.h>
#include <NoiascaHW/lcd_PCF8574.h>

constexpr byte cols = 20;
constexpr byte rows = 4;
constexpr byte addr = 0x27;
LiquidCrystal_PCF8574 lcd(addr, cols, rows);

const int pin = 2; // Pin mit LED
bool relayOn = false; 

//#define RELAY_PIN 2
#define INTERVALL_BEGIN 8
#define INTERVALL_END 20
#define DS3231_ADDRESSE 0x68

void setup() {
  Wire.begin();
  lcd.init();
  lcd.clear();
  lcd.backlight(); 
  Serial.begin(9600);
  pinMode(pin, OUTPUT);

}

void loop() {
  zeigeZeit();
  schalteRelaisImIntervall();
  delay(1000);
}

void zeigeZeit() {
  byte sekunde, minute, stunde, wochentag, tag, monat, jahr;
  leseDS3231zeit(&sekunde, &minute, &stunde, &wochentag, &tag, &monat, &jahr);
  lcd.clear();
  lcd.setCursor(0, 0);
  lcd.print("1");
  lcd.setCursor(0, 2);
  if (stunde >= INTERVALL_BEGIN && stunde < INTERVALL_END) {
    lcd.print("Pumpe: EIN");
    digitalWrite(pin, HIGH); // pin einschalten
  } else {
    lcd.print("Pumpe: AUS");
    digitalWrite(pin, LOW); // pin ausschalten
  }
  lcd.setCursor(0, 1);
  lcd.print("Uhrzeit: ");
  if (stunde < 10) {
    lcd.print("0");
  }
  lcd.print(stunde, DEC);
  lcd.print(":");
  if (minute < 10) {
    lcd.print("0");
  }
  lcd.print(minute, DEC);
  lcd.print(":");
  if (sekunde < 10) {
    lcd.print("0");
  }
  lcd.print(sekunde, DEC);
}

void leseDS3231zeit(byte *sekunde, byte *minute, byte *stunde, byte *wochentag, byte *tag, byte *monat, byte *jahr) {
  Wire.beginTransmission(0x68);
  Wire.write(0);
  Wire.endTransmission();
  Wire.requestFrom(0x68, 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());
}

void schalteRelaisImIntervall()
{
  static unsigned long previousMillis = 0;
  byte stunde, minute;
  leseDS3231zeit(NULL, &minute, &stunde, NULL, NULL, NULL, NULL);
  unsigned long currentMillis = millis();
  if (stunde >= INTERVALL_BEGIN && stunde < INTERVALL_END)
  {
    if (digitalRead(pin) == LOW)
    {
      if (minute == 0)
      {
        // Relais einschalten, wenn es nicht schon eingeschaltet ist
        digitalWrite(pin, HIGH);
        previousMillis = currentMillis;
      }
    }
    else if (currentMillis - previousMillis >= 120000)
    {
      // Wenn 2 Minuten vergangen sind, schalt das Relais aus
      digitalWrite(pin, LOW);
    }
  }
  else
  {
    // Relais außerhalb des Intervalls ausschalten
    digitalWrite(pin, LOW);
    relayOn = false;
  }
}



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

beschreibe mal in Text was dein Code machen soll.

Und dann, was er fehlerhaft statt dessen macht.

Tausche mal:

void schalteRelaisImIntervall()
{
  static unsigned long previousMillis = 0;
  static bool onceStart = false;
  byte stunde, minute;
  leseDS3231zeit(NULL, &minute, &stunde, NULL, NULL, NULL, NULL);
  unsigned long currentMillis = millis();
  if (stunde >= INTERVALL_BEGIN && stunde < INTERVALL_END)
  {
    if (digitalRead(pin) == LOW)
    {
      if (minute == 0 && !onceStart)
      {
        // Relais einschalten, wenn es nicht schon eingeschaltet ist
        digitalWrite(pin, HIGH);
        previousMillis = currentMillis;
        onceStart = true;
      }
    }
    else if (currentMillis - previousMillis >= 120000)
    {
      // Wenn 2 Minuten vergangen sind, schalt das Relais aus
      digitalWrite(pin, LOW);
    }
  }
  else
  {
    // Relais außerhalb des Intervalls ausschalten
    digitalWrite(pin, LOW);
    relayOn = false;
    onceStart = false;
  }
}
1 Like

In diesem Code möchte ich in der zeit vom 8:00 bis 20:00, jeweils den Pin 2 für 2 min aktivieren.
Nach denn 2min soll dieser wieder ausgehen.

ich stelle die zeit meines DS3231 dann auf 7:59 und lass ihn dann ablaufen. im Display wird pumpe aus angezeigt. Um 8:00 schaltet der sich die LED an und die pumpe wechselt in pumpe ein.
nach den Zwei min blinkt die LED und die Pumpe wird weiterhin in Pumpe ein angezeigt.
Was ich gerne hätte wäre, das nach diesen 2 min das LED ausgeht und im Display Pumpe aus stehlt.

ich hoffe ich konnte das verständlich rüber bringen

Vielen Dank für eure Hilfe!

das hat leider keine veränderung gebracht

Ach menno!
Du kannst doch den Pin nicht an zwei Stellen beschreiben!
Wie kommst Du denn auf die Idee in der Anzeige den PIN zu steuern, wenn Du das über die Zeit machen willst?

GRRRR!

void zeigeZeit()
{
  byte sekunde, minute, stunde, wochentag, tag, monat, jahr;
  leseDS3231zeit(&sekunde, &minute, &stunde, &wochentag, &tag, &monat, &jahr);
  lcd.clear();
  lcd.setCursor(0, 0);
  lcd.print("1");
  lcd.setCursor(0, 2);
  lcd.print("Pumpe: ");
  lcd.print(digitalRead(pin ? "EIN" : "AUS"));
  lcd.setCursor(0, 1);
  lcd.print("Uhrzeit: ");
  if (stunde < 10)
  {
    lcd.print("0");
  }
  lcd.print(stunde, DEC);
  lcd.print(":");
  if (minute < 10)
  {
    lcd.print("0");
  }
  lcd.print(minute, DEC);
  lcd.print(":");
  if (sekunde < 10)
  {
    lcd.print("0");
  }
  lcd.print(sekunde, DEC);
}

Und dann kannst Du das delay() rausnehmen - das braucht es dann nicht mehr...

1 Like

Wo beschreibe ich denn den pin zweimal?

geht mal zeilenweise deine ursprüngliche Funktion zeigeZeit() durch.
Wie oft kommt darin digitalWrite vor?

du sollst aber nur in schalteRelaisImIntervall() schalten.

1 Like

Ah versehe. ich schalte also zweimal...

Ich hab Dir das oben schon korrigiert -> Musste nur austauschen.
OrigInal:

und

1 Like

ok super! dank euch vielmals!

Den Abschnitt verstehe ich aber nicht. muss der input nicht von pin 2 kommen?

Das ist das eine Kurzschrift.
Alternativ ginge auch:

if (digitalRead(pin) == HIGH)
{
lcd.print("EIN");
}
else
{
lcd.print("AUS");
}

Nein, da muss keien 2 rein, da Du oben der constanten pin ja die 2 zugewiesen hast.
digitalRead funktioniert prinizipell genauso wie digitalWrite.

1 Like

Also der code läuft so super gut.
habe jetzt noch versucht den dahin zu ändern, dass ich den in einem 30 min turnus laufen lassen kann. Ich denke immer, dass die codes die ich zu mir zusammen baue zu komplex sind.
ist das so?

#include <Wire.h>
#include <NoiascaLiquidCrystal.h>
#include <NoiascaHW/lcd_PCF8574.h>

constexpr byte cols = 20;
constexpr byte rows = 4;
constexpr byte addr = 0x27;
LiquidCrystal_PCF8574 lcd(addr, cols, rows);

const int pin = 2; // Pin mit LED
bool relayOn = false; 

#define INTERVALL_BEGIN 8
#define INTERVALL_END 20
#define INTERVALL_MINUTES 30
#define DS3231_ADDRESSE 0x68

void setup() {
  Wire.begin();
  lcd.init();
  lcd.clear();
  lcd.backlight(); 
  Serial.begin(9600);
  pinMode(pin, OUTPUT);

}

void loop() {
  zeigeZeit();
  schalteRelaisImIntervall();
  delay(1000);
}

void zeigeZeit()
{
  byte sekunde, minute, stunde, wochentag, tag, monat, jahr;
  leseDS3231zeit(&sekunde, &minute, &stunde, &wochentag, &tag, &monat, &jahr);
  lcd.clear();
  lcd.setCursor(0, 0);
  lcd.print("Ebbe & Flut");
  lcd.setCursor(0, 2);
  lcd.print("Pumpe: ");
  if (digitalRead(pin) == HIGH){
    lcd.print("EIN");}
  else{
    lcd.print("AUS");}
  lcd.setCursor(0, 1);
  lcd.print("Uhrzeit: ");
  if (stunde < 10)
  {
    lcd.print("0");
  }
  lcd.print(stunde, DEC);
  lcd.print(":");
  if (minute < 10)
  {
    lcd.print("0");
  }
  lcd.print(minute, DEC);
  lcd.print(":");
  if (sekunde < 10)
  {
    lcd.print("0");
  }
  lcd.print(sekunde, DEC);
}

void leseDS3231zeit(byte *sekunde, byte *minute, byte *stunde, byte *wochentag, byte *tag, byte *monat, byte *jahr) {
  Wire.beginTransmission(0x68);
  Wire.write(0);
  Wire.endTransmission();
  Wire.requestFrom(0x68, 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());
}

void schalteRelaisImIntervall()
{
  static unsigned long previousMillis = 0;
  static bool onceStart = false;
  byte stunde, minute;
  leseDS3231zeit(NULL, &minute, &stunde, NULL, NULL, NULL, NULL);
  unsigned long currentMillis = millis();
  
  if (stunde >= INTERVALL_BEGIN && stunde < INTERVALL_END)
  {
    if (digitalRead(pin) == LOW)
    {
      if (minute % INTERVALL_MINUTES == 0 && !onceStart)
      {
        // Relais einschalten, wenn es nicht schon eingeschaltet ist
        digitalWrite(pin, HIGH);
        previousMillis = currentMillis;
        onceStart = true;
      }
    }
    else if (currentMillis - previousMillis >= (INTERVALL_MINUTES * 60 * 1000))
    {
      // Wenn die festgelegte Zeit abgelaufen ist, schalten Sie das Relais aus
      digitalWrite(pin, LOW);
      onceStart = false;
    }
  }
  else
  {
    // Relais außerhalb des Intervalls ausschalten
    digitalWrite(pin, LOW);
    relayOn = false;
    onceStart = false;
  }
}

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

Ich find erstmal nix problematisches.
Hier:

würde ich der 1000 ein UL anfügen um sicherzugehen, das mit unsigned long gerechnet wird.

was meinst du genau? :wink:

Der compiler arbeitet standardmäßig mit int auf der rechten Seite, wenn nix anderes angegeben ist.
Das kann bei einer Berechnung zu einem Überlauf führen.
Wenn Du die Zeile änderst und dem compiler mitteilst, das er da schon in (unsigned)long arbeiten soll, kann Dir das nciht passieren:
(INTERVALL_MINUTES * 60 * 1000UL))

Ah versteh.
Dank dir!!