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

Hallo,

Deine Klammersetzung war völlig daneben. Beschäftige Dich bitte mit dem Syntax.
Scheinbar hat der Compiler immer ein brauchbares Klammernpaar gefunden und hat deshalb nicht gemeckert.

probiere es mal damit

#define RELAY1  6                        
#define RELAY2  7                        

void Relais (sTime time)
{   // Reihenfolge spät nach früh

  if ( time.bHour == 20 && time.bMinute >= 50 && time.bMinute <= 51 )    // zwischen 20:50 - 22:51 Uhr
    {
	 digitalWrite(RELAY1,LOW);           // Turns ON Relays 1
    }
    else  digitalWrite(RELAY1,HIGH);           // Turns ON Relays 1
    
  if ( time.bHour == 20 && time.bMinute >= 52 && time.bMinute <= 53 )    // zwischen 20:52 - 22:53 Uhr
    {    
     digitalWrite (RELAY2, LOW);
    }
    else  digitalWrite(RELAY2,HIGH);           // Turns ON Relays 1

Hallo Leute....

@jurs Ja genau...soweit ich nun in der Matherie durchblicke kann eine Funktion nur einen Wert zurück geben. Und da bräuchte ich eine Funktion die eben ein Timeswitch-Flag zurück gibt welches in einer weiteren Funktion mit dem deltaH-Flag weiter verarbeitet werden kann/soll.

@doc Uijuij...habs gestern abend auch noch gemerkt dass da die Klammern falsch waren. Hab aber noch immer das Problem dass ich das wenn ich es in einer separaten Funktion laufen haben möchte die Relais nix tun. Wo genau muss ich denn wie die Relais definieren damit ich diese auch separat in einer eigenen Funktion ein/aus schalten kann???

PS: Da fehlt ne Schlussklammer bei dir :grin:

Hallo,

ich habe auch ein Problem mit der sTime Struktur. Man kann die nicht einfach so frei verwenden.

Ich kann zwar fehlerfrei kompilieren, bekomme aber entweder 0 oder irgendwelchen Müll ausgegeben. Das wird sicherlich bei dir auch so sein, deswegen werden Deine if Bedingungen nie erfüllt sein. Wenn Du die Minuten und Stunden seriell ausgeben läßt, siehst Du was da gerade aktuell ist.

Hab mal mein C Buch rausgekramt, vielleicht komme ich heute noch dahinter ... :D

Wenn ich die if-Abfragen in die void printDateTime Funktion integriere dann funktioniert das Schalten der Relais.

Wenn ich eine neue Funktion anlege z.B. void switchrelais (sTime time) , dann sind beide immer "HIGH"...

Hallo,

genau daran scheiter ich auch noch. Weil ein neuer fremder Funktionsufruf der sTime Struktur irgendwie nicht so funktioniert wie gedacht. Kommt Zeit kommt Rat ...

Loschder:
Muss ich mal ein klein wenig drüber nachdenken.

So, fertig nachgedacht und ein geändertes Programmbeispiel gemacht.

Die Library ist nun um eine “Timer Switch” (Zeitschaltuhr) Logik erweitert worden.

Das Beispielprogramm unterstützt dabei einen Schaltausgang (vorkonfiguriert: Pin-13) mit beliebig vielen Tagesschaltzeiten.

LCD-Anzeige mit der LiquidCrystal-Library ist im Beispielprogramm nun ebenfalls enthalten und kann über bedingte Kompilierung durch Ändern einer einzigen Zeile eingebunden oder außen vor gelassen werden:

#define LCD_OUTPUT 1 // comment out this line or set 0 if no LCD is used

Vorkonfiguriert sind die Pins, die vom “LCD KEYPAD SHIELD” verwendet werden.

Die Programmlogik in der loop() Funktion ist nun wie folgt:

  • bei jedem Durchlaufen der loop auf serielle Befehle zum Stellen der Zeit testen
  • einmal pro Sekunde die Funktionen input(), processing() und output() aufrufen

Der Schaltstatus ‘relayState’ wird in der Funktion ‘processing()’ gesetzt.
Wenn die Schaltung nicht rein nach Zeit erfolgen soll, so wäre in der ‘processing()’ Funktion der richtige Platz dafür, den Schaltstatus noch zu ändern.

Das setzen des Ausgangs gemäß ‘relayState’ erfolgt dann erst in der ‘output()’ Funktion, wo auch die Textanzeige formatiert und ausgegeben wird (1x pro Sekunde auf LCD, 1x alle 10 Sekunden auf Serial).

Wie bisher auch muss die Library nicht installiert werden, sondern einfach den Ordner des Beispielprojekts im Arduino-Sketchordner entpacken. Die Library befindet sich dann auf einer Tab-Seite.

dateTimeLibEasyDemo.zip (5.13 KB)

Hallo,

irgendwie wird doch mit den Strukturen nur alles verbastelt? Einen richtigen Sinn hat das doch nicht?
Lokale Variablen hätten das auch getan.

Ich habe jetzt lange daran gesessen um die reine Sekunde irgendwie vor zu holen um sie im Hauptsketch verwenden zu können. Nach langer Zeit merkte ich, dass man im Hauptsketch gar nichts mehr machen kann. Man muß in der .h Datei/Tab bleiben. Ich bekomme die Sekunde zum Bsp. nicht raus um sie global verwenden zu können.

Man kann nur vom Hauptsketch Funktionen im .h Tab aufrufen. Aber keine Variablen aus dem .h Tab rüberholen.

Laut meinem Verständnis und meinem Buch müßte es eigentlich so sein, dass man mit
Serial.print (sTime.bSecond) auf die Sekunde zugreifen kann. Funktioniert aber nicht.

Meine Krücke wäre jetzt die, alles weitere im .h Tab zu schreiben.

Es wäre gut für alle zu wissen, wie man die Variablen aus dem h. Tab rausbekommt?

Mittlerweile hast Du schon einen neuen Code erstellt. Nur wer soll das vertehen und daraus lernen?
Es ist ja auch wieder alles ins .h Tab gewandert. Warum macht man das?

dateTimeLibEasyDemo_001.zip (4.39 KB)

Doc_Arduino: irgendwie wird doch mit den Strukturen nur alles verbastelt? Einen richtigen Sinn hat das doch nicht?

Durch die Library, die exakt NULL Variablen enthält, werden Daten und Code getrennt. Das ist der Sinn einer Library, die für die Verarbeitung spezieller Daten ebenso speziellen Code bereitstellt. Übergeben werden Daten ausschließlich als "Parameter" an die Funktionen der Library. Und zurückgeliefert werden Ergebnisse entweder als "Rückgabewert" einer Funktion, oder in Form von Referenzparametern ("call by reference"), die durch die Funktion verändert werden können und nach dem Aufrufen einer Funktion einen anderen Inhalt haben als vor dem Aufruf.

Die Library enthält nur Datenstruktur-Grundgerüste ('struct'), aus denen Du in Deinem Hauptprogramm Variablen erzeugen kannst. Z.B. schreibst Du im Hauptprogramm:

sTime localTime;

Und schon hast Du eine Variable mit dem Namen 'localTime', die vom Typ 'sTime' ist, mit der Du etwas machen kannst.

Du könntest in diese Variable zum Beispiel aus der RTC die lokale Zeit einlesen, wozu es in der Library (.h Tab) eine Funktion gibt, die Du aufrufen kannst:

RTCreadLocalTime(localTime);

Und dann hast Du in der Variablen 'localTime' eine komplette Zeitangabe zur Verfügung. localTime.iYear ==> Jahr localTime.bMonth ==> Monat localTime.bDay ==> Tag localTime.bHour ==> Stunde localTime.bMinute ==> Minute localTime.bSecond ==> Sekunde localTime.sTimezone ==> Zeitzone (0=UTC, 1=CET, 2=CEST)

Kannst Du alles im Programm verwenden.

Oder auch nicht.

Hallo jurs,

erstmal Danke für die Rückmeldung. Ich hatte vergessen das die .h Tab sowas ist wie eine Lib mit strenger Trennung damit nichts durcheinander kommt. Deshalb der Sinn von struct. Soweit klar. Okay.

Mit der Übergabe und Aufruf muß ich mir morgen in Ruhe nochmal anschauen. Mir schwirt immer noch im Kopf, dass ja alles schon vorhanden ist und man nur mit sTime.bSecond oder meinetwegen mit time.bSecond draufzugreifen müßte. Dachte ich jedenfalls. Bis später ...

R E S P E K T

Jurs, danke für deine Mühe...funktioniert einwandfrei!!!

Danke...danke...danke

MfG Chris

Hallo,

also das mit dem struct denke ich, habe ich verstanden. Wir verstehen uns aber noch falsch.

Ich müßte jetzt jedesmal zusätzlich die RTC neu auslesen um meine eigene Variable zubekommen damit ich im Hauptsketch damit arbeiten kann? Das zusätzliche auslesen ist doch aber Quatsch, wenn die eh aller x Sekundenintervall ausgelesen wird. Die Zeit ist doch schon im Speicher bzw. in Deinem struct. Ich will nur darauf zugreifen. Nicht nochmal die RTC mit auslesen belasten und Zeit vertrödeln.

Wenn ich weiter richtig verstehe, kommt man aber wegen der .h Lib nur so an die Daten ran, also muß man die RTC nochmal auslesen, sonst gehts nicht. Richtig?

Das wiederum funktioniert wie Du beschrieben hast, nur wird damit leider die RTC eigentlich unnötig oft angesprochen. Geht nicht doch anders ohne zusätzlichen Zugriff/auslesen?

void TestTaskDemo()
{
  sTime testinfo;
  RTCreadLocalTime(testinfo);
  int zahl = testinfo.bSecond;
  Serial.println(zahl);
}

Edit: oder man ändert die rtcTask Funktion und hängt sich mit rein mit seinen neuen Variablen. Damit umgeht man das zusätzliche auslesen. Die "zahl" kann man auch zur globalen machen.

void rtcTask()
{
  // read the RTC after each UPDATEINTERVAL milliseconds
  static unsigned long lastUpdate;
  sTime time;
  if (millis()-lastUpdate>=UPDATEINTERVAL)
  {
    lastUpdate+=UPDATEINTERVAL;
    RTCreadZoneTime(time); // read zoneTime
    printDateTime(time);   // show it on serial
    RTCreadLocalTime(time); // read localTime
    printDateTime(time);   // show it on serial
    Serial.println();
    
    int zahl = time.bSecond;
    Serial.println(zahl);
  }
}

Doc_Arduino: Wenn ich weiter richtig verstehe, kommt man aber wegen der .h Lib nur so an die Daten ran, also muß man die RTC nochmal auslesen, sonst gehts nicht. Richtig?

Das wiederum funktioniert wie Du beschrieben hast, nur wird damit leider die RTC eigentlich unnötig oft angesprochen. Geht nicht doch anders ohne zusätzlichen Zugriff/auslesen?

Wenn Du eine sekundengenau Zeit benötigst, mußt Du die RTC einmal pro Sekunde auslesen. Ob Du die Zeit dabei in eine "lokale" Variable ausliest, die Du nur in einer einzigen Funktion Deines Sketches verwenden kannst oder in ein "globale" Variable, die stets allen Funktionen Deines Sketches zur Verfügung steht, ist Dir selbst überlassen.

Mein gestern gepostetes Beispielprogramm liest die Zeit einmal pro Sekunde von der RTC in eine globale Variable ein, so dass die sekundengenaue Zeit dann im gesamten Sketch für jede Funktion jederzeit verfügbar ist.

Ist das Auslesen einmal pro Sekunde "unnötig oft" für Dich? Das Auslesen der RTC dauert ca. eine Millisekunde, ist das zu lange, wenn es einmal pro Sekunde gemacht wird?

Würdest Du es bevorzugen, dass die Zeit viel seltener aus der RTC ausgelesen wird (z.B. einmal pro Stunde oder einmal pro Tag?) und die Aktualisierung zwischenzeitlich aus dem millis()-Takt abgeleitet und weitergezählt wird, um dann einmal pro Stunde oder pro Tag eine "Synchronisierung" zwischen der RTC-Zeit und der von millis() abgeleiten weitergezählten Zeit durchzuführen?

Loschder:
R E S P E K T

Jurs, danke für deine Mühe…funktioniert einwandfrei!!!

Danke…danke…danke

Keine Ursache, sowas in der Art wollte ich schon immer mal machen. Denn es hat mich schon immer genervt, dass es überhaupt keine praxisgerechten RTC-Libraries für zeitgesteuerte Anwendungen zu geben scheint. Ein Anfänger muss sich erstmal drei zusätzliche Third-Party-Libraries installieren für Time, TimeAlarms, und DS1307RTC. Und dann hat er immer noch nicht:

  • automatische Sommerzeitumschaltung
  • serielle Befehlsverarbeitung zum Stellen der RTC-Uhrzeit

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.

Noch ne klitzekleine Frage:

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?

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).

