Newbie sucht Hilfe... DS3231 RTC mit MEZ/MESZ Umschaltung gesucht

Loschder: Ich benötige für meine 4er-Relaiskarte ein Duplizieren auf weitere Kanäle

Also Output 13 soll auch auf 12 und 11, und auf Output 10 negiert.

Kann ich das in ECHTZEIT also wirklich identisch gleichzeitig über den Arduino laufen lassen oder sind da gewisse Milli´s Zeitversatz dazwischen?

Wenn Du zum Umschalten den Befehl "digitalWrite()" verwendest, dann dauert die Ausührung des Befehls jedesmal zwischen 4 und 6 Mikrosekunden (also "Millionstel Sekunden"), je nach verwendetem Board und Pin.

Jedes mechanische Relais schaltet um ein vielfaches langsamer.

Loschder: Output 11 und 10 fungieren als Kreuzschaltung für +24VDC die Verpolung zu kreuzen - daher könnte ein leichter Zeitversatz evtl. problematisch sein...(Ansteuerung von 2 Linearantriebe für Fenster öffnen/schließen).

Wenn Du problematische Schaltstellungen softwaretechnisch vermeiden möchtest, dann müßtest Du über problematische Schaltzustände drüberschalten, indem Du bei Änderungen des Schaltzustands jeweils: - vom aktuellen Schaltzustand in einen sicheren Schaltzustand schaltest - mindestens zweimal die Relais-Schaltzeit wartest - und dann erst den neuen Schaltzustand freischaltest

Für den Anwendungsfall "DC-Motor mit zwei Relais in verschiedene Laufrichtungen oder aus schalten" existieren jedenfalls Schaltungen, die jede Kurzschlussgefahr vollkommen ausschalten und das Risiko darauf beschränken, dass ein Motor bei gleichzeitiger Relaisansteuerung aber unterschiedlich langen Relaisschaltzeiten während der Zeitdifferenz in die falsche Laufrichtung angesteuert wird.

Wenn Du eine Schaltung hast, bei der auch nur theoretisch ein Kurzschluss zwischen 24V und GND geschaltet sein kann, wenn ein Relais eine falsche Schaltposition hat, hast Du Deine Relais falsch geschaltet.

Hasde Recht... bin´s nochmal durchgegangenb und

in dem Zeitbereich vernachlässigbar - zudem macht es dem Linearantrieb auch rein gar nix wenn auf beiden Leitungen zurzzeitig 24VDC bzw GND drauf sind.

MfG und nochmals Danke

Ooooh sunny day ...

jurs: Allerdings ist auch das natürlich noch ausbaufähig. Zum Beispiel müssen jetzt die Schaltzeiten im Beispielprogramm immer noch fest in das Programm reingeschrieben, kompiliert und hochgeladen werden. Man könnte nun natürlich noch auf die Idee kommen, den seriellen Befehlsinterpreter weiter auszubauen, so dass man nicht nur die RTC-Zeit per seriellem Befehl anders einstellen kann, sondern auch die gewünschten Schaltzeiten über serielle Kommandos änderbar machen.

Hab mir das auch schon überlegt, man müßte die Werte im EEProm speichern, sonst sind die nach einem Reset weg. Fertige RTC Module haben einen kleinen EEProm drauf. Der Uhren RAM ist zwar gepuffert, nach Batteriewechsel ist das dann auch weg. Überlegung wäre, Werte übertragen, dann landen die im µC RAM und erst nach einem weiteren save Befehl werden sie dauerhaft im EEprom ablegt. Damit umgeht man auch das Problem/Gefahr permanent das EEprom zu beschreiben. Was meinst Du? Meister der Strukturen. :)

Noch eine Frage zu Struktur. Wird bei neuer Zuweisung zu einer vorhandenen Struktur neuer RAM belegt oder muß man das als Verlinkung betrachten?

Doc_Arduino: Hab mir das auch schon überlegt, man müßte die Werte im EEProm speichern, sonst sind die nach einem Reset weg. Fertige RTC Module haben einen kleinen EEProm drauf.

