Délai très long () possible?

9

J'essaie de faire une petite porte qui s'ouvre et se ferme qui devrait s'ouvrir ou se fermer toutes les 12 heures. Je me demandais si je pouvais juste faire un petit script en boucle avec un delay () pendant 12 heures, delay (43 200 000 000); J'imagine? Cependant, je n'ai aucune idée si c'est possible et / ou recommandable. Certains commentaires / alternatives (si nécessaire) seraient bien :)

Fred Pannekoek
la source
ok, je pense que le retard a un maximum de 65535 µs, mais maintenant j'ai besoin d'une alternative ...
Fred Pannekoek
4
Le chronométrage dans des systèmes plus matures et MCU seuls se fait généralement en programmant un canal de temporisation matérielle du MCU pour déclencher une interruption périodiquement, puis en les comptant - ce qui permet au processeur de faire d'autres choses entre-temps et est cumulativement aussi précis que le cristal d'horloge.
Chris Stratton
3
L'utilisation du délai agrandit une très légère erreur de surcharge. Il vaut mieux utiliser une interruption pour chronométrer une bonne période connue et ensuite compter à partir de là. Voici une preuve de concept sur mon site personnel: blog.linformatronics.nl/213/electronics/…
jippie
1
S'il ne doit pas être parfaitement synchronisé, vous pouvez utiliser des choses non conventionnelles, comme un capteur de lumière pour détecter le matin et le soir.
The Guy with The Hat
oui, j'y ai pensé, mais je n'ai qu'une petite partie de détecteur de lumière et je ne sais pas comment la protéger des intempéries (la petite porte est à l'extérieur)
Fred Pannekoek

Réponses:

10

La méthode d'horloge en temps réel est le moyen le plus précis, mais sinon, utilisez millis

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

Cela retardera jusqu'à env. 4294967295ms (2 ^ 32-1) ou 49 jours, après quoi la minuterie rattrapera la valeur destartMillis

geometrikal
la source
1
Qu'est-ce qui ne va pas avec l'utilisation delay(LONG_DELAY_MS)? L' implémentation Arduino accepte les longs non signés. Je ne suis pas non plus tout à fait sûr que votre code fonctionne correctement lorsqu'il se millis()termine et est plus petit questartMillis
Gerben
Le retard rend votre arduino complètement inactif en attendant que je me trompe. Je ne sais pas comment cela agira lorsque millis sera de retour à 0.
Fred Pannekoek
@Gerben bonnes choses, mettez-le comme réponse!
geometrikal
2
Le débordement de @FredPannekoek fonctionnera bien, tant que le long non signé est utilisé.
geometrikal
1
@ 23ars La principale raison du succès d'Arduino est sa bibliothèque d'abstraction matérielle facile à utiliser, si vous êtes contre les fonctions des bibliothèques, vous vous limitez quelque peu. Quoi qu'il en soit, la fonction des commentaires est d'améliorer la réponse, si vous avez une meilleure solution, écrivez votre propre réponse. ;)
geometrikal
7

delay()a ses utilisations, mais pour de longs retards ce n'est pas bon. Il indique simplement au microcontrôleur de ne rien faire pour les xcycles d'horloge. Pendant ce temps, votre Arduino ne peut rien faire d'autre.

Votre meilleur pari serait d'utiliser une chose appelée horloge en temps réel (RTC). Ces puces sont spécialement conçues pour garder une trace du temps, et vous pouvez les connecter à votre Arduino en toute simplicité. Voici un exemple de la façon dont vous pouvez le faire.

À M
la source
+1 - La solution RTC est particulièrement bonne si vous voulez plus de précision que ce que le MCU peut vous donner.
Ricardo
1
@Ricardo - un RTC n'est probablement pas plus précis qu'un MCU avec un cristal d'horloge utilisant l'un de ses temporisateurs matériels pour déclencher une interruption périodique; ce qu'il vous apporte généralement, c'est le suivi de la perte de puissance et peut-être une certaine connaissance des schémas de calendrier.
Chris Stratton
1
Afaik uno n'utilise pas de mors à quartz comme résonateur céramique pour son horloge, donc avec beaucoup moins de précision qu'un rtc.
jfpoilpret
@ChrisStratton - À droite. Point pris. Le RTC sera une bien meilleure option si le PO doit ouvrir ou fermer la porte à une heure donnée de la journée.
Ricardo
7

Vous pouvez utiliser l'interruption du chien de garde et faire dormir votre MCU en attendant et économiser de l'énergie.

Mais notez que vous n'économiserez de l'énergie que si votre carte le sauvegarde également. Cela signifie que vous devez avoir un régulateur de tension de repos faible au lieu des régulateurs habituels qui équipent les cartes Arduino les plus courantes, telles que l'Uno. Sinon, peu importe si votre MCU économise de l'énergie si votre carte ne le fait pas.

Voici le code (non testé):

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

Le code que j'ai copié provient de cette page: Arduino basse consommation utilisant la minuterie de surveillance .

Ricardo
la source
1

Avez-vous un sommeil (int secondes non signé) disponible?

Sinon, cela vous permettrait de retarder () très longtemps:

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
la source
Je pourrais essayer ceci si je n'arrive pas à obtenir un rtc comme Tom l'a dit. Merci pour ton aide!
Fred Pannekoek
1

Cela fonctionnera:

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

        delay(1000);
        p++;

}
Frank C
la source
4
pas la meilleure solution et le PO a demandé 12 heures, pas 2 minutes.
Madivad
1

J'utilise juste des boucles quand je ne veux pas faire de trucs entre les deux:

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
la source
4
Expliquant en quoi c'est mieux qu'un simple delay(43200000).
1
Eh bien, pour commencer, il serait plus facile de modifier la durée d'attente. Modifiez simplement le nombre pour chaque heure, minute et seconde sans avoir besoin de convertir en millisecondes.
GeneCode