LOCODUINO

Comment gérer le temps dans un programme ?

Et comment faire plusieurs tâches simultanément

.
Par : Dominique, Guillaume, Jean-Luc

DIFFICULTÉ :

Dès vos premières applications, vous avez pu constater que la gestion du temps revient très fréquemment dans la programmation des diverses applications qui nous concernent. Cela va de choses simples comme les animations lumineuses à base de DEL comme dans « Chenillard de DEL » ou « Enseigne de magasin » ou bien l’envoi d’une impulsion de durée déterminée à un moteur d’aiguillage électromagnétique, par exemple, à des choses plus complexes comme la détection du début et de la fin du passage d’un train avec un capteur infrarouge en distinguant les intervalles entre les wagons qui génèrent des impulsions courtes et la fin du passage qui génère une impulsion d’une longueur qui dépend du moment où un autre train va se présenter.

Nous avons déjà vu dans l’exemple de programme à la fin de « La programmation, qu’est ce que c’est » le clignotement d’une DEL. Pour rappel, la fonction loop() intiale était comme ceci :

void loop() {
  digitalWrite(13, HIGH);
  digitalWrite(13, LOW);
}

La broche 13 correspondant à la DEL qui se trouve sur toutes les cartes Arduino. Dans ce cas, l’exécution est si rapide que nos yeux ne voient pas le clignotement de la DEL [1].

Supposons une animation de travaux avec un feu qui flashe toutes les secondes. Comment incorporer ce laps de temps dans le programme précédent ?.

En première approche, nous cherchons à faire des choses simples et nous allons naturellement nous tourner vers la fonction delay(...).

La fonction delay(...)

Cette première fonction est simple. Comme son nom l’indique, elle ajoute un délai pendant lequel la carte arduino marque une pause dans l’exécution du code. Entre parenthèses, unique argument de la fonction, se place le temps de la pause dont l’unité est la milliseconde. Ce qui ajouté au programme donne :

void loop() {
  digitalWrite(13, HIGH);
  delay(20);
  digitalWrite(13, LOW);
  delay(980);
}

et ainsi la DEL émet un flash de 20ms toutes les secondes.

Si nous voulons une pause plus précise que la milliseconde, il existe la fonction delayMicroseconds(...). Entre parenthèses se place le temps en microsecondes.

L’inconvénient majeur de ces deux fonctions est que pendant le temps spécifié, la carte est bloquée, elle ne peut pas continuer l’exécution du programme. Or, par exemple, de nombreuses tâches nécessitent une lecture fréquente des broches programmées en entrée : détection de train, lecture d’un bouton poussoir.

Nous allons prendre un exemple de la vie de tous les jours pour illustrer le propos. Imaginez que vous avez à mener de front deux tâches : faire cuire un œuf à la coque et guetter le facteur pour lui remettre une lettre qui ne vous est pas destiné. Si vous restez planté devant la pendule pour minuter l’œuf à la coque, vous raterez le facteur. C’est ce que l’on fait en utilisant delay(...), on attend devant la pendule et on ne fait rien d’autre. Si vous restez planté devant la fenêtre à guetter le facteur, votre œuf sera trop cuit.

L’autre solution consiste à jeter régulièrement un œil à la pendule tout en guettant le facteur. Si le temps de cuisson de l’œuf est atteint, on le sort de l’eau. De cette manière il est possible de faire deux choses presque en même temps.

Nous allons donc voir maintenant cette autre fonction qui permet de jeter un œil à la pendule.

La fonction millis()

La fonction millis() renvoie une date [2] qui est le nombre de millisecondes qui se sont écoulées depuis la mise sous tension ou le dernier reset. Contrairement à delay(...), cette fonction n’est pas bloquante [3], elle permet juste de jeter un œil à la pendule. Il faut ensuite utiliser la date pour décider de ce que le programme doit faire.

Reprenons l’exemple simple de la DEL clignotante. Utilisons tout d’abord une variable pour mémoriser l’état de la DEL et une variable pour mémoriser la date du dernier changement d’état de la DEL. Comme millis() renvoie une valeur de type unsigned long [4], cette date est un unsigned long initialisé à 0 :

byte etatDEL = HIGH;
unsigned long dateDernierChangement = 0;

Ensuite, dans loop(), nous allons jeter un œil à la pendule en appelant la fonction millis() et stocker son résultat dans une variable dateCourante. Ensuite, nous allons calculer l’intervalle de temps en soustrayant dateDernierChangement à dateCourante puis, selon l’état de la DEL et l’intervalle de temps, décider si on doit l’allumer ou l’éteindre. Enfin, si un changement d’état de la DEL a eu lieu, il faut mémoriser dans dateDernierChangement la date de l’événement de manière à pouvoir calculer le prochain intervalle :

void loop()
{
  unsigned long dateCourante = millis();
  unsigned long intervalle = dateCourante - dateDernierChangement;

  if (etatDEL == HIGH && intervalle > 20) {
    // extinction de la DEL car elle est allumee (HIGH) et 20ms se sont écoulées
    etatDEL = LOW;
    digitalWrite(13, etatDEL);
    dateDernierChangement = dateCourante;
  }
  else if (etatDEL == LOW && intervalle > 980) {
    // allumage de la DEL car elle est éteinte (LOW) et 980ms se sont écoulées
    etatDEL = HIGH;
    digitalWrite(13, etatDEL);
    dateDernierChangement = dateCourante;
  }
}

Pour l’instant, le progrès n’est pas spectaculaire. On a écrit plus de code mais le programme fait exactement la même chose. Ajoutons maintenant une seconde DEL avec un cycle d’allumage différent. On va gérer simultanément les deux DEL. On appelle cela du multiplexage. Cette seconde DEL est connectée sur la broche 12 et s’allume lorsque cette broche est HIGH. Elle va être allumée pendant 100ms et éteinte pendant 200ms. Pour savoir comment raccorder une DEL, reportez vous à « Fonctionnement et pilotage d’une DEL ».

Nous allons avoir besoin de deux fois plus de variables puisque nous avons maintenant deux DEL. Voici les déclarations de ces variables dont les noms sont suffixés par le numéro de broche de la DEL concernée.

byte etatDEL13 = HIGH;
byte etatDEL12 = HIGH;
unsigned long dateDernierChangement13 = 0;
unsigned long dateDernierChangement12 = 0;

Pour clarifier le programme, nous allons créer deux fonctions. La première va gérer la DEL de la broche 13 et la seconde va gérer la DEL de la broche 12.

Voici pour commencer la fonction qui gère la DEL de la broche 13, c’est un simple copier-coller du code qui est dans loop() ci-dessus :

void flashDEL13()
{
  unsigned long dateCourante = millis();
  unsigned long intervalle = dateCourante - dateDernierChangement13;

  if (etatDEL13 == HIGH && intervalle > 20) {
    // extinction de la DEL car elle est allumée (HIGH) et 20ms se sont écoulées
    etatDEL13 = LOW;
    digitalWrite(13, etatDEL13);
    dateDernierChangement13 = dateCourante;
  }
  else if (etatDEL13 == LOW && intervalle > 980) {
    // allumage de la DEL car elle est éteinte (LOW) et 980ms se sont écoulées
    etatDEL13 = HIGH;
    digitalWrite(13, etatDEL13);
    dateDernierChangement13 = dateCourante;
  }
}

La seconde fonction, flashDEL12() est similaire. Seules changent les intervalles, les variables de mémorisation de l’état de la DEL et de la date du dernier changement et, bien sûr, la broche :