MfG Chris

Hallo jurs,

warum reden wir immer aneinander vorbei?

2 Fragen bleiben noch.

Wo sind Deine globalen Variablen? Was ist der Unterschied zwischen void Funktionsname(sTime time) und void Funktionsname(sTime &time) ? Danke.

Doc_Arduino: warum reden wir immer aneinander vorbei?

Keine Ahnung.

Doc_Arduino: 2 Fragen bleiben noch.

Wo sind Deine globalen Variablen?

In dem zuletzt von mir geposteten Beispielprogramm sind das die globalen Variablen:

byte relayState; // globale Variable für den Schaltzustand des Relais

sTime localTime; // globale Variable für die Zeit

swTime_t switchTimes[]={ // globales Variablen-Array für die Schaltzeiten
  {500,530},
  {830,900},
  {1200,1230},
  {1530,1600},
  {1900,1930},
  {2230,2300},
};

Doc_Arduino: Was ist der Unterschied zwischen void Funktionsname(sTime time) und void Funktionsname(sTime &time) ?

Das ist bei einer Funktionsdeklaration in C++ der Unterschied zwischen der Parameterübergabe "Call by Value" und "Call by Reference".

Die Deklaration "void Funktionsname(sTime time)" steht für "Call by Value", in dem Fall ist der Parameter innerhalb der Funktion wie eine lokale Variable zu sehen. D.h. wenn Du von irgendwo die Funktion aufrufst, kannst Du diesen Parameter zwar innerhalb der Funktion ändern, aber die Änderungen sind immer nur für die jeweilige Funktion gültig. Nach Ende der Funktion sieht der Aufrufer wieder nur dieselbe, unveränderte Variable, die er an die Funktion übergeben hat.

