LOCODUINO

Instructions conditionnelles : le switch ... case

.
Par : Jean-Luc

DIFFICULTÉ :

Nous avons examiné le if ... else dans « Instructions conditionnelles : le if ... else ». Une seconde instruction conditionnelle existe. Elle permet des choix multiples, ce qui peut s’avérer très utile dans de nombreux cas, mais elle est plus restrictive car elle ne permet qu’une seule condition, l’égalité.

La condition qui est évaluée par un if ... else est de nature booléenne, elle ne peut être que vraie ou fausse, ce qui correspond à l’exécution des instructions du if ou bien à l’exécution des instructions du else.

Syntaxe du switch ... case

Dans le cas d’un switch ... case, la condition est remplacée par une expression évaluée par le switch. Chaque case mentionne la valeur de l’expression pour laquelle ses instructions doivent être exécutées. C’est à dire que si l’expression qui apparaît dans le switch est égal à la valeur du case alors les instructions du case sont exécutées.

La syntaxe générale de cette instruction est la suivante :

switch (expression) {
  case valeur1:
    // instructions à exécuter si expression est égale à valeur1
    break;
  case valeur2:
    // instructions à exécuter si expression est égale à valeur2
    break;
  case valeur3:
    // instructions à exécuter si expression est égale à valeur3
    break;
  default:
    // instructions à exécuter si expression n'est égale à aucune des valeurs des case
    break;
}

Les valeurs des case sont impérativement des constantes.

default est optionnel et est exécuté quand aucun des case ne correspond à l’expression qui apparaît dans le switch (expression). C’est généralement une bonne idée d’y mettre le signalement d’une erreur.

les instructions break qui apparaissement après les instructions de chaque case sont primordiales. En effet, en leur absence, l’exécution se poursuivrait avec les instructions du case suivant. Par exemple, si expression est égale à valeur2 et que le break situé à la fin des instructions du case valeur2: est omise, les instructions du case valeur3: seront exécutées à la suite.

Le dernier break est inutile mais je recommande de le mettre tout de même. En effet, si dans le futur vous ajoutez un nouveau case à la fin du switch, il y a fort à pariez que vous oublierez le break pour fermer le case qui précède. Vous ne pouvez pas imaginer le nombre de bugs de ce type qui ont enquiquiné les programmeurs.

Le break provoque la poursuite de l’exécution à l’instruction qui suit le switch.

Le nombre de case n’est pas limité.

Usage du switch ... case

Les usages sont multiples mais les cas d’application sont généralement liés à l’exécution d’une conditionnelle selon un état du système. Cela va du codage ou du décodage d’un protocole de communication, vous en avez un exemple dans l’article de Dominique, « Comment piloter trains et accessoires en DCC avec un Arduino (1) », où dans l’ISR, l’état d’envoi de la trame DCC est géré via un switch ... case à la gestion d’un feu tricolore dont nous allons donner un exemple :

Supposons que nous voulions gérer un signal de BAL [1]. Le signal possède 3 feux : vert, jaune et rouge. Il peut prendre 5 états : feu vert, feu jaune, feu jaune clignotant, feu rouge, feu rouge clignotant. Nous allons donc définir 5 constantes pour désigner ces états : VERT, JAUNE, JAUNE_CLIGNOTANT, ROUGE et ROUGE_CLIGNOTANT. Comme ceci [2] :

const byte VERT = 0;
const byte JAUNE = 1;
const byte JAUNE_CLIGNOTANT = 2;
const byte ROUGE = 3;
const byte ROUGE_CLIGNOTANT = 4;

Chaque feu va évidemment correspondre à une DEL associée à une broche. Appelons ces broches pinVerte, pinJaune et pinRouge. Ce qui donne également lieu à la déclaration de constantes :

const byte pinVerte = 4;
const byte pinJaune = 5;
const byte pinRouge = 6;

Les DEL sont connectées de telle sorte qu’un état HIGH sur la broche provoque l’allumage de la DEL. Voir « Fonctionnement et pilotage d’une DEL ».

Il nous faut également une variable qui va accueillir l’état du signal et que l’on va initialiser à ROUGE :

byte etatSignal = ROUGE;

