LOCODUINO

Aide
Forum de discussion
Dépôt GIT Locoduino
Flux RSS

vendredi 26 avril 2024

Visiteurs connectés : 70

Comment gérer le temps dans un programme ?

et comment faire plusieurs tâches simultanément

. Par : Dominique, Guillaume, Jean-Luc

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 (...)

Retourner à l'article

Vous répondez à :

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();
}
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.)

65 Messages

Rubrique Programmation

Le monde des objets (1)

Le monde des objets (2)

Le monde des objets (3)

Le monde des objets (4)

Les pointeurs (1)

Les pointeurs (2)

Les Timers (I)

Les Timers (II)

Les Timers (III)

Les Timers (IV)

Les Timers (V)

Bien utiliser l’IDE d’Arduino (1)

Bien utiliser l’IDE d’Arduino (2)

Piloter son Arduino avec son navigateur web et Node.js (1)

Piloter son Arduino avec son navigateur web et Node.js (2)

Piloter son Arduino avec son navigateur web et Node.js (3)

Piloter son Arduino avec son navigateur web et Node.js (4)

Démarrer en Processing (1)

L’assembleur (9)

Comment gérer le temps dans un programme ?

L’assembleur (8)

Processing pour nos trains

L’assembleur (7)

L’assembleur (6)

Arduino : toute première fois !

TCOs en Processing (1)

L’assembleur (5)

L’assembleur (4)

L’assembleur (3)

L’assembleur (2)

L’assembleur (1)

TCOs en Processing (2)

Calculer avec l’Arduino (1)

La programmation, qu’est ce que c’est

Types, constantes et variables

Installation de l’IDE Arduino

Répéter des instructions : les boucles

Les interruptions (1)

Instructions conditionnelles : le if ... else

Instructions conditionnelles : le switch ... case

Comment concevoir rationnellement votre système

Comment gérer l’aléatoire ?

Trucs, astuces et choses à ne pas faire !

Calculer avec l’Arduino (2)

Les structures

Systèmes de numération

Les fonctions

Trois façons de déclarer des constantes

Transcription d’un programme simple en programmation objet

Ces tableaux qui peuvent nous simplifier le développement Arduino

Les chaînes de caractères

Les derniers articles

L’assembleur (9)


Christian

L’assembleur (8)


Christian

L’assembleur (7)


Christian

L’assembleur (6)


Christian

L’assembleur (5)


Christian

L’assembleur (4)


Christian

L’assembleur (3)


Christian

L’assembleur (2)


Christian

L’assembleur (1)


Christian

TCOs en Processing (2)


Pierre59

Les articles les plus lus

Les Timers (I)

Les interruptions (1)

Instructions conditionnelles : le if ... else

Ces tableaux qui peuvent nous simplifier le développement Arduino

Piloter son Arduino avec son navigateur web et Node.js (1)

Comment gérer le temps dans un programme ?

Les Timers (II)

Calculer avec l’Arduino (1)

Calculer avec l’Arduino (2)

Les Timers (III)