Die andere Deklaration "void Funktionsname(sTime &time)" steht für "Call by Reference". In dem Fall ist der Parameter innerhalb der Funktion tatsächlich exakt die Variable, die der Aufrufer übergeben hat. D.h. wenn Du diese Variable dann innerhalb der Funktion veränderst, wird der Aufrufer nach dem Ende der Funktion alle Änderungen in dieser Variablen sehen, die von der Funktion durchgeführt wurden.

@Loschder Man kann auch Pins wirklich gleichzeitig setzten. Das ist aber etwas komplizierter: http://www.arduino.cc/en/Reference/PortManipulation Dazu das: http://pighixxx.com/unov3pdf.pdf

z.B.:

void setPins(byte output)
{
   byte state = PORTB;

   bitWrite(state, 2, !output);  //Pin 10 = PB2
   bitWrite(state, 3, output);   //Pin 11 = PB3
   bitWrite(state, 4, output);   //Pin 12 = PB4
   bitWrite(state, 5, output);   //Pin 13 = PB5

   PORTB = state;
}

Und dann LOW oder HIGH übergeben

@Doc_Arduino

Wo sind Deine globalen Variablen?

Nicht im Header, sondern im Test-Sketch. Der Header enthält nur Deklarationen. Keine Definitionen.

Was ist der Unterschied zwischen void Funktionsname(sTime time) und void Funktionsname(sTime &time) ?

call-by-reference solltest du inzwischen kennen: http://www.willemer.de/informatik/cpp/parameter.htm runter zu "Referenz-Parameter"

Wurde auch von jurs angesprochen. structs oder Objekte sollte man auf Grund der Größe nicht by-value übergeben. Außerdem kann man durch eine Referenz eine Änderung am struct innerhalb der Funktion nach außen übergeben.

In dem Code hat jurs an einer Stelle das & vergessen. Wahrscheinlich ein Flüchtigkeitsfehler

Hallo,

jetzt habe ich den Unterschied verstanden. Vielen Dank an Euch.

Wenn zu viel drum herum geschrieben wird, verliert man das wesentliche. Jurs hat das oben exakt auf den Punkt gebracht. Mehr muß man dazu nicht erklären. Genauso müßte es in den Büchern stehen. Alles nachvollziehbar.

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 ...