Et puis également une variable qui va nous permettre de gérer les clignotements comme on a pu le voir dans « Comment gérer le temps dans un programme ? » que je vous engage à lire pour comprendre ce qui va venir et une seconde variable etatClignotant qui mémorise l’état de la broche du feu qui est en cours de clignotement.

unsigned long dateDernierClignotement = 0;
byte etatClignotant = LOW;

Enfin, grâce à un switch ... case nous allons déterminer ce qui doit être fait sur les DEL pour que l’affichage corresponde à l’état du signal. Nous allons mettre ça dans une fonction afficheFeu :

void afficheFeu()
{
  switch (etatSignal) {
 
    case VERT:
      digitalWrite(pinVerte, HIGH);
      break;
 
    case JAUNE:
      digitalWrite(pinJaune, HIGH);
      break;
 
    case JAUNE_CLIGNOTANT:
      unsigned long dateCourante = millis();
      if (dateCourante - dateDernierClignotement > 480) {
        dateDernierClignotement = dateCourante;
        etatClignotant = ! etatClignotant;
        digitalWrite(pinJaune, etatClignotant);
      }
      break;
 
    case ROUGE:
      digitalWrite(pinRouge, HIGH);
      break;
 
    case ROUGE_CLIGNOTANT:
      unsigned long dateCourante = millis();
      if (dateCourante - dateDernierClignotement > 480) {
        dateDernierClignotement = dateCourante;
        etatClignotant = ! etatClignotant;
        digitalWrite(pinRouge, etatClignotant);
      }
      break;
  
    default:
      Serial.println("Code de feu inconnu !");
      break;     
  }
}

Pour permettre le clignotement, ce afficheFeu doit être appelé à intervalles réguliers dans loop().

Bien entendu il ne s’agit pas d’une application complète mais le code présenté ici servira de base à un exemple plus complet que nous verrons prochainement.

