Go Down

Topic: [gelöst] Problem Zeitdifferenz zwischen Millis und RTC (Read 194 times) previous topic - next topic

engineeeer

Hallo,

das folgende Teilprogramm soll später in ein größeres Projekt eingegliedert werden.

Zweck:
Ich möchte mehrere Relays zeitgesteuert in einer bestimmten festen Reihenfolge ansteuern.
D.h. wenn das RTC bei sekunde 0 ist, möchte ich den counterTimer starten sodass die Relay ansteuerung ab diesem Zeitpunkt unabhängig von der RTC sekundenzeit ist. Also das RTC zählt dann nach 60 sekunden wieder von 0 an. Mein counterTimer jedoch zählt unabhängig weiter, also z.b. 75 sekunden lang, bis dieser wieder auf 0 gesetzt wird.

Es wird also ein ,,Event´´ ausgelöst (bei RTC sekunde 0) mit dem ich dann mein Relays-Ablauf triggern kann.

Soweit so gut.

Mir ist jedoch aufgefallen das es eine Abweichung beim hochzählen der Sekunden vom RTC, im Vergleich zum counterTimer mit millis() gibt.

Ich dachte eigentlich das das RTC 3231 so genau ist das ich mich darauf verlassen kann. (Zumindest in so kleinen Zeiträumen wie bei mir sowiso).

Später soll das Event natürlich nicht jede Sekunde 0 gestartet werden, es werden weitere Bedingungen verwendet die das Event dann nur starten wenn ich möchte UND die RTC Sekunden auf 0 sind. Im folgenden also nur als Testaufbau.

Hauptfrage:
Wiso zählt der counterTimer langsamer hoch, als die RTC sekunden ???
Wie kann ich dieses Problem kompensieren ???


Im Seriellen Monitor ist eindeutig zu erkennen das der counterTimer nacheilt.

Code: [Select]
//counterUPTimer
unsigned long previousTimer = 0;
int counterTimer = 0;
long intervalTimer = 1000; //

//RTC
#include <DS3231.h>
DS3231 rtc(SDA, SCL);
Time t;

int x = 0;

void setup() {
  Serial.begin(9600);
  rtc.begin();
}

void loop() {

  if (t.sec == 1) {
    x = 1;
  }

  if (x == 1) {
    counterUPTimer();
  }

  t = rtc.getTime();
  Serial.print("   sec:");
  Serial.print(t.sec, DEC);

  Serial.print(" x:");
  Serial.print(x);

  Serial.print(" counterTimer:");
  Serial.println(counterTimer);

}

void counterUPTimer() {

  unsigned long currentTime = millis();

  if (currentTime - previousTimer > intervalTimer) {
    previousTimer = currentTime;
    counterTimer++;
  }
  if (counterTimer == 75) {
    counterTimer = 0;
    x = 0;
  }
}

Wie immer, vielen Dank für Rückmeldungen aller Art !

HotSystems

#1
Nov 03, 2020, 12:36 pm Last Edit: Nov 03, 2020, 12:37 pm by HotSystems
Quote
Hauptfrage:
Wiso zählt der counterTimer langsamer hoch, als die RTC sekunden ???
Wie kann ich dieses Problem kompensieren ???
Weil der Controller meist mit einem nicht so genauen Resonator arbeitet und deine RTC mit einem temperatur kompensierten Quarz arbeitet. Damit ist deine RTC deutlich genauer.

Und warum willst du das kompensieren ?
Gruß Dieter

I2C = weniger ist mehr: weniger Kabel, mehr Probleme. 8)

engineeeer

Also das Relais-Event steuert mehrere Relais an die voneinander nach bestimmten Zeit Muster schalten sollen.

Also z.B.:
Es ist 16:00:00 Uhr und jetzt soll das Relais-Event starten.

Relais 1 geht nach 10 sekunden an.
Relais 2 geht nach 20 sekunden an.
Beide gehen nach 75 sekunden aus.

Mit dem RTC sekunden Zeiger kann ich nicht auf über 60 Sekunden schalten.

Und mit dem internen millis() habe ich also zwangsläufig Abweichung.

Ich würde es gern so genau wie möglich schalten. Wenn ich die Relays dann nach genau 300 sekunden schalten möchte, sind das dann nur 285 sekunden (Übertrieben gesagt). Und das ist ja nicht genau ?


Tommy56

Warum rechnest Du nicht Stunden, Minuten und Sekunden der RTC in Sekunden des Tages um? Dann kannst Du sekundengenau mit der RTC-Zeit arbeiten.

Gruß Tommy
"Wer den schnellen Erfolg sucht, sollte nicht programmieren, sondern Holz hacken." (Quelle unbekannt)

engineeeer

Warum rechnest Du nicht Stunden, Minuten und Sekunden der RTC in Sekunden des Tages um? Dann kannst Du sekundengenau mit der RTC-Zeit arbeiten.

Gruß Tommy
Das wär der Hammer, wie ? Andere Lib. ?

HotSystems

#5
Nov 03, 2020, 12:51 pm Last Edit: Nov 03, 2020, 12:53 pm by HotSystems
Ich würde es gern so genau wie möglich schalten. Wenn ich die Relays dann nach genau 300 sekunden schalten möchte, sind das dann nur 285 sekunden (Übertrieben gesagt). Und das ist ja nicht genau ?


