Transcription d’un programme simple en programmation objet

. Par : Dominique, Guillaume, Jean-Luc. URL : https://www.locoduino.org/spip.php?article113

Pourquoi parler de codage avant d’avoir spécifié les besoins d’un réseau ?

Quand nous concevons un réseau, en tout cas pour ma part, mon souhait est de diversifier les tâches. En effet, coder, poser les voies, faire les bâtiments, tout cela dans un but de non monotonie.
Bref, comment donc coder sans avoir défini entièrement le réseau ?
Nous avons tout de même une idée de ce que l’on veut faire : quelques animations lumineuses, faire bouger le train, etc...

Dans cette optique, Thierry nous apporte la solution : les objets. Nous vous invitons à lire les articles de la série : Le monde des objets (1).

Néanmoins, cette façon de coder n’apporte pas que cet avantage. Nous allons en voir d’autres au cours de cet exemple de traduction d’un programme.

Seul programme pour une carte Arduino

La plupart des programmes d’animations lumineuses que nous trouvons sont seuls sur la carte Arduino. C’est-à-dire que seule cette animation pourra être téléversée et en ajouter une dans le code bouleversera la cinématique, et l’animation sera parasitée. Cela est dû à la présence de la commande delay() qui met en pause la carte Arduino ne permettant pas l’exécution d’un autre code.
Il faut donc traduire ce code avec un autre moyen de gérer le temps : la commande millis(). Petit rappel : Comment gérer le temps dans un programme ?.

Exemple de programme

Prenons l’animation soudure à l’arc, décrite dans l’article éponyme : Simulateur de soudure à arc. Nous allons commencer simple en y allant petit à petit. Nous nous attacherons à réutiliser les acquis que nous aurons vu pour les autres animations.
Traduisons tout d’abord ce programme avec la commande millis().
Il nous faut établir le diagramme d’enchaînement des commandes, l’animation se décompose comme ceci :
Cycle de 10 à 20 flashs de 10 à 100 ms avec un laps de temps entre flashs de 10 à 30 ms et entre chaque cycle, une pause de 1,5 à 7s.
L’aléatoire viendra de la commande random() comme décrit dans cet article : Comment gérer l’aléatoire ?.

Traduction

Traduisons le programme. Pour cela, il va nous falloir utiliser des instructions conditionnelles telles que les if et else, des variables "compteur"...
Il n’est pas admissible en langage C d’utiliser la balise goto, même si le langage en fournit la possibilité, parce que cela introduit du code non linéaire difficilement lisible et maintenable. Une bonne maîtrise de base est donc nécessaire mais est facilement surmontable avec les if quand nous posons bien le problème sur une simple feuille. Eh oui, car le bon outil d’un codeur est paradoxalement un bloc-notes.
Un petit dessin vaudra mieux qu’un grand discours, vous ne verrez pas mon talent mais simplement un début de carte fait sur Framindmap :

Petite explication du dessin : nous partons du if attente entre 2 cycles. Si non au résultat, les flashs se font. Si oui au résultat, les flashs s’arrêtent et nous testons le temps d’attente. Si oui, on reprend les flashs ; si non, nous attendons encore.

Ce dessin ne représente pas tout le cheminement mais en montre au moins une partie. Il faut bien penser que la fonction loop() est une boucle infinie. A chaque fin, nous revenons automatiquement au point de départ de la fonction. En dessinant l’arbre décisionnel, le code vient tout seul.

Tester aussi des conditions implique un apport de certaines variables qui changent quand une autre condition est remplie, qui, elles, ne sont pas sur le dessin.

Mais le meilleur dessin est le vôtre, essayez.

Maintenant que nous avons dessiné notre plan, le code vient de lui-même :

const byte pin=13;
boolean boucle=0;
byte dureeflash;
unsigned long temps=0;
byte compteur=0;
byte tempsflash;
byte compte;
long tempspause;

void setup() {
  // put your setup code here, to run once:
  pinMode(pin, OUTPUT);
  randomSeed(analogRead(0));
  tempsflash=random(10,31);
  compte=random(10,21);
  tempspause=random(1500,7001);
}

void loop() {
  // put your main code here, to run repeatedly:
  if((compteur>compte)&&(boucle==0))
  {
    if((millis()-temps)>tempspause)
    {
      temps=millis();
      compte=random(10,21);
      tempspause=random(1500,7001);
      compteur=0;
    }
  }
  else
  {
    switch(boucle)
    {
      case 0:
      if((millis()-temps)>tempsflash)
      {
        boucle=1;
        digitalWrite(pin, HIGH);
        temps=millis();
        dureeflash=random(10,101);
      }
      break;
      case 1:
      if((millis()-temps)>dureeflash)
      {
        boucle=0;
        digitalWrite(pin, LOW);
        temps=millis();
        tempsflash=random(10,31);
        compteur++;
      }
      break;
    }  
  }
}

