Czy możliwe jest bardzo duże opóźnienie ()?

9

Staram się otwierać i zamykać małe drzwi, które powinny się otwierać lub zamykać co 12 godzin. Zastanawiałem się, czy mógłbym po prostu zrobić mały skrypt z zapętleniem z opóźnieniem () na 12 godzin, opóźnienie (43 200 000 000); Zgaduję? Nie mam jednak pojęcia, czy jest to możliwe i / lub godne polecenia. Przydatne byłyby jakieś opinie / alternatywy (w razie potrzeby) :)

Fred Pannekoek
źródło
ok, myślę, że opóźnienie ma maksimum 65535 µs, ale teraz potrzebuję alternatywy ...
Fred Pannekoek,
4
Pomiar czasu w bardziej dojrzałych systemach samotnie MCU jest zwykle wykonywany przez zaprogramowanie kanału timera sprzętowego MCU, aby okresowo uruchamiał przerwanie, a następnie zliczanie ich - co pozwala procesorowi robić inne rzeczy w międzyczasie i jest kumulatywnie tak dokładne jak kryształ zegara.
Chris Stratton,
3
Użycie opóźnienia zwiększy jeszcze tak niewielki błąd narzutu. Lepiej jest użyć przerwania, aby odmierzyć znany dobry okres, a następnie policzyć stamtąd. Oto dowód koncepcji na mojej osobistej stronie: blog.linformatronics.nl/213/electronics/...
jippie
1
Jeśli nie musi to być dokładnie na czas, możesz użyć niekonwencjonalnych rzeczy, takich jak czujnik światła, aby wyczuć poranek i wieczór.
Facet z kapeluszem
tak, myślałem o tym, jednak mam tylko małą część detektora światła i nie jestem pewien, jak uchronić ją przed warunkami atmosferycznymi (małe drzwi są na zewnątrz)
Fred Pannekoek

Odpowiedzi:

10

Metoda zegara czasu rzeczywistego jest najdokładniejszym sposobem, ale w przeciwnym razie jest używana millis

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

Opóźni to do ok. 4294967295ms (2 ^ 32-1) lub 49 dni, po upływie których czasomierz dogoni wartość dostartMillis

geometrikal
źródło
1
Co jest złego w zwykłym używaniu delay(LONG_DELAY_MS)? Arduino realizacja akceptuje niepodpisanych tęskni. Nie jestem też do końca pewien, czy kod działa poprawnie, gdy jest millis()zawijany, i jest mniejszy niżstartMillis
Gerben,
Opóźnienie powoduje, że twoje arduino jest całkowicie nieaktywne podczas oczekiwania, jeśli mam rację. Nie wiem, jak to zadziała, gdy millis powróci do zera
Fred Pannekoek,
@Gerben dobre rzeczy, połóż to jako odpowiedź!
geometrikal
2
Przepełnienie @FredPannekoek będzie działać dobrze, o ile użyty zostanie długi bez znaku .
geometrikal
1
@ 23ars Głównym powodem, dla którego Arduino odnosi takie sukcesy, jest łatwa w użyciu biblioteka abstrakcji sprzętu, jeśli przeciwstawiasz się funkcjom bibliotek, nieco się ograniczasz. W każdym razie funkcją komentarzy jest poprawienie odpowiedzi, jeśli masz lepsze rozwiązanie, napisz własną odpowiedź. ;)
geometrikal
7

delay()ma swoje zastosowania, ale w przypadku długich opóźnień nie jest to dobre. Mówi po prostu mikrokontrolerowi, aby nic nie robił dla xcykli zegara. W tym czasie Twoje Arduino nie może zrobić nic więcej.

Najlepszym rozwiązaniem byłoby użycie zegara czasu rzeczywistego (RTC). Te chipy są specjalnie zaprojektowane, aby śledzić czas, i możesz łatwo podłączyć je do swojego Arduino. Oto przykład, jak możesz to zrobić.

Tomek
źródło
+1 - Rozwiązanie RTC jest szczególnie dobre, jeśli chcesz uzyskać większą dokładność niż MCU może ci dać.
Ricardo
1
@ Ricardo - RTC prawdopodobnie nie będzie bardziej dokładna niż MCU z kryształem zegara używającym jednego ze swoich sprzętowych timerów do wyzwalania okresowego przerwania; to, co zazwyczaj dostaje, to śledzenie strat mocy i być może pewna znajomość schematów kalendarza.
Chris Stratton,
1
Afaik uno nie używa kwarcowego rezonatora ceramicznego do swojego zegara, a więc z dużo mniejszą dokładnością niż RTC.
jfpoilpret,
@ChrisStratton - Racja. Punkt wzięty. RTC będzie znacznie lepszą opcją, jeśli OP będzie musiał otworzyć lub zamknąć drzwi o określonej porze dnia.
Ricardo
7

Możesz użyć przerwania watchdoga i uśpić MCU podczas oczekiwania i oszczędzać energię.

Zauważ jednak, że oszczędzasz energię tylko wtedy, gdy Twoja tablica również ją oszczędza. Oznacza to, że zamiast zwykłych regulatorów wyposażonych w najpopularniejsze płyty Arduino, takie jak Uno, musisz mieć regulator niskiego napięcia spoczynkowego. W przeciwnym razie nie ma znaczenia, czy MCU oszczędza energię, jeśli Twoja płyta nie.

Oto kod (nieprzetestowany):

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

Kod, który skopiowałem, pochodzi z tej strony: Low-Power Arduino using the Watchdog Timer .

Ricardo
źródło
1

Czy masz dostęp do snu (bez znaku w ciągu kilku sekund)?

Jeśli nie, pozwoli to na bardzo długie opóźnienie ():

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
źródło
Mógłbym spróbować, jeśli nie uda mi się zdobyć RTC, jak powiedział Tom. Dzięki za pomoc!
Fred Pannekoek,
1

To zadziała:

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

        delay(1000);
        p++;

}
Frank C.
źródło
4
nie najlepsze rozwiązanie, a OP poprosił o 12 godzin, a nie 2 minuty.
Madivad,
1

Po prostu używam pętli, gdy nie chcę robić rzeczy pomiędzy:

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
źródło
4
Wyjaśnienie, w jaki sposób jest to lepsze niż proste delay(43200000).
1
Cóż, na początek łatwiej byłoby zmodyfikować, jak długo chcesz czekać. Wystarczy zmienić liczbę dla każdej godziny, minut i sekund bez konieczności przeliczania na milisekundy.
GeneCode