void flashDEL12()
{
  unsigned long dateCourante = millis();
  unsigned long intervalle = dateCourante - dateDernierChangement12;

  if (etatDEL12 == HIGH && intervalle > 100) {
    // extinction de la DEL car elle est allumée (HIGH) et 100ms se sont écoulées
    etatDEL12 = LOW;
    digitalWrite(12, etatDEL12);
    dateDernierChangement12 = dateCourante;
  }
  else if (etatDEL12 == LOW && intervalle > 200) {
    // allumage de la DEL car elle est éteinte (LOW) et 200ms se sont écoulées
    etatDEL12 = HIGH;
    digitalWrite(12, etatDEL12);
    dateDernierChangement12 = dateCourante;
  }
}

Enfin, dans loop(), nous allons appeler les deux fonctions que nous venons de voir.

void loop()
{
  flashDEL13();
  flashDEL12();
}

Voici une vidéo montrant l’exécution de ce programme

Voici également le programme à télécharger :

multiplex.ino
Programme de multiplexage de deux clignotements simultanés de DEL.

Le programme n’est pas d’une grande élégance. Les deux fonctions ne diffèrent que par les variables utilisées. On pourrait tout à fait ajouter les variables utilisées en argument pour n’avoir qu’une fonction mais une solution encore plus élégante est d’utiliser des objets. Nous verrons ultérieurement comment s’y prendre.

Pour terminer, il existe également une fonction micros() qui donne la date en microsecondes. Cette fonction renvoie également une donnée de type unsigned long.

Il est aussi possible de gérer le temps via les timers. Pour en savoir plus, lisez « Les Timers (I) »