Petite note : quand nous comparons un random avec un if dans une boucle infinie, l’effet pseudo-aléatoire est anéanti puisque chaque appel va donner un nombre différent. Il faut stocker le nombre aléatoire dans une variable pour avoir tout de même l’effet aléatoire. En effet, il faut exécuter random un minimum de fois.

Avantages de ce code et des objets

Nous notons donc que maintenant il est facile d’ajouter une animation à ce code. Prenons, par exemple, sur une même carte Arduino, deux simulateurs à l’arc sur deux broches différentes. Il est facile avec le programme précédent de combiner en un seul programme les deux codes (même code reproduit avec d’autres variables). Cependant cela reste une opération fastidieuse. En effet, il faut copier-coller au bon endroit du programme :

  • déclaration des variables
  • void setup()
  • void loop()

L’apport des objets va nous simplifier le code. Nous avons dans notre exemple théorique deux animations identiques. Pourquoi ne pas transcrire cette animation en classe ?
Nous aurons notre classe, et dans la partie effective du code une déclaration d’objets par animation et le lancement de chaque animation dans le loop.

Cela peut paraître compliqué mais l’étape précédente était plus dure. Venons-en au fait.

Construction de la classe

Comme dit au début de cet article, nous allons donc nous inspirer des articles sue les objets et nous complexifierons dans un autre article pour nous faciliter ensuite les choses.

Premièrement, les parties privées et publiques de la classe : finalement ce qui est suffisant est qu’il nous faut modifier la broche de sortie de la DEL mais aussi pouvoir lancer ou arrêter l’animation, tout le reste est privé. Pour coller au maximum à d’autres bibliothèques tel que liquidcrystal, nous utiliserons notre constructeur perso pour créer notre objet avec la broche de sortie mais aussi une fonction begin pour initialiser (mettre le code que nous avons mis dans le setup).

Déclarons la classe :

class SoudureArc
{
  private:
    byte pin;
    boolean boucle=0;
    byte dureeflash;
    unsigned long temps=0;
    byte compteur=0;
    byte tempsflash;
    byte compte;
    long tempspause;    
  public:
    void off();
    SoudureArc(byte apin);
    void begin(); 
    void on();
};

Spécifions ensuite les méthodes que l’on a ébauché avec la classe :

void SoudureArc::off()
{
  digitalWrite(pin, LOW);
}

SoudureArc::SoudureArc(byte apin)
{
  pin=apin;
}

void SoudureArc::begin()
{
  pinMode(pin, OUTPUT);
  randomSeed(analogRead(0));
  tempsflash=random(10,31);
  compte=random(10,21);
  tempspause=random(1500,7001);
  off();
}

void SoudureArc::on()
{
  if((compteur>compte)&&(boucle==0))
  {
    if((millis()-temps)>tempspause)
    {
      temps=millis();
      compte=random(10,21);
      tempspause=random(1500,7001);
      compteur=0;
   }
  }
  else
  {
    switch(boucle)
    {
      case 0:
      if((millis()-temps)>tempsflash)
      {
        boucle=1;
        digitalWrite(pin, HIGH);
        temps=millis();
        dureeflash=random(10,101);
      }
      break;
      case 1:
      if((millis()-temps)>dureeflash)
      {
        boucle=0;
        off();
        temps=millis();
        tempsflash=random(10,31);
        compteur++;
      }
    }  
  }
}

Tel quel, ce code ne fonctionnera pas sur un Arduino. Il nous faut déclarer l’objet avec sa broche, initialiser dans le setup et lancer l’animation dans le loop. A la suite des deux bouts de codes précédents, voici donc la partie principale :

SoudureArc soudure(13);

void setup()
{
  soudure.begin();
}

void loop()
{
  soudure.on();
}

Et pour mettre sur une carte Arduino deux animations Soudure à l’arc :

SoudureArc soudure1(13);
SoudureArc soudure2(12);

void setup()
{
  soudure1.begin();
  soudure2.begin();
}

void loop()
{
  soudure1.on();
  soudure2.on();
}

à la suite de la description de la classe et de ses méthodes.

Et vous avez deux animations sans complexifier le code. Nous voyons donc par cet exemple simple l’avantage de la programmation objet : pouvoir coder par avance et maintenir un code propre et net dans le sketch principal.

Et avantage non négligeable, le programme est plus léger.