[1Bloc Automatique Lumineux.

[2Il existe une manière plus élégante de déclarer plusieurs constantes que nous verrons ultérieurement.

8 Messages

  • Instructions conditionnelles : le switch ... case 4 juillet 2017 15:42, par Jacques

    Bonjour Jean-Luc,
    Je viens de prendre connaissance de cet article édité en janvier 2015.
    J’ai des feux de signalisation à animer sur mon réseau.
    A la fin de ton article tu écris que celui-ci "servira de base à un exemple plus complet que nous verrons prochainement".
    Où se trouve l’exemple plus complet dont tu parles ?
    En effet, j’ai beau chercher dans Locoduino, je ne trouve pas cet exemple promis.
    Bien cordialement.
    Jacques

    Répondre

  • Instructions conditionnelles : le switch ... case 4 mars 2019 18:01, par PECOURT Jean-Louis (Jihel)

    Bonjour,

    1 - Dans l’exemple ci-dessus, pourquoi l’ensemble du programme switch case est-il placé derrière un : void(afficheFeu)
    J’avais cru comprendre que les programmes se trouvaient dans la partie loop() ?

    2 - D’autre part ("cas d’école"), la variable peut-elle être booléenne (donc 2 cas (0, 1) pour remplacer un if) ? par exemple récupération d’un bit dans un octet.

    3 - La numérotation des cas peut-elle commencer par 0 (zéro)

    4 - La numérotation des cas peut-elle commencer par n’importe quel chiffre et/ou nombre, et doit-elle être continue ?
    exemple : j’ai une variable qui ne prend que les valeurs 4, 7, 12

    Cordialement
    J.L.

    Répondre

    • Instructions conditionnelles : le switch ... case 5 août 2020 12:00, par Jean-Luc

      Bonjour.
      Ça fait un bout de temps mais je n’avais pas vu la question.

      1. le switch est placé dans une fonction qui sera appelée dans loop().
      2. Oui. Toute valeur différente de 0 est interprétée comme vraie, 0 est interprété comme faux.
      3. Oui
      4. Oui

      Cordialement.

      Répondre

  • Instructions conditionnelles : le switch ... case 5 août 2020 10:38, par Kaki In

    Bonjour

    Est-il possible de passer des String en argument ou il n’y a que les nombres qui sont pris en charge par le switch ?

    Répondre

  • Instructions conditionnelles : le switch ... case 5 août 2020 11:54, par Jean-Luc

    Bonjour,
    seules les données d’un type qui se ramènent à un int peuvent être utilisés c’est à dire les nombres entiers et les items d’un enum.

    Répondre

  • Bonjour,
    Etant à la recherche d’un programme pour actionner mes feux tricolore sur mon réseau ferroviaire, je suis tombé sur votre site.
    Mais j’ai un souci dans la copie du code, mon Arduino UNO ne prend pas l’instruction switch
    Cela me met un défaut.
    Cordialement

    Répondre

  • Instructions conditionnelles : le switch ... case 24 avril 2021 10:25, par msport

    ... probablement une faute de frappe.

    Répondre

  • // je laisse un code fonctionnel si ça peut servir à quelqu'un .
    const byte VERT             = 0 ;
    const byte JAUNE            = 1 ;
    const byte JAUNE_CLIGNOTANT = 2 ;
    const byte ROUGE            = 3 ;
    const byte ROUGE_CLIGNOTANT = 4 ;
    
    const byte led_verte = 5 ;
    const byte led_jaune = 6 ;
    const byte led_rouge = 7 ;
    
    byte etat_signal ;
    unsigned long temps_ecoule = 0 ;
    
    void setup ( )
    {
      pinMode ( led_verte , OUTPUT ) ;
      pinMode ( led_jaune , OUTPUT ) ;
      pinMode ( led_rouge , OUTPUT ) ;
      etat_signal = ROUGE ; // on initialise à " led_rouge = HIGH " .
    }
    
    void loop ( ) 
    {
      unsigned long temps_actuel = millis ( ) ; // récupère le temps actuel .
      
      // vérifie si le temps imparti est écoulé .
      if ( temps_actuel - temps_ecoule >= 5000 ) 
      {
        temps_ecoule = temps_actuel ; // enregistre le temps actuel .
        changerEtat ( ) ; // passe à l'état suivant .
      }
      afficheFeu ( ) ; // affiche l'état courant .
    }
    
    void changerEtat ( )
    {
      etat_signal ++ ; // passe à l'état suivant .
      
      // revient à l'état initial si on a atteint le dernier état .
      if ( etat_signal > ROUGE_CLIGNOTANT ) etat_signal = VERT ; 
    }
    
    void afficheFeu ( )
    {
      switch ( etat_signal ) 
      {
      case VERT :   
        digitalWrite ( led_verte , HIGH ) ;
        digitalWrite ( led_jaune , LOW  ) ;
        digitalWrite ( led_rouge , LOW  ) ;
        break ;
     
      case JAUNE :
        digitalWrite ( led_verte , LOW  ) ;
        digitalWrite ( led_jaune , HIGH ) ;
        digitalWrite ( led_rouge , LOW  ) ;
        break ;
      
      case JAUNE_CLIGNOTANT :
        // allume la led_jaune pendant 500ms, puis l'éteint pendant 500ms .
        if ( ( millis ( ) / 500 ) % 2 == 0 ) 
          digitalWrite ( led_jaune , HIGH ) ;
        else
          digitalWrite ( led_jaune , LOW ) ;
        digitalWrite ( led_verte , LOW ) ;
        digitalWrite ( led_rouge , LOW ) ;
        break ;
      
      case ROUGE :
        digitalWrite ( led_verte , LOW  ) ;
        digitalWrite ( led_jaune , LOW  ) ;
        digitalWrite ( led_rouge , HIGH ) ;
        break ;
      
      case ROUGE_CLIGNOTANT :
        // allume la led_rouge pendant 500ms, puis l'éteint pendant 500ms .
        if ( ( millis ( ) / 500 ) % 2 == 0 ) 
          digitalWrite ( led_rouge , HIGH ) ;
        else
          digitalWrite ( led_rouge , LOW ) ;
        digitalWrite ( led_verte , LOW ) ;
        digitalWrite ( led_jaune , LOW ) ;
        break ;
      
      default :
        Serial . println ( " Code de feu inconnu ! " ) ;
        break ; 
      }
    } 

    Répondre

Réagissez à « Instructions conditionnelles : le switch ... case »

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