Bug dans fonction switch() { case}

Bonjour à tous !
Depuis plusieurs semaines je fait un programme pour arroser automatiquement mon jardin, mais depuis 3 jours je bloque sur un point, je vous ai mis un extrait du programme qui me pose problème (N’hesitez pas à me demander le programme complet si besoins):

#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#define OLED_RESET 4
Adafruit_SSD1306 display(128, 64, &Wire, OLED_RESET);;

long tprec2 = 0;


const int bout1 = 2;          // Bouton 1 (Changer menu, modifier valeur) 
const int boutp = 4;          // Bouton + (Augmenter valeur)
const int boutm = 5;          // Bouton - (Diminuer valeur)

byte moism;
byte jourm;           
byte heurem;            // Variable de mémorisation date d'arrosage voulu
byte minutem;
int  reglagetemps;

int qteL;

byte b1 = 0;
bool effetb1 = HIGH;
bool bout1prec;

void setup() {
  Serial.begin(9600);

  pinMode(bout1, INPUT_PULLUP);           
  pinMode(boutp, INPUT_PULLUP);
  pinMode(boutm, INPUT_PULLUP);
  
  display.begin(SSD1306_SWITCHCAPVCC, 0x3C);
  display.clearDisplay();
  display.setTextColor(SSD1306_WHITE);        // Texte en blanc
  display.setTextSize(2); display.setCursor(10, 30); display.println("DEMARRAGE");
  display.display();
  delay(1000);
  display.clearDisplay();
  display.display();
  Wire.begin(9600);
  int tprec2 = millis(); 
}