Jeder Arduino-Controller hat ein eingebautes EEPROM drauf.

Doc_Arduino: Der Uhren RAM ist zwar gepuffert, nach Batteriewechsel ist das dann auch weg. Überlegung wäre, Werte übertragen, dann landen die im µC RAM und erst nach einem weiteren save Befehl werden sie dauerhaft im EEprom ablegt. Damit umgeht man auch das Problem/Gefahr permanent das EEprom zu beschreiben.

Siehst Du da wirklich eine relevante Gefahr für das EEPROM? Das Arduino EEPROM wird vom Hersteller für 100000 Schreibzyklen garantiert. Minimum. Wenn jemand eine volle Stunde dran sitzt und für dieselbe Schaltzeit ständig neue Befehle über Serial eintippt, zum Verstellen der Schaltzeit - was schafft er dabei weg? Einen seriellen Befehl eintippen - 10 Sekunden? Macht 360 geänderte Schaltzeiten pro Stunde. Da müßte er 100000/360= 277 Stunden ständig dransitzen und immmer dieselbe Schaltzeit ändern, damit das ein Problem werden könnte.

Wenn jemand seine Arduino-Zeitschaltuhr mutwillig zerstören möchte, geht das auch schneller als in (Minimum) 277 Stunden Befehle über Serial eintippen: Einfach mit dem Hammer draufschlagen! Viele EEPROM-Speicher halten auch 10, 100 oder 1000 mal so lange wie der Hersteller es mindestens garantiert.

Doc_Arduino: Noch eine Frage zu Struktur. Wird bei neuer Zuweisung zu einer vorhandenen Struktur neuer RAM belegt oder muß man das als Verlinkung betrachten?

Strukturen sind erstmal nicht Zuweisungskompatibel. Und es entstehen auch keine Variablen irgendwie zufällig neu im RAM. Variablen entstehen durch Deklaration. Und wenn Du im Programm mehr als eine Zeitvariable benötigst, kannst Du natürlich mehr als eine Variable deklarieren. Zum Beispiel getrennte Variablen für "Zonenzeit" und "lokale Zeit":

sTime zoneTime; // globale Variable für die Zonenzeit
sTime localTime; // globale Variable für die lokale Zeit

Falls Du im Programm gleichzeitig mit verschiedene Zeiten zu hantieren hast.

Aber weshalb willst Du in einem Programm verschiedene Zeiten haben? Willst Du verschiedene RTC-Module am selben Arduino anschließen, alle RTC-Module auf dieselbe Zeit stellen und später wieder auslesen und vergleichen, um wieviel welches Modul eine andere Zeit hat als die anderen angeschlossenen Module?

Noch ne Frage an jurs,

wäre sowas praktikabel:

void processing()
{ if (deltaTau >= 1.5)
  relayState=isOnTime(localTime,switchTimes, NUMSWITCHTIMES);
  else return;
}

oder eher

void processing()
{ 
  relayState=isOnTime(localTime,switchTimes, NUMSWITCHTIMES,(deltaTau >= 1.5));

}

Oder ist gar beides gleich, nur anders geschrieben...

Loschder: oder eher

void processing()
{ 
  relayState=isOnTime(localTime,switchTimes, NUMSWITCHTIMES,(deltaTau >= 1.5));

}

Der Aufruf der Funktion 'isOnTime()', so wie ich sie gepostet habe, ergibt so keinerlei Sinn und sollte zu Compiler-Mecker beim Compilieren führen, wenn Du versuchen solltest, vier Parameter an die Funktion zu übergeben.

Die Funktion erwartet genau drei Parameter: - die aktuelle Zeit - einen Pointer auf den ersten Eintrag im Schaltzeiten-Array - die Anzahl der Schaltzeiten im Schaltzeiten-Array Mit einem vierten Parameter kann die von mir geschriebene Funktion nichts anfangen.

Hallo,

