Sehr lange Verzögerung () möglich?

9

Ich versuche, eine kleine Tür zu öffnen und zu schließen, die sich alle 12 Stunden öffnen oder schließen sollte. Ich habe mich gefragt, ob ich nur ein kleines Schleifenskript mit einer Verzögerung () für 12 Stunden und einer Verzögerung (43 200 000 000) erstellen könnte. Ich vermute? Ich habe jedoch keine Ahnung, ob dies möglich und / oder empfehlenswert ist. Einige Rückmeldungen / Alternativen (falls erforderlich) wären nett :)

Fred Pannekoek
quelle
ok, ich denke, Verzögerung hat ein Maximum von 65535 µs, aber jetzt brauche ich eine Alternative ...
Fred Pannekoek
4
Das Timing in ausgereifteren MCU-alleinigen Systemen erfolgt normalerweise, indem ein Hardware-Timer-Kanal der MCU so programmiert wird, dass ein Interrupt regelmäßig ausgelöst wird, und diese dann gezählt werden. Dadurch kann der Prozessor in der Zwischenzeit andere Aufgaben ausführen und ist kumulativ so genau wie der Uhrenkristall.
Chris Stratton
3
Durch die Verwendung der Verzögerung wird ein sehr geringfügiger Overhead-Fehler vergrößert. Es ist besser, einen Interrupt zu verwenden, um eine bekannte gute Periode zu messen und dann von dort aus zu zählen. Hier ist ein Proof of Concept auf meiner persönlichen Website: blog.linformatronics.nl/213/electronics/…
jippie
1
Wenn es nicht perfekt abgestimmt sein muss, können Sie unkonventionelle Dinge wie einen Lichtsensor verwenden, um morgens und abends zu erfassen.
Der Kerl mit dem Hut
Ja, ich habe darüber nachgedacht, aber ich habe nur ein kleines Lichtdetektorteil und bin mir nicht sicher, wie ich es vor dem Wetter schützen soll (die kleine Tür ist draußen)
Fred Pannekoek

Antworten:

10

Die Echtzeituhrmethode ist die genaueste Methode, wird aber ansonsten verwendet millis

unsigned long startMillis = millis();
while (millis() - startMillis < LONG_DELAY_MS);

Dies verzögert sich bis zu ca. 4294967295ms (2 ^ 32-1) oder 49 Tage, danach holt der Timer den Wert von aufstartMillis

geometrisch
quelle
1
Was ist falsch daran, nur zu benutzen delay(LONG_DELAY_MS)? Die Arduino-Implementierung akzeptiert vorzeichenlose Longs. Ich bin mir auch nicht ganz sicher, ob Ihr Code beim millis()Umwickeln korrekt funktioniert und kleiner ist alsstartMillis
Gerben
Verzögerung macht Ihr Arduino vollständig inaktiv, während Sie warten, wenn ich richtig bin. Ich weiß nicht, wie sich das verhalten wird, wenn Millis wieder auf 0 steht.
Fred Pannekoek
@ Gerben gute Sachen, als Antwort!
geometrisch
2
@FredPannekoek-Überlauf funktioniert einwandfrei, solange unsigned long verwendet wird.
geometrisch
1
@ 23ars Der Hauptgrund, warum Arduino so erfolgreich ist, ist seine benutzerfreundliche Hardware-Abstraktionsbibliothek. Wenn Sie gegen Funktionen aus Bibliotheken sind, beschränken Sie sich etwas. Wie auch immer, die Funktion von Kommentaren besteht darin, die Antwort zu verbessern. Wenn Sie eine bessere Lösung haben, schreiben Sie Ihre eigene Antwort. ;)
geometrisch
7

delay()hat seine Verwendung, aber für lange Verzögerungen ist es nicht gut. Es weist den Mikrocontroller einfach an, nichts für xTaktzyklen zu tun . Während dieser Zeit kann Ihr Arduino nichts anderes tun.

Am besten verwenden Sie eine sogenannte Echtzeituhr (RTC). Diese Chips wurden speziell entwickelt, um die Zeit im Auge zu behalten, und Sie können sie problemlos mit Ihrem Arduino verbinden. Hier ist ein Beispiel, wie Sie das tun können.

Tom
quelle
+1 - Die RTC-Lösung ist besonders gut, wenn Sie mehr Genauigkeit wünschen, als die MCU Ihnen bieten kann.
Ricardo
1
@ Ricardo - Eine RTC ist wahrscheinlich nicht genauer als eine MCU mit einem Taktkristall, der einen ihrer Hardware-Timer verwendet, um einen periodischen Interrupt auszulösen. Normalerweise erhalten Sie einen Überblick über den Stromausfall und möglicherweise einige Kenntnisse über Kalenderschemata.
Chris Stratton
1
Afaik uno verwendet kein Quarzbit, keinen Keramikresonator für seine Uhr, daher mit viel geringerer Genauigkeit als ein RTC.
Jfpoilpret
@ ChrisStratton - Richtig. Punkt genommen. Die RTC ist eine viel bessere Option, wenn das OP die Tür zu einer bestimmten Tageszeit öffnen oder schließen muss.
Ricardo
7