[1Mesuré à l’oscilloscope, le temps qui s’écoule entre la mise à HIGH de la sortie 13 et la mise à LOW est de 3,94µs et le temps qui s’écoule entre la mise à LOW et la mise à HIGH est de 4,56µs.

[2date dans le sens instant précis dans le temps et non date calendaire.

[3L’exécution ne se bloque pas en attendant que le temps passe.

[4La date maximum est donc 4294967295 millisecondes, soit un peu plus de 1193 heures, soit un peu plus de 49 jours.

65 Messages

  • Comment gérer le temps dans un programme ? 14 janvier 2015 16:25, par Stéphane

    je sens que c’est pile ce que je veux essayer de faire pour mon réseau. Avec votre aide, plus celle du forum LRPresse les idées se mettent en place.
    Merci à tous.

    Répondre

  • Comment gérer le temps dans un programme ? 14 janvier 2015 16:26, par Stéphane

    Et j’attends impatiemment la suite avec les objets ;-)

    Répondre

  • Comment gérer le temps dans un programme ? 26 janvier 2015 10:42, par petitrain

    Bonjour à toute l’équipe
    Bravo pour ce blog et toute l’aide que vous apportez.J’ai suivi avec grand intérêt cet article sur le temps. J’essaie de faire une fonction pour gérer la pwm sans delay mais sans succés.
    Pouvez-vous m’aiguiller pour me dire pourquoi ça ne va pas
    Je voudrais que les deux leds aient une progression ensemble, bien sur à des rythmes différents.
    Dans la loop, Arduino n’exécute que le premier appel de la fonction, si je mets un // devant, alors il exécute le deuxième appel.
    Merci pour votre aide.

    byte x=0;                                                 
    unsigned long tempsPresent;                              
     
    void monteeEclairage(byte numeroBroche,int interval){     
      if(millis()>=tempsPresent+interval){                      
        tempsPresent= tempsPresent+interval;                  
        analogWrite(numeroBroche,x);                           
        x=x+1;
      }
    }
     
    void setup(){
      pinMode(3,OUTPUT);
      pinMode(5,OUTPUT);
      unsigned long tempsPresent=0;
    }
     
    void loop(){
      monteeEclairage(3,100);
      monteeEclairage(5,200);
    }

    Répondre

    • Comment gérer le temps dans un programme ? 26 janvier 2015 10:59, par Guillaume

      Bonjour,
      quand tu veux faire appel à deux fonctions distinctes utilisant millis(), il te faut stocker le temps dans 2 variables différentes.
      Car dans ton cas seule la 1ère fonction avec les paramètres est exécutée entièrement, temps est "remis à 0" et la condition dans la 2ème fonction n’attend jamais 200.

      Dans ton programme aussi, j’avoue que je ne sais pas comment analogWrite gère le x sup à 255. Rajoute peut être une condition pour dire stop ou pour faire repartir au début.

      Une petite suggestion : introduis des constantes pour désigner tes broches.

      Répondre

      • Comment gérer le temps dans un programme ? 26 janvier 2015 15:28, par Jean-Luc

        Bonjour et merci :)

        Guillaume a raison. Le problème vient de la variable tempsPresent qui est utilisée pour les deux DEL. Lors du 2e appel à la fonction : monteeEclairage(5,200);, millis()>=tempsPresent+interval est toujours faux puisque tempsPresent vient juste d’être changé par l’appel précédent. Donc tout se passe comme si le 2e appel n’avait pas d’effet. De manière général l’appel avec l’intervalle le plus court fonctionnera bien, les autres non.

        Il faut donc une variable par DEL.

        C’est un peu compliqué car la fonction doit pouvoir changer cette variable. Il faut donc passer un pointeur ou une référence. Essayez comme ceci :

        byte x=0;                                                 
        unsigned long tempsPresentDEL3 = 0;                              
        unsigned long tempsPresentDEL5 = 0;                              
        
        /*
         * le & après le unsigned long indique que l'argument tempsPresent
         * est passé par référence. Si tempsPresent est modifié dans la fonction,
         * la variable passée en argument sera modifiée
         */
        void monteeEclairage(byte numeroBroche,int interval, unsigned long& tempsPresent)
        {     
          if(millis()>=tempsPresent+interval){                      
            tempsPresent= tempsPresent+interval;                  
            analogWrite(numeroBroche,x);                           
            x=x+1;
          }
        }
         
        void setup(){
          pinMode(3,OUTPUT);
          pinMode(5,OUTPUT);
        }
         
        void loop(){
          monteeEclairage(3, 100, tempsPresentDEL3);
          monteeEclairage(5, 200, tempsPresentDEL5);
        }

        Concernant la variable x, elle est de type byte. Sa valeur maximum est donc 255. Quand elle est augmentée de 1 alors qu’elle est à 255, elle repasse à 0.

        Répondre

  • Comment gérer le temps dans un programme ? 26 janvier 2015 17:12, par petitrain

    Merci à tous les deux pour vos réponses rapides et précises.
    J’en étais presque arrivé à la bonne formulation après la réponse de Guillaume mais il me manquait le & après le 3ème paramètre de ma fonction (manque de connaissance !!!).
    A guillaume : effectivement ma variable est une byte donc débordement...
    pour les constantes de broches, je voulais faire voir aux personnes de mon club quelles n’étaient pas obligatoires et expliquer l’intérêt de les déclarer au début ; j’ai pris l’habitude de mettre des commentaires quand le programme tourne bien.
    Encore merci à vous deux.

    Répondre

  • Comment gérer le temps dans un programme ? 8 février 2015 12:09, par Doxy

    Bonjour et bravo pour cet article sur la fonction millis
    La fonction Delay m’avait déçu ; certes elle m’avait permis de faire un montage sympas mais impossible à ma carte Arduino de faire autre chose en même temps ; http://forum.e-train.fr/viewtopic.p...;; j’ai bien l’intention de m’y remettre pour d’autre éclairage.

    Répondre

  • Comment gérer le temps dans un programme ? 4 août 2016 17:29, par Précillia

    Bonjour à tous,

    Merci pour cet article qui m’a déjà pas mal aidé !
    Je souhaiterai contrôler l’allumage ou l’extinction de 5 LEDs de couleurs différentes (UV, bleu, vert, orange et rouge) tout en contrôlant leur intensité d’éclairement (PWM wave).

    Par exemple,
    en premier je souhaiterai que les LEDs s’allument avec les valeurs suivantes pendant 1min :
    UV = 0
    BLEU = 0
    VERT = 0
    ORANGE = 0
    ROUGE = 125
    (Donc ici, seule la rouge est allumée)

    Ensuite toutes les éteindre pendant 2 min

    Puis pendant 1min :
    UV = 0
    BLEU = 0
    VERT = 75
    ORANGE = 2
    ROUGE = 10

    Etc...et j’en ai d’autres.

    J’avais pensé utiliser le code suivant :

    int uv = 13;          
    int bleu = 3;          
    int vert = 11;          
    int orange = 10;          
    int rouge = 9;
    
    byte etatDELUV = 0;
    byte etatDELBLEU = 0;
    byte etatDELVERT = 0;
    byte etatDELORANGE = 0;
    byte etatDELROUGE = 125;
    
    unsigned long dateDernierChangementUV = 0;
    unsigned long dateDernierChangementBLEU = 0;
    unsigned long dateDernierChangementVERT = 0;
    unsigned long dateDernierChangementORANGE = 0;
    unsigned long dateDernierChangementROUGE = 0;
    
    
    
    void setup() {
      pinMode(uv, OUTPUT);
      pinMode(bleu, OUTPUT);
      pinMode(vert, OUTPUT);
      pinMode(orange, OUTPUT);
      pinMode(rouge, OUTPUT);
    
    }
    
    
    void UV()
        {
          unsigned long dateCourante = millis();
          unsigned long intervalle = dateCourante - dateDernierChangementUV;
         
          if (etatDELUV == 0 && intervalle > 720000) {
            etatDELUV = 125;
            analogWrite(uv, etatDELUV);
            dateDernierChangementUV = dateCourante;
          }
          else if (etatDELUV == 125 && intervalle > 60000) {
            etatDELUV = 0;
            analogWrite(uv, etatDELUV);
            dateDernierChangementUV = dateCourante;
          }
           else if (etatDELUV == 0 && intervalle > 120000) {
            etatDELUV = 250;
            analogWrite(uv, etatDELUV);
            dateDernierChangementUV = dateCourante;
          }
    
        }
    
    
    void BLEU()
        {
          unsigned long dateCourante = millis();
          unsigned long intervalle = dateCourante - dateDernierChangementBLEU;
         
          if (etatDELBLEU == 0 && intervalle > 540000) {
               etatDELBLEU = 50;
            analogWrite(bleu, etatDELBLEU);
            dateDernierChangementBLEU = dateCourante;
          }
          else if (etatDELBLEU == 50 && intervalle > 60000) {
                 etatDELBLEU = 0;
            analogWrite(bleu, etatDELBLEU);
            dateDernierChangementBLEU = dateCourante;
          }
           else if (etatDELBLEU == 0 && intervalle > 120000) {
               etatDELBLEU = 50;
            analogWrite(bleu, etatDELBLEU);
            dateDernierChangementBLEU = dateCourante;
          }
    else if (etatDELBLEU == 50 && intervalle > 60000) {
            etatDELBLEU = 0;
            analogWrite(bleu, etatDELBLEU);
            dateDernierChangementBLEU = dateCourante;
          }
    else if (etatDELBLEU == 0 && intervalle > 120000) {
            etatDELBLEU = 100;
            analogWrite(bleu, etatDELBLEU);
            dateDernierChangementBLEU = dateCourante;
          }
        }

    etc ... pour toutes les LEDs

    puis enfin :

    void loop() {
     UV();
     BLEU();
     VERT();
     ORANGE();
     ROUGE();
    }

    Mais malheureusement, certaines LEDs s’allument mais pas dans l’ordre que je souhaite...
    Je ne m’y connais pas assez en programmation pour savoir d’où vient mon erreur, et si j’utilise les bonnes fonctions.

    Pourriez-vous m’aider ? ou me renvoyer vers une explication ?
    Merci beaucoup !

    Répondre

    • Comment gérer le temps dans un programme ? 6 août 2016 15:00, par Dominique

      Je pense comme Jean-Luc que votre programmation est du type "à donner des résultats imprévisibles" !

      Pour vous répondre directement, il faudrait réaliser le montage et tester le logiciel en ajoutant des affichages des états sur le moniteur.

      Cette piste vous conduirait à programmer autrement. Des automates de ce genre existent en exemple un peu partout. Sur Locoduino, la bibliothèque ScheduleTable est là pour cela. Elle vous donnera des instants déterminés et remettra vos événements en ordre.

      Bon courage.

      Répondre

      • Comment gérer le temps dans un programme ? 13 décembre 2022 16:24, par Phil

        bonjour Dominique
        je suis heureux que vous parliez et répondiez en FRANÇAIS pour certaine personne et en plus "Bon courage" pour ce Monsieur, quel honneur !!!! alors que moi j’ai terminé mon message par "Amicalement". et aucune marque de civilité, avec une réponse en ANGLAIS, par contre Jean-Luc m’a répondu en FRANÇAIS et a terminé sa réponse par "cordialement".
        il a peut-être plus d’éducation que vous ????
        et si cela vous dérangeait de répondre à ma question "basique", il fallait, vous en dispenser, cela vous aurait dispensé de mes commentaires.
        il faut peut-être prendre les à leur niveau et descendre de votre nuage de je sais TOUT.
        si les questions posées ne semblent pas de votre niveau, laissez d’autres plus sympa y répondre.
        en plus Jean-Luc m’a mis un lien.
        au plaisir de ne plus vous lire.
        PS : mon mail concernait la signification de while(!) pour info.
        "si tous les animateurs étaient comme vous, le site aurait très mauvaise presse".
        Amicalement
        Phil

        Répondre

  • Comment gérer le temps dans un programme ? 4 août 2016 17:34, par Jean-Luc

    Bonjour,

    Quand ça devient trop compliqué, on s’y perd. Peut-être devriez vous essayer la La bibliothèque ScheduleTable que j’ai réalisée pour précisément faciliter ce type de programmation.

    Répondre

  • Une petite remarque concernant la fonction micros() : elle a, selon les cartes Arduino (et aussi, apparemment, sur les ATtiny85 et sans doute d’autres), une résolution de quatre ou huit microsecondes (c’est-à-dire que la fonction retourne toujours un multiple de quatre ou huit ; cf. le lien joint pour les cartes Arduino ; pour les ATtiny je ne sais pas où on peut trouver cette info mais cela semble également valable…).
    Sur certains programmes cela peut avoir son importance… Par exemple dans un programme tournant sur un attiny85 où j’avais besoin d’un nombre plus ou moins aléatoire entre 1 et 6, je l’obtenais en calculant, à chaque fois que j’appuyais sur un bouton : (micros() % 6 + 1)). Et je ne comprenais pas pourquoi je n’obtenais que des nombres impairs !
    Bonne journée !

    Voir en ligne : https://www.arduino.cc/reference/en...

    Répondre

    • Comment gérer le temps dans un programme ? 11 mai 2018 09:20, par Jean-Luc

      Bonjour,

      effectivement la résolution de micros() varie selon le microcontrôleur. Sur un ATMega 328 (Uno), par exemple, elle est basée sur le Timer 0 qui fait un tour en 256 ticks et 1024 microsecondes. Par conséquent le tick vaut 4μs et on ne peut pas avoir une mesure de temps plus fine à moins d’utiliser un autre Timer pour le faire.

      Répondre

  • Comment gérer le temps dans un programme ? 3 mars 2019 13:44, par Lionel

    Bonjour,
    Personnellement j’ai résolu ce problème en utilisant un compteur.
    A chaque loop j’incrémente ce compteur avec une pause de 1 sec, ce qui permet pendant ce temps de contrôler les autres entrées.

    int reset = 8 ; // sortie reset
    int capteur = 2 ; // entrée capteur
    int appelHaut = 9 ; //sortie appel extrème haut
    int inspection = 3 ; // entree commande inspection
    int compteur ;

    void setup()

    pinMode(inspection, INPUT_PULLUP) ;
    pinMode(capteur, INPUT_PULLUP) ;
    pinMode(reset, OUTPUT) ;
    pinMode(appelHaut, OUTPUT) ;
    compteur = 0 ;

    void loop()

    if (digitalRead (capteur) == HIGH or digitalRead (inspection) == LOW)
    compteur = 0 ;

    if (digitalRead (capteur) == LOW)
    compteur ++ ;

    delay (1000) ;
    if (compteur == 10)

    digitalWrite (reset, HIGH) ;
    delay (1000) ;
    digitalWrite (reset, LOW) ;
    delay (1500) ;
    digitalWrite (appelHaut, HIGH) ;
    delay (1000) ;
    digitalWrite (appelHaut, LOW) ;

    Répondre

  • Comment gérer le temps dans un programme ? 17 mars 2019 20:38, par PECOURT Jean-Louis

    Bonsoir,
    Je désirerais une petite précision. Il y a des choses qui rentrent (en se creusant un peu la tête...) ; mais d’autres où cela coince...
    Dans ce logiciel, il y a deux déclarations en Byte (byte etatDEL13 = HIGH et identique pour l’autre sortie).
    Pourquoi Byte et pas Boolean, qui serait - à mon sens - plus logique ?
    Un booléen peut être vrai/faux ou haut/bas ou 1/0. Mais le Byte est un octet, et (pour ce que j’en ai compris), correspond à une valeur numérique.
    Bon d’accord, le programme marche dans les deux cas. Mais si on peut utiliser des bytes pour des booléens, quel est l’intérêt de ce type de donnée ?
    Cordialement.
    J.L.

    Répondre

    • Comment gérer le temps dans un programme ? 17 mars 2019 22:40, par Jean-Luc

      Bonsoir, il y a deux réponses à cette question. Tout d’abord le C est assez basique en ce qui concerne le typage et les booléens n’existent pas vraiment, ce sont en réalité des entiers sur un octet. Ensuite l’état d’un broche, HIGH ou LOW, n’est pas un booléen mais un octet.

      Répondre

  • Comment gérer le temps dans un programme ? 15 février 2020 14:06, par Fabien

    Bonjour !
    Merci pour cet article très clair.
    J’ai cependant une question.
    Du fait de la boucle sans fin ni pause, le CPU de l’arduino ne va t’il pas être en permanence à 100% et donc chauffer ?
    A+
    Fabien

    Répondre

  • Comment gérer le temps dans un programme ? 15 février 2020 19:47, par Fabien

    Effectivement si le cpu à 100% est bien refroidi il ne devrait pas y avoir de problème à part une consommation électrique elle aussi au max.
    Au cas où la carte arduino serait mal ventilée et/ou sans radiateur il faut faire attention.
    Personnellement l’introduirais tout de même une petite tempo dans la boucle pour ne pas la laisser à fond.

    Répondre

    • Comment gérer le temps dans un programme ? 15 février 2020 20:28, par msport

      Je pense que vous transposez ici les problèmes de température des processeurs d’ordinateurs qui consomment des dizaines de watts.

      La figure 35-2. de la fiche technique de l’ATmega328P donne une consommation de 5 mA sous 5V à 8MHz soit 25mW en mode actif. (et aucune différence suivant les instructions exécutées).

      La difficulté est plutôt d’avoir un programme qui marche et comme le dit l’article que vous signaliez il vaut mieux que le processeur reste actif en permanence puisque nous sommes en temps réel.

      Répondre

  • Comment gérer le temps dans un programme ? 11 mars 2020 11:43, par AMARA Yazid

    Bonjour,

    Je dois écrire un programme dans lequel je dois déterminer la moyenne de clics sur le bouton poussoir par seconde. Mon problème c’est que je sais pas comment identifier le temps(la durée) entre le premier et le dernier clic.

    Je dois calculer nombre de clics/intervalle de temps entre premier et dernier clic

    Merci pour votre aide.

    Répondre

  • Comment gérer le temps dans un programme ? 11 mars 2020 12:55, par msport

    LOCODUINO est consacré aux discussions ayant trait à l’utilisation de l’Arduino dans les automatismes et les animations pour le train miniature. Si vos questions ne concernent pas le modélisme ferroviaire, vous perdez votre temps et nous aussi.
    Par ailleurs, vous avez la réponse à vos questions dans l’article à travers les exemples donnés.

    Répondre

  • Comment gérer le temps dans un programme ? 19 novembre 2020 13:23, par Etienne

    Je m’interroge sur la portée des variables dan votre exemple.

    La variable dateDernierChangementUV n’est pas initialisée la première fois ! Comment pouvez-vous être sur que cette valeur sera inférieure à la valeur retournée pas le fonction millis() la première fois. Est-ce que toutes les variables sont initialisée à 0 au démarrage ?
    J’avais cru comprendre que le langage était du C ! en retournant dans un fonction, les variable locales ne devraient pas conserver leur valeur (enfin elle le pourrait mais rien ne le garanti).

    Je débute en programmation Arduino, mais je suis assez perplexe !

    Répondre

  • Comment gérer le temps dans un programme ? 19 novembre 2020 17:35, par msport

    Vous posez une question à un intervenant ou à l’auteur ?
    Sauf erreur, par défaut les variables sont initialisées à 0 par l’IDE.
    Avec les Arduino, rien de tel que l’expérimentation, parfois on a des surprises.

    Répondre

  • bonjour, cela fait plusieurs jour que j’essaie de programmer mon stepper moteur. Je veux le faire tourner d’un sens puis de l’autre chaque 2h,durant 18jours.
    pour le moment j’essaie de faire la 1ere partie ( tourner à chaque 2h) , mais cela ne marche pas. s’il vous plait quelqu’un peut m’aider c’est pour mon projet de fin d’etude. merci.
    le code que j’ai fait :

    #include <Stepper.h>
    #define     in1Pin             8
    #define     in2Pin             9
    #define     in3Pin            10
    #define     in4Pin            11
    Stepper motor(50, in1Pin, in2Pin, in3Pin, in4Pin);   
    const long onDuration = 500;// OFF time 
    const long offDuration = 500;// ON time 
    long rememberTime=0;// this is used by the code
    
    
    const int NbrPas =50; 
    Stepper monmoteur(NbrPas, in1Pin, in2Pin, in3Pin, in4Pin);
    
    void setup() {
    monmoteur.step(50);
     Serial.begin(9600);
     pinMode(in1Pin,OUTPUT);
     pinMode(in2Pin,OUTPUT);
     pinMode(in3Pin,OUTPUT);
     pinMode(in4Pin,OUTPUT);
    
     monmoteur.setSpeed(20);  // Vitesse à 10 tours/min
    }
    
    void loop() {
      int j= NbrPas;
      int i=-NbrPas;
      if ( (millis()- rememberTime) >= onDuration  )
      { 
        monmoteur.step(-50);
        rememberTime=millis();// remember Current millis() time
      }
      else 
      {   
        if( (millis()- rememberTime) >= 1000){     
          monmoteur.step(50);
          rememberTime=millis();// remember Current millis() time
        }
      }
    }  

    Répondre

    • Bonjour chère camarades, comment allez-vous ? J’espère que vous allez bien !
      Bon a vrai dire moi aussi je suis confronté au même problème que vous et j’aimerais vous demandez de l’aide vu que ça fait longtemps que vous vous êtes confronter à ceci._

      Répondre

  • Comment gérer le temps dans un programme ? 15 juillet 2021 18:45, par Dominique

    Est-ce un projet de modélisme ferroviaire ? Si oui le debugging de programme se fait plutôt sur le forum.

    Répondre

  • signification de (while !) en début de programme 10 décembre 2022 14:50, par Phil

    Bonjour Messieurs
    pouvez-vous me dire à quoi sert ce fameux (while !) souvent en début de programme dans le setup (), avant ou après :
    "Serial.begin(9600) ;"
    est-il indispensable ???
    Merci
    Amicalement
    Phil

    Répondre

  • (while !) 11 décembre 2022 15:00, par phil

    bonjour Messieurs
    Merci, de votre réactivité mais surtout de votre réponse.
    bonne journée.
    Amicalement.
    Phil

    Répondre

    • (while !) 13 décembre 2022 16:26, par Phil

      bonjour Dominique
      je suis heureux que vous parliez et répondiez en FRANÇAIS pour certaine personne et en plus "Bon courage" pour ce Monsieur, quel honneur !!!! alors que moi j’ai terminé mon message par "Amicalement". et aucune marque de civilité, avec une réponse en ANGLAIS, par contre Jean-Luc m’a répondu en FRANÇAIS et a terminé sa réponse par "cordialement".
      il a peut-être plus d’éducation que vous ????
      et si cela vous dérangeait de répondre à ma question "basique", il fallait, vous en dispenser, cela vous aurait dispensé de mes commentaires.
      il faut peut-être prendre les à leur niveau et descendre de votre nuage de je sais TOUT.
      si les questions posées ne semblent pas de votre niveau, laissez d’autres plus sympa y répondre.
      en plus Jean-Luc m’a mis un lien.
      au plaisir de ne plus vous lire.
      PS : mon mail concernait la signification de while(!) pour info.
      "si tous les animateurs étaient comme vous, le site aurait très mauvaise presse".
      Amicalement
      Phil

      Répondre

      • (while !) 13 décembre 2022 16:51, par Jean-Luc

        Bonjour,
         
        Ma foi, il existe sans doute plusieurs Dominique/dominique par ici. Normalement Dominique est authentifié car il est rédacteur sur Locoduino et donc son prénom n’apparaîtra pas avec un d minuscule.
         
        J’ai donc regardé les IP de Dominique et de dominique. Il se trouve qu’ils n’ont pas la même IP et que l’IP de dominique n’est pas une IP française alors que celle de Dominique l’est.
         
        Par conséquent, il semble que vous ayez confondu les Dominique/dominique, ce qui n’est pas étonnant car ils sont légion.
         
        Et donc on fait quoi de vos invectives à la suite de la réponse de Dominique que vous avez postées là et qui apparaissent comme parfaitement injustifiées (si on peut juger justifié le fait de régler ses comptes dans les forums des articles de Locoduino) ?
         
        Cordialement

        Répondre

      • (while !) 13 décembre 2022 22:03, par Dominique

        Bonjour Phil,
        j’ai vu cette réponse en anglais. Elle provient du site Arduino.cc où tout un chacun peut puiser ses connaissances en complément de Locoduino, en ce qui concerne les questions simples, mais la réponse en anglais se traduit facilement par les nombreux traducteurs disponibles.

        Votre agressivité n’a pas lieu d’être de toute façon et cela me semble pire que ce dont vous vous plaignez.

        Cordialement

        Répondre

        • (while !) 14 décembre 2022 16:18, par Phil

          Bonjour Messieurs

          Jean-Luc et Dominique avec D
          je suis désolé de cette confusion entre D et d car jusqu’à présent je n’avais jamais été confronté à ce genre de problème. A chaque question (cette été),une réponse de Christian ou jean-Luc (avec formule de politesse) mais je ne m’attendais pas à recevoir une réponse en Anglais alors que la question a été posé en français. alors effectivement, il existe des traducteurs (et c’est ce que j’ai fait) mais pourquoi le fameux dominique ne m’a pas répondu en FRANÇAIS ???? (avec un traducteur).

          Bref, déjà merci à Jean-Luc sa réactivité, qui m’a toujours très bien répondu et désolé pour Dominique pour qui mon message et ma colère (visiblement) n’était pas destiné.

          Amicalement.
          Phil

          Répondre

  • Comment gérer le temps dans un programme ? 13 décembre 2022 17:01, par msport

    Bonjour,
    à tout le moins, on peut relire le chapitre sur la convivialité (et pas que) dans le sujet :
    Où et comment demander de l’aide ?
    Cordialement

    Répondre

  • Comment gérer le temps dans un programme ? 8 juin 2023 15:48, par bernard

    bonjour,
    moi mon problème est différent faire clignoter ok ça c’est bon mais je n’arrive pas à faire clignoter par exemple 3 fois une seconde toutes les 20 secondes, je bloque là dessus et ça me fatigue à force. je n’arrive même pas à mettre en brouillon un code car tous ceux que je tente ne fonctionnent pas. avez vous une idée de la manière d’aborder millis dans ce cas de figure ?

    bernard

    Répondre

  • Comment gérer le temps dans un programme ? 8 juin 2023 16:17, par Jean-Luc

    Bonjour,
     
    Il vous faut une variable d’état, par exemple un booléen qui indique si le programme fait clignoter 3 fois la LED. Appelons là bool clignote = true;. Le fait qu’elle soit initialisée à true fait que le programme démarrera en faisant clignoter la LED. Ensuite on a le code qui fait clignoter la LED qui est construit selon le principe décrit dans l’article mais qui ne s’exécute que si clignote est true. En plus on compte combien de fois l’état de la LED est changé pour arrêter au bout de 6 (3 clignotements) en mettant clignote à false.

    Ça donne ça :

      if (clignote) {
        uint32_t nouvelleDate = millis();
        if (nouvelleDate - derniereDateClignote > 500) {
          derniereDateClignote = nouvelleDate;
          digitalWrite(LED_BUILTIN, ! digitalRead(LED_BUILTIN));
          compteClignote++;
          if (compteClignote == 6) {
            compteClignote = 0;
            clignote = false;
          }
        }
      }

    Il suffit maintenant de rajouter le code qui passe clignote à true toutes les 20 secondes sans oublier de mettre la derniereDateClignote à la date courante :

      uint32_t nouvelleDate = millis();
      if (nouvelleDate - derniereDateDelai > 20000) {
        derniereDateDelai = nouvelleDate;
        derniereDateClignote = nouvelleDate;
        clignote = true;
      }

    Le programme complet :

    void setup() {
      pinMode(LED_BUILTIN, OUTPUT);
    }
    
    bool clignote = true;
    uint32_t derniereDateClignote = 0;
    uint32_t derniereDateDelai = 0;
    uint8_t compteClignote = 0;
    
    void loop() {
      if (clignote) {
        uint32_t nouvelleDate = millis();
        if (nouvelleDate - derniereDateClignote > 500) {
          derniereDateClignote = nouvelleDate;
          digitalWrite(LED_BUILTIN, ! digitalRead(LED_BUILTIN));
          compteClignote++;
          if (compteClignote == 6) {
            compteClignote = 0;
            clignote = false;
          }
        }
      }
    
      uint32_t nouvelleDate = millis();
      if (nouvelleDate - derniereDateDelai > 20000) {
        derniereDateDelai = nouvelleDate;
        derniereDateClignote = nouvelleDate;
        clignote = true;
      }
    }

    Répondre

  • Comment gérer le temps dans un programme ? 14 juin 2023 17:06, par bernard

    Merci infiniment,
    ça me fait avancer et apprendre aussi, je vais tenter maintenant sur cette base de faire clignoter plusieurs leds à des rythmes et délais différents, ça me donne bien une leçon votre explication que j’ai, je pense comprise merci, merci.
    Bernard.

    Répondre

  • Comment gérer le temps dans un programme ? 14 juin 2023 23:27, par bernard

    Voila Votre code adapté pour 2 leds si j’ai bien compris ? mon code est il bon ? ou sera trop chargé sur 37 leds ou autre anomalie dans ma manière d’aborder et de construire mon montage qui fera clignoter les phares et les balises dans leur clignotement réels sur une carte marine( oui ce n’est pas du ferroviaire mais bon) le projet est de reproduire la rade de Brest avec ses balises et feux de nuit qui ont tous une couleur et un clignotements différents pour qu’un navigateur ne se perde pas la nuit et sache par rapport aux annotations de la carte officielles reconnaitre les fréquences de clignotement des repères lumineux

    suis pas sur d’être clair
    merci
    bernard

    Répondre

  • Comment gérer le temps dans un programme ? 14 juin 2023 23:29, par bernard

    oups code oublié le voila

    #define LED1 8
    #define LED2 9
    
    void setup() {
      pinMode(LED1, OUTPUT);
      pinMode(LED2, OUTPUT);
    }
     
    bool clignote1 = true;
    bool clignote2 = true;
    uint32_t derniereDateclignote1 = 0;
    uint32_t derniereDateclignote2 = 0;
    uint32_t derniereDateDelai = 0;
    uint8_t compteclignote1 = 0;
    uint8_t compteclignote2 = 0;
     
    void loop() {
      if (clignote1) {
        uint32_t nouvelleDate = millis();
        if (nouvelleDate - derniereDateclignote1 > 500) {
          derniereDateclignote1 = nouvelleDate;
          digitalWrite(LED1, ! digitalRead(LED1));
          compteclignote1++;
          if (compteclignote1 == 6) {
            compteclignote1 = 0;
            clignote1 = false;
          }
        }
      }
     
      uint32_t nouvelleDate = millis();
      if (nouvelleDate - derniereDateDelai > 20000) {
        derniereDateDelai = nouvelleDate;
        derniereDateclignote1 = nouvelleDate;
        clignote1 = true;
      }
      /*..............2EME LED......................*/
    
       if (clignote2) {
        uint32_t nouvelleDate = millis();
        if (nouvelleDate - derniereDateclignote2 > 1000) {
          derniereDateclignote2 = nouvelleDate;
          digitalWrite(LED2, ! digitalRead(LED2));
          compteclignote1++;
          if (compteclignote2 == 2) {
            compteclignote2 = 0;
            clignote2 = false;
          }
        }
      }
     
     
      /*uint32_t nouvelleDate = millis();   // ANCIEN CODE LOCO */
      if (nouvelleDate - derniereDateDelai > 2000) {
        derniereDateDelai = nouvelleDate;
        derniereDateclignote2 = nouvelleDate;
        clignote2 = true;
      }
    }

    Répondre

    • Comment gérer le temps dans un programme ? 15 juin 2023 09:34, par Jean-Luc

      Bonjour,
       
      Pas de soucis à dupliquer du code. Est-ce que ça marchera pour 37 LED ? C’est sur un Mega ? Attention à la consommation totale (voir Que peut-on alimenter avec un Arduino) et il faudra sans doute mettre des amplis comme des ULN (voir Amplifier le signal de sortie d’un ARDUINO avec un ULN 2803). Est-ce que le CPU ne sera pas trop chargé ? Non, le temps d’exécution du code pour 1 LED ne doit pas dépasser quelques dizaines de µs. Avec des process qui sont dans le domaine de la seconde, on peut en piloter des centaines.
       
      Mais si vous répliquez exactement le même schéma pour plusieurs LED, ça va être fastidieux et ça vaut le coup de faire une fonction, voire même des objets. Ça sera plus simple à comprendre et à lire, plus court et ça prendra moins de mémoire.

      Répondre

  • Comment gérer le temps dans un programme ? 15 juin 2023 09:38, par bernard

    bon j’ai remodifié le code et super grand merci ça marche pour 2 donc je peux continuer comme ça pour toutes les leds. mille merci ça fonctionne..
    et en plus j’ai appris un truc , pas belle la vie ?

    voici mon code pour 2

    #define LED1 7
    #define LED2 8
    
    void setup() {
      pinMode(LED1, OUTPUT);
      pinMode(LED2, OUTPUT);
    }
     
    bool clignote1 = true;
    bool clignote2 = true;
    uint32_t derniereDateclignote1 = 0;
    uint32_t derniereDateclignote2 = 0;
    uint32_t derniereDateDelai = 0;
    uint32_t derniereDateDelai2 = 0;
    uint8_t compteclignote1 = 0;
    uint8_t compteclignote2 = 0;
     
    void loop() {
      if (clignote1) {
        uint32_t nouvelleDate = millis();
        if (nouvelleDate - derniereDateclignote1 > 1000) {
          derniereDateclignote1 = nouvelleDate;
          digitalWrite(LED1, ! digitalRead(LED1));
          compteclignote1++;
          if (compteclignote1 == 6) {
            compteclignote1 = 0;
            clignote1 = false;
          }
        }
      }
     
      uint32_t nouvelleDate = millis();
      if (nouvelleDate - derniereDateDelai > 10000) {
        derniereDateDelai = nouvelleDate;
        derniereDateclignote1 = nouvelleDate;
        clignote1 = true;
      }
      /*..............2EME LED......................*/
    
       if (clignote2) {
        uint32_t nouvelleDate2 = millis();
        if (nouvelleDate2 - derniereDateclignote2 > 100) {
          derniereDateclignote2 = nouvelleDate2;
          digitalWrite(LED2, ! digitalRead(LED2));
          compteclignote2++;
          if (compteclignote2 == 12) {
            compteclignote2 = 0;
            clignote2 = false;
          }
        }
      }
     
      uint32_t nouvelleDate2 = millis();  
      if (nouvelleDate2 - derniereDateDelai2 > 5000) {
        derniereDateDelai2 = nouvelleDate2;
        derniereDateclignote2 = nouvelleDate2;
        clignote2 = true;
      }
    }

    Répondre

    • Comment gérer le temps dans un programme ? 15 juin 2023 09:44, par Jean-Luc

      Comme je le disais, si vous avez plus de 2 LED, répliquer le code n’est pas la voie à suivre. Le mieux est d’encapsuler le code dans une classe et d’instancier des objets. Je peux vous expliquer ça.

      C’est comme si vous me disiez « J’ai creusé 2m de tranchée avec une pelle, ça marche, je peux continuer sur 37m ? ». Ben non. Faut aller chercher une pelleteuse et mieux, ici elle sera robotisée, on lui explique sur 1m et elle fait sur 37m ou plus toute seule.

      Répondre

      • Comment gérer le temps dans un programme ? 15 juin 2023 17:39, par bernard

        Comme je le disais, si vous avez plus de 2 LED, répliquer le code n’est pas la voie à suivre. Le mieux est d’encapsuler le code dans une classe et d’instancier des objets. Je peux vous expliquer ça.

        bonjour,
        oui je veux bien qu’on m’explique l’encapsulage. , oula la laaa je vais en apprendre des choses moi avec vous.. vous êtes une vraie encyclopédie pour moi. je ne suis qu’un électricien de base qui apprend la domotique à la retraite en passe temps. je sais programmer simplement mais je ne cherche pas plus loin pour améliorer quand ça fonctionne. deja je comprends quand on me coache c’est pas si mal.. et comme on dit il faut apprendre toute sa vie.
        sinon oui je vais le faire avec un Arduino méga.

        bernard

        Répondre

        • Comment gérer le temps dans un programme ? 18 juin 2023 10:41, par Jean-Luc

          Bonjour,
           
          Pour encapsuler tout ça on va faire une classe. Tout d’abord les données. Le fonctionnement d’une LED nécessite :

          • La broche de la LED ;
          • Un intervalle de temps ;
          • Une période de clignotement ;
          • Un nombre de clignotement.

          Dans le programme actuel, ces 4 paramètres apparaissent en tant que constantes dans le code. On a aussi besoin des deux variables qui stockent les deux dates, celle qui compte les clignotements et un booléen pour savoir si on est en train de clignoter ou non. Ça nous donne ceci :

          class Clignotant {
              /* Intervalle d'émission des clignotements */
              uint32_t mIntervalle;
              /* Date de démarrage de l'intervalle en cours */
              uint32_t mDateIntervalle;
              /* Date de du dernier clignotement */
              uint32_t mDatePeriode;
              /* Période des clignotements */
              uint16_t mPeriode;
              /* Nombre de clignotements */
              uint8_t mNombre;
              /* Comptage du nombre de clignotements */
              uint8_t mCompteClignote;
              /* true si un clignotement est en cours */
              bool mClignote;
              /* broche de la LED */
              uint8_t mLEDPin;

          Par habitude je préfixe les données qui sont à l’intérieure d’une classe par un ’m’ pour membre.

          Ensuite, on a besoin d’une fonction membre de la classe qu’on appelle le constructeur. Cette fonction porte le même nom que la classe et a pour but d’initialiser les données membres. Elle est appelée lorsqu’on crée un objet. Ici notre constructeur prend 4 argument qui sont les paramètres listés plus haut et qui sont copiés dans les données membres correspondantes. Les autres données membres sont initialisés à 0 pour les dates, à true pour le clignotement.

            public:
              Clignotant(uint8_t inLEDPin,
                         uint32_t inIntervalle,
                         uint16_t inPeriode,
                         uint8_t inNombre):
                mLEDPin(inLEDPin),
                mIntervalle(inIntervalle),
                mDateIntervalle(0),
                mPeriode(inPeriode / 2),
                mDatePeriode(0),
                mNombre(inNombre * 2),
                mCompteClignote(0),
                mClignote(true) {

          À noter qu’on en profite pour rendre les paramètres de l’objet plus compréhensibles : le nombre de clignotement est multiplié par 2 car pour, par exemple, 3 clignotements, on a 6 changements d’état de la LED. Symétriquement le période est divisée par deux.

          Ensuite on a une fonction membre objectLoop qui contient le code que nous avons déjà vu en substituant aux constantes les données membres correspondantes :

              void objectLoop() {
                const uint32_t nouvelleDate = millis();
                if (nouvelleDate - mDateIntervalle > mIntervalle) {
                  mDateIntervalle = nouvelleDate;
                  mDatePeriode = nouvelleDate;
                  mClignote = true;
                }
          
                if (mClignote)  {
                  const uint32_t nouvelleDate = millis();
                  if (nouvelleDate - mDatePeriode > mPeriode) {
                    mDatePeriode = nouvelleDate;
                    digitalWrite(mLEDPin, ! digitalRead(mLEDPin));
                    mCompteClignote++;
                    if (mCompteClignote == mNombre) {
                      mCompteClignote = 0;
                      mClignote = false;
                    }
                  }
                }
              }

          On a aussi besoin d’une fonction membre qui va juste programmer la broche de la LED en sortie :

              void setupObject() {
                pinMode(mLEDPin, OUTPUT);
              }

          Il suffit ensuite de déclarer nos objet :

          Clignotant led1(LED_BUILTIN, 20000, 1000, 6);
          Clignotant led2(4, 8000, 500, 3);
          Clignotant led3(5, 9000, 700, 4);

          Pour les faire fonctionner, il faudrait appeler dans setup tous les setupObject :

            led1.setupObject();
            led2.setupObject();
            led3.setupObject();

          idem dans loop avec loopObject
           
          C’est pas terrible, on réplique un tas de ligne de code et si on ajoute une LED, il faut l’ajouter aussi dans setup et loop. Or il est possible de construire une liste d’objets lorsqu’on les crées. On a besoin d’un pointeur permettant de chainer les objets et d’une variable, pointeur également, pour stocker la tête de liste. Le premier pointeur est un membre de la classe, il y en a autant qu’il y a d’objets, le second est en exemplaire unique. On va en faire une variable de classe, partagée par touts les objets. Pour cela on ajoute static devant sa déclaration :

              /* Chainage de tous les objets lors de leur création */
              Clignotant *mNext;
              static Clignotant *sListe;

          Une donnée de classe doit être initialisée à part. Le pointeur est initialisé à NULL pour signifier qu’il pointe sur rien :

          Clignotant *Clignotant::sListe = NULL;

          Dans le constructeur, on construit la liste d’objets en ajoutant l’objet que l’on construit en tête de liste :

                  mNext = sListe;
                  sListe = this;

          On peut ensuite écrire deux fonctions de classe qui parcourent la liste pour appeler setupObject et setupLoop :

              static void setup() {
                Clignotant *objetCourant = sListe;
                while (objetCourant != NULL) {
                  objetCourant->objectSetup();
                  objetCourant = objetCourant->mNext;
                }
              }
              
              static void loop() {
                Clignotant *objetCourant = sListe;
                while (objetCourant != NULL) {
                  objetCourant->objectLoop();
                  objetCourant = objetCourant->mNext;
                }
              }

          Ces deux fonctions sont appelées comme ceci dans setup et loop :

          void setup() {
            Clignotant::setup();
          }
          
          void loop() {
            Clignotant::loop();
          }

          Et c’est beaucoup plus sympa car maintenant si on veut ajouter une LED, il suffit de la déclarer, elle sera automatiquement prise en charge. Le code complet :

          class Clignotant {
              /* Intervalle d'émission des clignotements */
              uint32_t mIntervalle;
              /* Date de démarrage de l'intervalle en cours */
              uint32_t mDateIntervalle;
              /* Date de du dernier clignotement */
              uint32_t mDatePeriode;
              /* Période des clignotements */
              uint16_t mPeriode;
              /* Nombre de clignotements */
              uint8_t mNombre;
              /* Comptage du nombre de clignotements */
              uint8_t mCompteClignote;
              /* true si un clignotement est en cours */
              bool mClignote;
              /* Pin de la LED */
              uint8_t mLEDPin;
          
              /* Chainage de tous les objets lors de leur création */
              Clignotant *mNext;
              static Clignotant *sListe;
          
            public:
              Clignotant(uint8_t inLEDPin,
                         uint32_t inIntervalle,
                         uint16_t inPeriode,
                         uint8_t inNombre):
                mLEDPin(inLEDPin),
                mIntervalle(inIntervalle),
                mDateIntervalle(0),
                mPeriode(inPeriode / 2),
                mDatePeriode(0),
                mNombre(inNombre * 2),
                mCompteClignote(0),
                mClignote(true) {
                  mNext = sListe;
                  sListe = this;
              }
          
              void objectLoop() {
                const uint32_t nouvelleDate = millis();
                if (nouvelleDate - mDateIntervalle > mIntervalle) {
                  mDateIntervalle = nouvelleDate;
                  mDatePeriode = nouvelleDate;
                  mClignote = true;
                }
          
                if (mClignote)  {
                  const uint32_t nouvelleDate = millis();
                  if (nouvelleDate - mDatePeriode > mPeriode) {
                    mDatePeriode = nouvelleDate;
                    digitalWrite(mLEDPin, ! digitalRead(mLEDPin));
                    mCompteClignote++;
                    if (mCompteClignote == mNombre) {
                      mCompteClignote = 0;
                      mClignote = false;
                    }
                  }
                }
              }
          
              void objectSetup() {
                pinMode(mLEDPin, OUTPUT);
              }
          
              static void setup() {
                Clignotant *objetCourant = sListe;
                while (objetCourant != NULL) {
                  objetCourant->objectSetup();
                  objetCourant = objetCourant->mNext;
                }
              }
              
              static void loop() {
                Clignotant *objetCourant = sListe;
                while (objetCourant != NULL) {
                  objetCourant->objectLoop();
                  objetCourant = objetCourant->mNext;
                }
              }
          
          };
          
          Clignotant *Clignotant::sListe = NULL;
          
          Clignotant led1(LED_BUILTIN, 20000, 1000, 6);
          Clignotant led2(4, 8000, 500, 3);
          Clignotant led3(5, 9000, 700, 4);
          
          void setup() {
            Clignotant::setup();
          }
          
          void loop() {
            Clignotant::loop();
          }

          Répondre

  • Comment gérer le temps dans un programme ? 15 juin 2023 12:27, par bernard

    c’est encore moi, comme je suis chiant et que j’aime bien compliquer les choses, que je me creuse beaucoup la tête en tant que débutant avec millis.
    je tente de faire allumer une led avec millis toujours mais cette fois ci avec allumage progressif sur une seconde, rester allumée une seconde puis éteindre progressif une seconde et cela toutes les 10 secondes par exemple.

    bernard

    Répondre

  • Comment gérer le temps dans un programme ? 19 juin 2023 23:02, par bernard

    Merci beaucoup pour ce cours monsieur jean luc.
    J’ai compris et je vais pouvoir commencer à faire autre chose avec les classes, mais pour le moment je me concentre sur mon projet de feux en mer et de la pointe bretonne.

    Il va falloir que je m’arrache encore un peu de cheveux car certains des clignotements des balises et feux sont très particuliers dans les périodes et je tiens à rester fidèle à la réalité. Pour exemple voici un lien qui vous donnera une vision plus précise des périodes non régulières. Voir à la page 8 du document, c’est très parlant.
    merci encore car j’apprend plein de chose et c’est super intéressant de travailler sur ce projet qui me force à sortir de ma zone de confort.
    Bernard.

    Voir en ligne : feux et balises en mer périodes

    Répondre

  • Comment gérer le temps dans un programme ? 22 juin 2023 08:59, par Jean-Luc

    Bonjour Bernard,
     
    J’ai parcouru le document. Concernant les feux à occultation et les feux à éclats, le fonctionnement se réduit à une série de durées avec un changement d’état du feu à chaque frontière. Ça peut être représenté par un tableau de durées et un état initial du feu (allumé ou éteint). D’où la définition de la classe FeuMaritime :

    class FeuMaritime {
        /* Dates relatives de changement d'état du feu */
        const uint32_t *mDatesChangement;
        /* Dernière date de changement */
        uint32_t mDerniereDate;
        /* Nombre de dates */
        uint8_t mNombreDeDates;
        /* Changement courant */
        uint8_t mChangementCourant;
        /* Etat initial */
        uint8_t mEtatInitial;
        /* Pin de la LED */
        uint8_t mLEDPin;
    
        /* Chainage de tous les objets lors de leur création */
        FeuMaritime *mNext;
        static FeuMaritime *sListe;
    
      public:
        FeuMaritime(const uint8_t inLEDPin,
                    const uint32_t *inDatesChangement,
                    const uint8_t inNombreDeDates,
                    const uint8_t inEtatInitial):
          mLEDPin(inLEDPin),
          mDatesChangement(inDatesChangement),
          mDerniereDate(0),
          mNombreDeDates(inNombreDeDates),
          mEtatInitial(inEtatInitial)
        {
          mNext = sListe;
          sListe = this;
        }
    
        void objectLoop() {
          const uint32_t nouvelleDate = millis();
          if (nouvelleDate - mDerniereDate > mDatesChangement[mChangementCourant]) {
            digitalWrite(mLEDPin, ! digitalRead(mLEDPin));
            mDerniereDate = nouvelleDate;
            mChangementCourant++;
            if (mChangementCourant == mNombreDeDates) {
              mChangementCourant = 0;
            }
          }
        }
    
        void objectSetup() {
          pinMode(mLEDPin, OUTPUT);
          digitalWrite(mLEDPin, mEtatInitial);
        }
    
        static void setup() {
          FeuMaritime *objetCourant = sListe;
          while (objetCourant != NULL) {
            objetCourant->objectSetup();
            objetCourant = objetCourant->mNext;
          }
        }
    
        static void loop() {
          FeuMaritime *objetCourant = sListe;
          while (objetCourant != NULL) {
            objetCourant->objectLoop();
            objetCourant = objetCourant->mNext;
          }
        }
    
    };
    
    FeuMaritime *FeuMaritime::sListe = NULL;

    Les arguments du constructeur sont la broche où la LED est connectée, un pointeur vers un tableau de constantes qui sont les intervalles de temps, le nombre d’éléments dans ce tableau et l’état initial (HIGH ou LOW).
     
    Pour utiliser cette classe, il faut d’abord instancier un tableau de constantes puis instancier un objet en lui passant ce tableau. Voici par exemple les feux mentionnés aux sections 2.1, 2.2 et 2.3.

    const uint32_t specAISM1[] = { 1000, 3000 };
    FeuMaritime feuAOccultationsRegulieres(0, specAISM1, 2, LOW); 
    
    const uint32_t specAISM2[] = { 1000, 2000, 1000, 6000 };
    FeuMaritime feuAOccultationsGroupees(1, specAISM2, 4, LOW); 
    
    const uint32_t specAISM3[] = { 1000, 1000, 1000, 3000, 1000, 9000 };
    FeuMaritime feuAOccultationsDiversementGroupees(2, specAISM3, 6, LOW); 

    setup et loop sont simplement :

    void setup() {
      FeuMaritime::setup();
    }
    
    void loop() {
      FeuMaritime::loop();
    }

    Répondre

  • bonjour, Jean Luc,
    la vache vous êtes super balaise. J’avance vite avec vos conseils et en plus je découvre plein de choses, moi je suis incapable d’avoir cette logique. je comprends mais il me faut du temps pour bien assimiler. j’ai du temps à la retraite aussi, donc j’avance à mon rythme dans l’apprentissage. ayant fait une carrière aux 3 ports de Nantes métropole (NGE) me voila retourné à Brest ma ville natale ou j’ai décidé de me lancer dans le maquettisme maritime, hé bien ce n’est pas de la tarte finalement. bon pour ce qui est décors ça va mais l’Arduino me rendra fou et grâce à vous je vais peut être devenir bon un jour et aussi pouvoir donner des petits conseils aux débutants. (peut être)
    merci mille fois
    Bernard

    Répondre

  • bonjour, jean Luc et les autres , je suis content de votre retour sur la toile. j’avais appris que vous aviez été piraté. quelle histoire. bon voila juste pour souhaiter un bon retour. pendant ce temps j’avance sur mes feux maritimes. doucement mais surement.
    bernard

    Répondre

Réagissez à « Comment gérer le temps dans un programme ? »

Qui êtes-vous ?
Votre message

Pour créer des paragraphes, laissez simplement des lignes vides.

Lien hypertexte

(Si votre message se réfère à un article publié sur le Web, ou à une page fournissant plus d’informations, vous pouvez indiquer ci-après le titre de la page et son adresse.)

Rubrique « Programmation »

Les derniers articles

Les articles les plus lus