ich hatte ja nur mal vorgedacht. Ohne extra save Befehl mußte immer vergleichen ob sich was geändert hat um zu speichern. Sonst speichert man ja jedesmal. Das kann man sich sparen wenn man einen save Befehl hat. Und ja, ich würde nicht pauschal ständig drauf los speichern wenn ich es nicht muß. Ich soll ja auch nicht sinnlos den RAM verballern nur weil viel habe.

Zur Strukturfrage. Ich möchte keine zusätzlichen Zeiten einbauen. Ist nur eine Frage zum RAM Verbrauch gewesen.

Demnach verbraucht sowas, nur theoretisch gedacht, keinen zusätzlichen RAM? Kann ich mehrfach neu anlegen wie ich möchte? Ich frage deshalb, weil damit jeder Aufruf eine neue Struktur anlegt. Irgendwo muß das ja gespeichert werden.

readLocalTime(localTime_2);
readLocalTime(localTime_3);
readLocalTime(localTime_4);

Strukturen verhalten sich auch nicht anders als normale Variablen. Das ist nur ein Container für Variablen. Parameter werden beim Aufruf auf den Stack kopiert und hören am Ende der Funktion auf zu existieren. Jedenfalls bei call-by-value. Wenn man call-by-reference hat wird da auch kein Speicher verbraucht. Das ist ja Sinn der Sache.

Und in dem Fall dient die Struktur ja glaube ich als Rückgabe-Wert. Die wird also vorher angelegt. Dann übergibt sie per Referenz und die Funktion füllt sie mit Werten.

Doc_Arduino: Demnach verbraucht sowas, nur theoretisch gedacht, keinen zusätzlichen RAM? Kann ich mehrfach neu anlegen wie ich möchte? Ich frage deshalb, weil damit jeder Aufruf eine neue Struktur anlegt. Irgendwo muß das ja gespeichert werden.

readLocalTime(localTime_2);
readLocalTime(localTime_3);
readLocalTime(localTime_4);

Nein, das hier verbraucht RAM:

sTime localTime_2; // ==> verbraucht RAM
sTime localTime_3; // ==> verbraucht RAM
sTime localTime_4; // ==> verbraucht RAM

Das hier braucht nur zeitweise 2 Bytes extra RAM, während die jeweilige Funktion läuft:

readLocalTime(localTime_2);
readLocalTime(localTime_3);
readLocalTime(localTime_4);

Der zusätzliche RAM-Bedarf entstehet dadurch, dass während die Funktion läuft, eine Pointer auf die Variable auf den Stack gelegt wird, der aber nach dem Funktionsende dort wieder heruntergenommen wird. Und nach dem Funktionsaufruf ist das RAM wieder wie vor dem Funktionsaufruf.

Ok,

und wie verknüpfe ich meine deltaTau Bedingung mit dem relayState=isOnTime???

ein byte erstellen? Und dann? Wie wäre die Einbindung?

Loschder: Ok,

und wie verknüpfe ich meine deltaTau Bedingung mit dem relayState=isOnTime???

ein byte erstellen? Und dann? Wie wäre die Einbindung?

Zum Beispiel:

void processing()
{ 
 // Einschalten nach Zeit, aber nur wenn eine Zusatzbedingung erfüllt ist
 relayState=isOnTime(localTime,switchTimes, NUMSWITCHTIMES) && (deltaTau >= 1.5);
}

Da es sich bei deltaTau offenbar um eine float-Variable handelt, muss die natürlich auch irgendwo herkommen und aktualisiert werden, z.B. innerhalb der input() Funktion von einem Sensor ausgelesen werden.

Ahhhh, supi.

Definiert als
float deltaTau;

und wird in void DHTtask errechnet

Wäre auch eine Schalthysterese rel. einfach realisierbar?

=1.5 ein, <1 aus ?

Loschder:
Wäre auch eine Schalthysterese rel. einfach realisierbar?

=1.5 ein, <1 aus ?

Für die Berücksichtigung einer Hysterese beim Schalten mußt Du Dir immer den letzten Schaltzustand merken, der sich aufgrund der Hysteresebedingung ergibt.

Z.B. in einer ‘static’ deklarierten Variablen innerhalb der Funktion.