Und deswegen sollst du es mit der RTC machen, das ist sehr genau.

Wie das geht hat Tommy ja schon geschrieben.
Gruß Dieter

I2C = weniger ist mehr: weniger Kabel, mehr Probleme. 8)

Tommy56

Das wär der Hammer, wie ? Andere Lib. ?
Nö, einfach mal nachdenken ;)

Stunden *3600 + Minuten * 60 + Sekunden

Gruß Tommy
"Wer den schnellen Erfolg sucht, sollte nicht programmieren, sondern Holz hacken." (Quelle unbekannt)

engineeeer

Ihr seit die besten, ist ja klar, wie denn sonst.
Finde es mega genial wie aktiv das Forum hier ist.
Besten Dank !

engineeeer

Scheinbar habe ich die Thematik doch nicht verstanden.
Ich möchte das der dayCounter jeweils um 0 UHR um eine stelle hochzählt.

1.Frage:
Wie verhindere ich das der Counter mehrmals hochgezählt wird, solange die if (timeInSecond == 0) erfüllt ist ?

Code: [Select]
Time:15:07:19 t.hour=15 t.min=7 t.sec=19 dayCounter=0 timeInSecond:4294956200
 Time:15:07:20 t.hour=15 t.min=7 t.sec=20 dayCounter=1 timeInSecond:4294956200
 Time:15:07:20 t.hour=15 t.min=7 t.sec=20 dayCounter=2 timeInSecond:4294956200
 Time:15:07:20 t.hour=15 t.min=7 t.sec=20 dayCounter=3 timeInSecond:4294956200
 Time:15:07:20 t.hour=15 t.min=7 t.sec=20 dayCounter=4 timeInSecond:4294956200
 Time:15:07:20 t.hour=15 t.min=7 t.sec=20 dayCounter=5 timeInSecond:4294956200
 Time:15:07:20 t.hour=15 t.min=7 t.sec=20 dayCounter=6 timeInSecond:4294956200
 Time:15:07:20 t.hour=15 t.min=7 t.sec=20 dayCounter=7 timeInSecond:4294956200
 Time:15:07:20 t.hour=15 t.min=7 t.sec=20 dayCounter=8 timeInSecond:4294956200
 Time:15:07:20 t.hour=15 t.min=7 t.sec=20 dayCounter=9 timeInSecond:4294956200
 Time:15:07:20 t.hour=15 t.min=7 t.sec=20 dayCounter=10 timeInSecond:4294956200
 Time:15:07:20 t.hour=15 t.min=7 t.sec=20 dayCounter=11 timeInSecond:4294956200
 Time:15:07:20 t.hour=15 t.min=7 t.sec=20 dayCounter=12 timeInSecond:4294956201




2.Frage:
Wenn ich 15:07:20 UHR in Sekunden seit 00:00Uhr umrechnen möchte.
Dann mach ich doch: 
timeInSecond =  ((t.hour * 3600) + (t.min * 60)) + t.sec;
Somit müsste in diesem Fall doch 54440 rauskommen. Laut SerialMonitor ist die Zahl jedoch 5 Stellen größer ?


Habe unter anderem schon mit Debounce herumprobiert, jedoch noch kein Erfolg erzielt.


Vielen Dank für weitere Denkanstöße!



Code: [Select]
//RTC
#include <DS3231.h>
DS3231 rtc(SDA, SCL);
Time t;

//timeInSeconds
unsigned long timeInSecond = 0;
int dayCounter = 0;

void setup() {
  Serial.begin(9600);
  rtc.begin();

}

void loop() {

  timeInSeconds();
  dayUpCounter();

  Serial.print(" Time:");
  Serial.print(rtc.getTimeStr());

  Serial.print(" t.hour=");
  Serial.print(t.hour);

  Serial.print(" t.min=");
  Serial.print(t.min);

  Serial.print(" t.sec=");
  Serial.print(t.sec);

  Serial.print(" dayCounter=");
  Serial.print(dayCounter);
}

void timeInSeconds() {
  t = rtc.getTime();
  timeInSecond =  ((t.hour * 3600) + (t.min * 60)) + t.sec;
  Serial.print(" timeInSecond:");
  Serial.println(timeInSecond);
}

void dayUpCounter() {

  if (timeInSecond == 0) {      // [(timeInSecond == 4294956200) Zu Testzwecken]
    dayCounter++;
  }
}







Tommy56

Schreibe mal 3600UL, sonst wird rechts in int gerechnet.
Ungewtestet, als Denkanstoß:
Code: [Select]

byte oldDay;
unsigned int dayCounter = 0; // Du erwartest keine negativen Tage

oldDay = t.day; // im setup aus der RTC

...
if (t.day != oldDay) {
  oldDay = t.day;
  dayCounter++;  //
}



Die timeInSecond brauchst Du an dieser Stelle nicht.

Gruß Tommy
Gruß Tommy
"Wer den schnellen Erfolg sucht, sollte nicht programmieren, sondern Holz hacken." (Quelle unbekannt)

engineeeer


Go Up