Sie können den Watchdog-Interrupt verwenden und Ihre MCU während des Wartens in den Ruhezustand versetzen und Strom sparen.

Beachten Sie jedoch, dass Sie nur dann Strom sparen, wenn Ihr Board dies auch spart. Das bedeutet, dass Sie anstelle der üblichen Regler, mit denen die gängigsten Arduino-Boards wie das Uno ausgestattet sind, einen Regler für niedrige Ruhespannung benötigen. Ansonsten spielt es keine Rolle, ob Ihre MCU Energie spart, wenn Ihr Board dies nicht tut.

Hier ist der Code (ungetestet):

#include <avr/sleep.h>
// This variable is made volatile because it is changed inside an interrupt function
volatile int sleep_count = 0; // Keep track of how many sleep cycles have been completed.
const int interval = 720; // Interval in minutes between waking and doing tasks.
const int sleep_total = (interval*60)/8; // Approximate number of sleep cycles 
// needed before the interval defined above elapses. Not that this does integer math.

void setup(void) {
    watchdogOn(); // Turn on the watch dog timer.
    // Disable the ADC by setting the ADEN bit (bit 7) to zero.
    ADCSRA = ADCSRA & B01111111;
    // Disable the analog comparator by setting the ACD bit (bit 7) to one.
    ACSR = B10000000;
    // Disable digital input buffers on all analog input pins by setting bits 0-5 to one.
    DIDR0 = DIDR0 | B00111111;
}

void loop(void) {
    goToSleep(); // ATmega328 goes to sleep for about 8 seconds
    // and continues to execute code when it wakes up
    if (sleep_count == sleep_total) {
        // CODE TO BE EXECUTED PERIODICALLY
    }
}

void goToSleep() {
    set_sleep_mode(SLEEP_MODE_PWR_DOWN); // Set sleep mode.
    sleep_enable(); // Enable sleep mode.
    sleep_mode(); // Enter sleep mode.
    // After waking from watchdog interrupt the code continues
    // to execute from this point.
    sleep_disable(); // Disable sleep mode after waking.
}

void watchdogOn() {
    // Clear the reset flag, the WDRF bit (bit 3) of MCUSR.
    MCUSR = MCUSR & B11110111;
    // Set the WDCE bit (bit 4) and the WDE bit (bit 3) of WDTCSR. 
    WDTCSR = WDTCSR | B00011000; 
    // Set the watchdog timeout prescaler value to 1024 K 
    // which will yeild a time-out interval of about 8.0 s.
    WDTCSR = B00100001;
    // Enable the watchdog timer interupt.
    WDTCSR = WDTCSR | B01000000;
    MCUSR = MCUSR & B11110111;
}

ISR(WDT_vect) 
{
    sleep_count ++; // keep track of how many sleep cycles have been completed.
}

Der Code, den ich kopiert habe, stammt von dieser Seite: Arduino mit geringem Stromverbrauch unter Verwendung des Watchdog-Timers .

Ricardo
quelle
1

Haben Sie einen Schlaf (vorzeichenlose int Sekunden) zur Verfügung?

Wenn nicht, können Sie () sehr lange verzögern ():

for (unsigned int bigloop=0; bigloop<65535; bigloop++)
{
   for (unsigned int smallloop=0; smallloop<65535; smallloop++)
   {
      for (unsigned int tinyloop=0; tinyloop<65535; tinyloop++)
      {
         delay(65535);
      }
   }
}
TDHofstetter
quelle
Ich könnte es versuchen, wenn ich es nicht schaffe, einen RTC zu bekommen, wie Tom sagte. Danke fürs Helfen!
Fred Pannekoek
1

Das wird funktionieren:

longDelayInSeconds = 120; //two minutes;   
while (p < longDelayInSeconds) {

        delay(1000);
        p++;

}
Frank C.
quelle
4
nicht die beste Lösung und das OP bat um 12 Stunden, nicht 2 Minuten.
Madivad
1

Ich benutze nur for-Schleifen, wenn ich nichts dazwischen machen möchte:

for (int Hours = 0; Hours < 12; Hours++) {            //Creates 12 hours
  for (int Minutes = 0; Minutes < 60; Minutes++) {    //Creates 1 hour
    for (int Seconds = 0; Seconds < 60; Seconds++) {  //Creates 1 minute
      delay(1000);                                    //Creates 1 second
    }
  }
}
Lohan
quelle
4
Erklären, wie das besser ist als ein einfaches delay(43200000).
1
Für den Anfang wäre es einfacher zu ändern, wie lange Sie warten möchten. Ändern Sie einfach die Zahl für jede Stunde, Minute und Sekunde, ohne in Millisekunden umrechnen zu müssen.
GeneCode