Wenn der obere Wert überschritten wird, den Schaltzustand setzen.
Wenn der untere Wert unterschritten wird, den Schaltzustand löschen.
Ansonsten, wenn die Werte dazwischen pendeln, immer den letzten Schaltzustand beibehalten.

void processing()
{ 
  static boolean deltaState;
  if (deltaTau >= 1.5) deltaState=true; // Deltastate setzen bei >=1.5
  else if (deltaTau < 1.0) deltaState=false; // Deltastate löschen bei <1.0
  // in allen anderen Fällen behält deltaState seinen letzten Zustand bei
  relayState=isOnTime(localTime,switchTimes, NUMSWITCHTIMES) && deltaState;
}

Dann hast Du eine Schalthysterese für den deltaTau-Messwert.

Wenn ich jetzt noch einen Taster einbinden möchte mit folgender Funktion:

Zum Wechsel des Relais-Ausgang: Automatik(Zeit und deltaTau), manuell Ein, manuell Aus

  1. mal Drücken relayState=isOnTime(localTime,switchTimes, NUMSWITCHTIMES) && deltaState;

  2. mal Drücken relayState= Ein, unabhängig von Bedingungen (was genau ist hier der Befehl, 1, true...?)

  3. mal Drücken relayState= Aus, unabhängig von Bedingungen (0, false...?)

und wieder von vorn

Was wäre hier machbar?

Loschder:
Was wäre hier machbar?

Vieles ist denkbar. Um einen interaktiven Button zu unterstützen, könntest Du beispielsweise zusätzlich zum ‘serialTask();’ auch noch einen ‘buttonTask()’ vorsehen, in dem ein Button abgefragt und eine StateChange-Erkennung mit Entprellung gemacht wird, und jedesmal beim Drücken des Buttons wird eine globale byte-Variable ‘operatingMode’ um eins weitergeschaltet, etwa:
operatingMode==0 für ‘Immer aus’
operatingMode==1 für ‘Immer ein’
operatingMode==2 für ‘Automatik’
und von 2 geht es dann beim nächsten Drücken des Buttons wieder zurück auf 0.

In der Funktion processing()-Funktion kannst Du den relayState dann setzen wie Du es möchtest.

Wobei sich auch eine optische Rückmeldung in der LCD-Anzeige anbietet, in welcher Betriebsart die Zeitschaltuhr betrieben wird. Beispielsweise könnte man in der zweiten LCD-Zeile neben dem Datum entweder den Text “MANU” oder “AUTO” für manuelle oder automatische Betriebsart einblenden.

Außerdem müßtest Du Dir dann überlegen, was nach einem Stromausfall passieren soll und ob die Variable ‘operatingMode’ dauerhaft gespeichert werden muss, damit der Wert nach einem Stromausfall wieder zur Verfügung steht.

Möglich wäre:

  1. Nach einem Reset des Controllers immer mit derselben festgelegten Betriebsart zu starten, z.B. mit operatingMode=2 für Automatikbetrieb
  2. Nach dem Ändern der Betriebsart diese im entweder batteriegepufferten Uhren-RAM (DS1307) oder im EEPROM zu speichern, und nach einem Controller-Reset in der setup() Funktion die Betriebsart dort wieder auszulesen, wo sie gespeichert wurde, damit der Controller nach einem Stromausfall beim Wiederkehren der Stromversorgung mit derselben Betriebsart weitermacht, auf die er vorher eingestellt worden war.

Ja, ja ,ja und nochmal ja :grin:

Genau des brauch ich...

Und logo solls zurück aufm Display ausgegeben werden...bau mir gerade n Plexi-Gehäuse für 2 St 20x4 LCD´s - da passt einiges drauf ;)

Ich schau mal ob ich da was zusammen bekomme...

So in etwa richtig???

const int buttonPin  = 2;

int buttonState      = 0;
int lastButtonState  = 0;
int StateNum         = 0;
int operatingMode    = 2;

void setup() {
 pinMode(buttonPin, INPUT);
}

