Atraso muito longo () possível?

9

Estou tentando fazer uma pequena porta de abertura e fechamento que deve abrir ou fechar a cada 12 horas. Fiquei pensando se eu poderia criar um pequeno script em loop com um atraso () por 12 horas, um atraso (43 200 000 000); Eu acho? No entanto, não tenho idéia se isso é possível e / ou recomendável. Algum feedback / alternativas (se necessário) seria bom :)

Fred Pannekoek
fonte
ok, eu acho atraso tem um máximo de 65535 mS, mas agora eu preciso de uma alternativa ...
Fred Pannekoek
4
O tempo em sistemas mais maduros, isolados por MCU, geralmente é feito através da programação de um canal de temporizador de hardware do MCU para disparar uma interrupção periodicamente e, em seguida, contando-os - que permite ao processador fazer outras coisas nesse meio tempo e é cumulativamente tão preciso quanto o relógio de cristal.
Chris Stratton
3
O uso do atraso aumentará um leve erro de sobrecarga. É melhor usar uma interrupção para cronometrar um bom período conhecido e depois contar a partir daí. Aqui está uma prova de conceito no meu site pessoal: blog.linformatronics.nl/213/electronics/…
jippie
11
Se não tiver que ser perfeitamente cronometrado, você pode usar coisas não convencionais, como um sensor de luz para sentir a manhã e a noite.
O cara com o chapéu
sim, eu pensei sobre isso, no entanto eu só tenho uma pequena parte detector de luz e eu não tenho certeza de como protegê-lo contra o tempo (a pequena porta está fora)
Fred Pannekoek

Respostas:

10

O método do relógio em tempo real é a maneira mais precisa, mas caso contrário, use millis

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

Isso atrasará até aprox. 4294967295ms (2 ^ 32-1) ou 49 dias, após os quais o cronômetro alcançará o valor destartMillis

geometrikal
fonte
11
O que há de errado em apenas usar delay(LONG_DELAY_MS)? A implementação do arduino aceita longos não assinados. Eu também não estou inteiramente certeza de que o código funciona corretos quando millis()envolve, e é menor do questartMillis
Gerben
O atraso torna o seu arduino completamente inativo enquanto aguarda se estou correto. Eu não sei como isso vai agir quando millis voltar ao 0. #
Fred Pannekoek
@ Gerben coisas boas, colocá-lo como resposta!
geometrikal
2
O estouro do @FredPannekoek funcionará bem, desde que seja usado o tempo não assinado .
geometrikal
11
@ 23ars A principal razão pela qual o Arduino é tão bem-sucedido é sua biblioteca de abstração de hardware fácil de usar; se você é contra funções de bibliotecas, está se limitando um pouco. De qualquer forma, a função dos comentários é melhorar a resposta; se você tiver uma solução melhor, escreva sua própria resposta. ;)
geometrikal
7

delay()tem seus usos, mas por longos atrasos não é bom. Simplesmente diz ao microcontrolador que não faça nada pelos xciclos do relógio. Durante esse período, o seu Arduino não pode fazer mais nada.

Sua melhor aposta seria usar uma coisa chamada Real Time Clock (RTC). Esses chips são feitos especificamente para acompanhar o tempo e você pode conectá-los ao seu Arduino com facilidade. Aqui está um exemplo de como você pode fazer isso.

Tom
fonte
+1 - A solução RTC é especialmente boa se você deseja mais precisão do que o MCU pode fornecer.
Ricardo
11
@ Ricardo - é provável que um RTC não seja mais preciso que um MCU com um relógio de cristal usando um de seus temporizadores de hardware para disparar uma interrupção periódica; o que geralmente você obtém é rastrear perdas de energia e talvez algum conhecimento de esquemas de calendário.
Chris Stratton
11
O Afaik uno não usa um ressonador de cerâmica para o relógio, com um pouco de quartzo, com muito menos precisão do que um rtc.
precisa saber é o seguinte
@ChrisStratton - Certo. Ponto tomado. O RTC será uma opção muito melhor se o OP tiver que abrir ou fechar a porta a uma determinada hora do dia.
Ricardo
7

Você pode usar a interrupção do watchdog e fazer com que o MCU durma enquanto aguarda e economize energia.

Mas observe que você só economizará energia se sua placa também a economizar. Isso significa que você precisa ter um regulador de tensão quieta baixa em vez dos reguladores usuais que equipam as placas Arduino mais comuns, como a Uno. Caso contrário, não importa se o seu MCU economiza energia se a sua placa não.

Aqui está o código (não testado):

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

O código que copiei é desta página: Arduino de baixa potência usando o timer do Watchdog .

Ricardo
fonte
1

Você tem um sono (segundos não assinados) disponível?

Caso contrário, você poderá atrasar () muito tempo:

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
fonte
Eu poderia tentar isso se não conseguir um rtc como o Tom disse. Obrigado por ajudar!
precisa
1

Isso funcionará:

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

        delay(1000);
        p++;

}
Frank C
fonte
4
não é a melhor solução e o OP pediu 12 horas, não 2 minutos.
Madivad
1

Eu apenas uso para loops quando não quero fazer coisas no meio:

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
fonte
4
Explicando como isso é melhor do que um simples delay(43200000).
11
Bem, para iniciantes, seria mais fácil modificar por quanto tempo você deseja esperar. Basta alterar o número para cada hora, minutos e segundos sem precisar converter em milissegundos.
GeneCode