void loop() {         

  
  display.clearDisplay();                          // Affichage momment d'arrosage programmé et de la quantité 
  display.setCursor(0, 30); 
  display.print(moism); display.print("/"); display.print(jourm);
  display.setCursor(50, 30); 
  display.print(heurem); display.print(":"); display.print(minutem);
  display.setCursor(50, 50);
  display.print(qteL);
  display.display(); 

  bouton();               // Execuction fonction bouton pour actualiser son état

  if (b1 == 2) {          // Si appui long sur le bouton 
   
 byte count = 1;       // Compteur pour mémoriser la valeur séléctionnée
 (mois, puis jour, puis heure, puis minute, puis quantitée d'eau)
    reglagetemps = 0;     // Mise à zéro compteur servant à incrémenter l'unité sélectionnée
    effetb1 = HIGH;       // Mémorisation de la prise en compte du changement d'état du bouton
     
    while (count < 7){   // Tant que le la valeur séléctionné n'es pas supérieuse à 5
      bouton();           // Execution fonction bouton
      //Serial.println("boucle de réglage");
      if (b1 == 1){       // Si appui court sur le bouton n°1
        count ++;         // Incrémentation du compteur pour sélectionner la valeur suivante
        effetb1 = HIGH;   // Mémorisation de la prise en compte du changement d'état du bouton
      }

      switch (count) {    // Incrémentation de la valeur sélectionnée
        case 1:
          moism = moism + reglagetemps;  // Si la valeur sélectionnée est le mois, adition avec l'incrémentation voulue
          if (moism > 12) {
            moism = 1;
          }
          else if (moism < 1){
            moism = 12;
          }
          break;
        
        case 2:
          jourm = jourm + reglagetemps; 
          if (jourm > 31) {
            jourm = 1;
          }
          else if (jourm < 1){
            jourm = 31;
          }
          break;
        
        case 3:
          heurem = heurem + reglagetemps;
          if (heurem > 23) {
            heurem = 0;
          }
          else if ((heurem == 0) && (reglagetemps == -1)) {
            heurem = 23;
          }
          break;
        
        case 4:
          minutem = minutem + reglagetemps; 
          if (minutem > 59) {
            minutem = 0;
          }
          else if ((minutem == 0) && (reglagetemps == -1)) {
            minutem = 59;
          }
          break;
        
        case 5:
        Serial.println("5");
          float incqteL = reglagetemps;
          qteL = qteL + (incqteL * 0.05);
          if (qteL > 2) {
            qteL = 0;
          }
          else if (qteL < 0){
            qteL = 2;
          }
          break;
        
        case 6:
          Serial.println("6");
          break;

        default:
          Serial.println("default");
          break;
      }
      
      reglagetemps = 0;
      
      while (count == 7) {        
        display.clearDisplay();  
        display.setTextSize(1);   // Affichage "Réglage" en haut de l'écran
        display.setCursor(0, 30); 
        display.print("Regler les autres paramètres d'arrosage ?");
        display.setCursor(0, 50); 
        display.print("OUI: Appuis long sur b1   NON: Appuis court sur b1");
        display.display();
        bouton();
        if (b1 == 2) {
          effetb1 = HIGH;
          Serial.println("7,foncion reglageM3");
        }
        else if (b1 == 1) {
          effetb1 = HIGH;
          count ++;
        }
      }
       
      display.clearDisplay();  
      display.setTextSize(1);   // Affichage "Réglage" en haut de l'écran
      display.setCursor(0, 0); 
      display.print("Reglage"); 
      display.print("   ");
      display.print(count); 

      // Affichage momment d'arrosage programmé
      display.setCursor(0, 30); 
      display.print(moism); display.print("/"); display.print(jourm);
      display.setCursor(40, 30); 
      display.print(heurem); display.print(":"); display.print(minutem);
      display.setCursor(85, 30);
      display.print(qteL);
      display.display();
      delay(100);
    }
  }
}



void bouton() {
  bool etatb1 = digitalRead(bout1);
 
  if (etatb1 == LOW && bout1prec == HIGH){
    tprec2 = millis();
    bout1prec = LOW;
  }
  
  if (etatb1 == HIGH && bout1prec == LOW){  // Si le bouton vient d'etre relaché
    bout1prec = HIGH;                       // Mémorisation etat précédent du bouton
    
    if ((millis()- tprec2) >= 500){      // Si appui plus long que la variable tbout
      b1 = 2;                              // Mémorisation de l'appui long, b1 = 2
      effetb1 = LOW;                       // Changement d'état du bouton non pris en compte
    }
    else {                                 // Sinon  c'est un appui court, b1 = 1
      b1 = 1;
      effetb1 = LOW;                        // Changement d'état du bouton non pris en compte
    }                                  
  }
    else if (effetb1 == HIGH){ b1 = 0; } // Si le changement d'état du bouton a été pris en compte, retour à l'état 0


  if (digitalRead(boutp) == LOW){ // Si appuis sur bouton "plus"
        reglagetemps = 1;
      }
      if (digitalRead(boutm) == LOW){ // Si appuis sur bouton "moins"
        reglagetemps = -1;
      }


   // Simulation appui boutons par bluetooth
  if (Serial.available()) {
    int Serialrecu = Serial.read();
    switch (Serialrecu) {
      case 'c':                    // Si "c" reçu, appuis court
        b1 = 1;        
        effetb1 = LOW;
        break;
      case 'l':                    // Si "l" reçu, appuis long
        b1 = 2;       
        effetb1 = LOW;
        break;
      case'p': 
        reglagetemps = 1; 
        //Serial.println("plus");
        break;
      case'm':
        reglagetemps = -1; 
        //Serial.println("moins");
        break;
    }
  }
}

En fait dans la fonction loop (qui est en fait une autre fonction dans mon programme de base) le “swicth (count) {}” ne semble pas s’executer normalement:
Quand je suis à “case 5:”, je recois “5” par voie série, mais rien pour le “case 6:”.

Le problème est surement tout bête mais j’arrive pas à avancer, je me tourne donc vers vous.
J’espère ne pas avoir oublié des infos, n’hésitez pas à me demander des précision.

Bonne soiré à vous! :slight_smile:

Selon la référence Arduino :

Parameters
var: a variable whose value to compare with various cases. Allowed data types: int, char.
label1, label2: constants. Allowed data types: int, char.

Ta variable count doit être un int, pas un byte.

Merci de ta réponse Lesept !

J'avais déjas essayé avec un int pour la variable count mais sans changement....

Bonjour,

C'est que count ne prend jamais la valeur 6.
Affiches count avant le switch

Salut Kamill :slight_smile:

J’affiche la valeur de count sur l’écran oled et après 5 il est bien égal à 6…

Peux-tu tester en changeant ceci :

          float incqteL = reglagetemps;
          qteL = qteL + (incqteL * 0.05);

par :

          qteL = qteL + (reglagetemps * 0.05);

hello
ne me demande pas pourquoi,
dans le
case 5:
Serial.println(“5”);

float incqteL = reglagetemps;

vires le float et déclare incqtel en globale

ca fonctionne

Effectivement le problème vient de "float incqteL" déclaré dans case 5: .
J'ai écrit qteL = qteL + (reglagetemps * 0.05); comme vous m'avez dit et ca fonctionne !
Merci beaucoup pour votre aide! Je me rappele que j'avais rajouté cette variable parceque l'incrémentation décimale ne marchais pas mais maintenant ca marche sans ! J'avais du faire une erreur ailleur...

Du coup pour savoir: Il faut jamais déclarer de variable dans un switch ?

Merci encore pour votre aide ! :slight_smile:

C’est bizarre. Normalement c’est juste un warning (du moment qu’on n’essaie pas d’utiliser la variable en dehors du case).

Pour définir une variable locale à un case il faut englober le traitement du case dans des accolades

        case 5:
          {
            Serial.println("5");
            float incqteL = reglagetemps;
            qteL = qteL + (incqteL * 0.05);
            if (qteL > 2) {
              qteL = 0;
            }
            else if (qteL < 0) {
              qteL = 2;
            }
          }
          break;

effectivement, en mettant des accolades, ca fonctionne

a noter que sans les accolades, c'e sont les cases suivants qui ne fonctionnent plus

Effectivement ca marche avec les accolades !

Merci Kamill de cette précision !

Edit: Je vien de voir qu'il faut aussi des accolades pour appeler une fonction externe

jogia:
Edit: Je vien de voir qu'il faut aussi des accolades pour appeler une fonction externe

Je ne pense pas. A moins que je n'ai pas compris le contexte.

J'ai déjà eu ce problème. En fait sans les accolades, une variable est définie jusqu'à la fin du bloc, mai le bloc ne finit pas à la case d'après, on peut écrire:
switch (nom) {
case boniche: Serial.print("va me chercher des croissants et ");
case normal: Serial.println("fais moi la bise");
break;
case matrone: Serial.printl("je vais te chercher le pain");
}
Dans cet exemple, le case boniche fait aussi les instructions de case normal. En fait case xxx est l'équivalent d'un goto, c'est pour cela que l'on est obligé de mettre un break à la fin d'un case si on ne veut pas que cela se poursuive à au case d'après.
En déclarant une variable dans un case qui n'est pas local à un case, on ne peut plus faire les case suivants car il y a une variable qui est accessible mais qui n'est pas déclarée.
Notre compilateur devrait générer une erreur, mais il supprime méchamment la suit du code.
En mettant des { }, la variable devient locale au bloc, c.a.d jusqu'à } et sa portée ne continue pas dans le case suivant, qui est donc compilé.

Je viens de voir qu'il faut aussi des accolades pour appeler une fonction externe

Je ne comprends pas Exemple?

Tout à fait exact Villeroi

Ça vient de l’approche prise pour traiter un statement de type switch case par la syntaxe. Ça s’écrit: switch ( condition ) statement
Il n’y a donc qu’un seul statement avec des points d’entrées car généralement on va mettre un compound statement avec les labels case: and default:

La spec C++ dit

Because transfer of control is not permitted to enter the scope of a variable, if a declaration statement is encountered inside the statement, it has to be scoped in its own compound statement:

Comme La notion de portée peut s’étendre entre cases (ça dépend où on met le break) et le compilateur pouvant sauter une partie du code (de case en case) Si on utilise une variable déclarée dans le switch, il faut définir sa portée, donc mettre un bloc englobant par des accolades.

Sinon concernant ce point:

lesept:
Selon la référence Arduino :
Ta variable count doit être un int, pas un byte.

la doc arduino prend un raccourci. Vous pouvez avoir le type que vous voulez du moment qu’il peut se promouvoir en un type intégral (un nombre entier) identique à celui exprimé dans la condition du switch et est une constant expression (constante évaluable par le compilateur). La spec dit

a constant expression of the same type as the type of condition after conversions and integral promotions

donc byte, uint32_t, int, char, .... sont tous possibles.

Il n’y a aucun besoin d’accolades par contre pour un appel de fonction, mais attention aux macros qui définiraient (bêtement) une variable temporaire sans avoir mis d’accolades cependant.