void buttonTask() 
{
 // read the pushbutton input pin
 buttonState = digitalRead(buttonPin);

   
   // change the state of the led when someone pressed the button
   if (buttonState == 1) {
        stateNum++;
     if(stateNum>2) stateNum=0;    
   }

     if (stateNum == 0)
     {
           operatingMode = 0;
           LCD.print (" manuell AUS");
     }
     elseif (stateNum == 1)
     {
           operatingMode = 1;
           LCD.print ("manuell EIN");
     }
     elseif (stateNum == 2)
     {
           operatingMode = 2;
           LCD.print ("Automatik");
     }
}

Hallo Jurs,

hab nun was gefunden…

byte operatingMode = 2;
int buttonPin      = 2;

void setup() 
{
  Serial.begin(9600);
  pinMode(buttonPin, INPUT);            // Signal - Taster
}

boolean buttonPressed()                 // Taster abfragen auf drücken des Buttons
{
  static boolean lastButtonState;
  boolean buttonState=digitalRead(buttonPin);
  if (buttonState!=lastButtonState)     // Status hat sich geändert
  {
    lastButtonState=buttonState;        // letzten Status merken
    if (buttonState==HIGH) return true; // Status hat sich auf "gedrückt" geändert
  }
  return false;
}

void loop() 
{ 
   if (buttonPressed()) 
  {
     operatingMode++;
     if(operatingMode>2) operatingMode=0;   
   }

     if (operatingMode == 0)
     {
           Serial.print (" manuell AUS");
     }
     else if (operatingMode == 1)
     {
           Serial.print ("manuell EIN");
     }
     else if (operatingMode == 2)
     {
           Serial.print ("Automatik");
     }
}

Passt das nu? Wie arbeite ich jetzt das byte operatingMode in die void processing?

void processing()
{
  static boolean deltaState;
  if (deltaTau >= 1.5) deltaState=true; // Deltastate setzen bei >=1.5
  else if (deltaTau < 1.0) deltaState=false; // Deltastate löschen bei <1.0
  // in allen anderen Fällen behält deltaState seinen letzten Zustand bei
  relayState=isOnTime(localTime,switchTimes, NUMSWITCHTIMES) && deltaState&& (operatingMode=2) || (operatingMode=1);
}

RICHTIG…?

Loschder:
RICHTIG…?

Richtig ist, was richtig funktioniert.

Deine Buttonabfrage dürfte so nicht funktionieren, weil sie so schnell aufeinanderfolgt, dass Du mechanisches Tasterprellen mit erfaßt und Du daher ggf. mehrere Signale bekommst, wenn der Taster tatsächlich nur einmal gedrückt wird.

Und Deine Verarbeitungslogik ist einerseits falsch, weil Du mit “=” Variablenzustände zuweist wo Du mit “==” Variablenzustände logisch vergleichen möchtest. Außerdem würde ich es eher so schreiben:

void processing()
{
  static boolean deltaState;
  if (operatingMode==0) relayState=false;  // manuell AUS
  else if (operatingMode==1) relayState=true; // manuell EIN
  else  // AUTOMATIK mit Berücksichtigung von Sensormesswert und Zeit
  {
    if (deltaTau >= 1.5) deltaState=true; // Deltastate setzen bei >=1.5
    else if (deltaTau < 1.0) deltaState=false; // Deltastate löschen bei <1.0
    // in allen anderen Fällen behält deltaState seinen letzten Zustand bei
    relayState=isOnTime(localTime,switchTimes, NUMSWITCHTIMES) && deltaState;
  }
}

jurs: Richtig ist, was richtig funktioniert.

Deine Buttonabfrage dürfte so nicht funktionieren...

Habs gerade mal aufgebaut... funktionieren tut´s irgendwie, aber hast recht...manchmal "verschluckt" sich der Status.

Habe noch im void setup digitalWrite(buttonPin,HIGH); zugefügt... aber kaum Besserung

Hasde ne Empfehlung für mein Problemchen...???

Schonmal Danke...auch für´s proccesing file (funzt perfekt)

MfG Chris