Variable qui reset a chaque tour de loop()

Bonjour,

Je suis novice en arduino. Je concois un escape game, étant animateur pour enfants: une rangée de leds et 3 boutons: deux pour choisir la led à allumer, un pour valider.
Il faut allumer les leds dans le bon ordre. Je stocke donc dans la variable "code" l'étape dans laquelle j'en suis dans l'accomplissement de l'allumage des leds.
L'idée est qu'a chaque fois que la bonne led est allumée, j'incrémente "code" pour passer a l'étape supérieure.

Seulement, d'après le moniteur série, code s'incrémente bien quand j'active la bonne led, mais dès le prochain tour de loop(), il retombe a zero (j'ai mis des print un peu partout pour en déduire ça).

Je m'arrache les cheveux dessus sans comprendre...

Je vous met mon code en entier, il est pas long. Le point critique est à partir de la ligne 120 (le switch)

Merci énormément pour l'aide que vous pourriez l'apporter, je suis dans l'impasse...

int SER_Pin = 5;   //pin 14 on the 75HC595
int RCLK_Pin = 6;  //pin 12 on the 75HC595
int SRCLK_Pin = 7; //pin 11 on the 75HC595


const int btn1 = 2; //the number of the key pin
const int btn2 = 3; //the number of the key pin
const int btn3 = 4; //the number of the key pin

int redpin = 8; //select the pin for the red LED
int bluepin =9; // select the pin for the blue LED
int greenpin =10;// select the pin for the green LED

int activ = 1;
bool valid = false;
bool btn1c= false;
bool btn2c= false;
bool btn3c= false;
bool change = true;
 
//How many of the shift registers - change this
#define number_of_74hc595s 1 
 
//do not touch
#define numOfRegisterPins number_of_74hc595s * 8
 
boolean registers[numOfRegisterPins];

int code;
 
void setup(){

  Serial.begin(9600);
 
  pinMode(SER_Pin, OUTPUT);
  pinMode(RCLK_Pin, OUTPUT);
  pinMode(SRCLK_Pin, OUTPUT);

  pinMode(btn1, OUTPUT);
  pinMode(btn2, OUTPUT);
  pinMode(btn3, OUTPUT);

  pinMode(redpin, OUTPUT);
  pinMode(bluepin, OUTPUT);
 
  //reset all register pins
  clearRegisters();
  writeRegisters();
}               
 
//set all register pins to LOW
void clearRegisters(){
  for(int i = numOfRegisterPins - 1; i >=  0; i--){
     registers[i] = LOW;
  }
} 
 
//Set and display registers
//Only call AFTER all values are set how you would like (slow otherwise)
void writeRegisters(){
 
  digitalWrite(RCLK_Pin, LOW);
 
  for(int i = numOfRegisterPins - 1; i >=  0; i--){
    digitalWrite(SRCLK_Pin, LOW);
 
    int val = registers[i];
 
    digitalWrite(SER_Pin, val);
    digitalWrite(SRCLK_Pin, HIGH);
 
  }
  digitalWrite(RCLK_Pin, HIGH);
 
}
 
//set an individual pin HIGH or LOW
void setRegisterPin(int index, int value){
  registers[index] = value;
}
 
void loop(){

    if(digitalRead(btn1) ==HIGH )
    {
      btn1c = true;
    }
    else if(btn1c) {
      btn1c = false;
      change = true;
      if(activ<8)
        activ++;
      else
        activ = 1;
    }
     if(digitalRead(btn3) ==HIGH )
    {
      btn3c = true;
    }
    else if(btn3c) {
      btn3c = false;
      change= true;
      if(activ>1)
        activ--;
      else
        activ = 7;
    }
    if(digitalRead(btn2) ==HIGH )
    {
      btn2c = true;
    }
    else if(btn2c) {
      btn2c = false;
      valid=true;
    }
    if(valid) {
      valid = false;
      Serial.print(code);
      Serial.print(activ);
      //code = 5263
       switch (code) {
      case 0:
        if(activ == 5)
          code = 1;
         else
          code = 0;
        break;
      case 1:
        if(activ == 2)
          code = 2;
         else
          code = 0;
        break;
       case 2:
        if(activ == 6)
          code = 3;
         else
          code = 0;
        break;
       case 3:
        if(activ == 3)
          code = 4;
         else
          code = 0;
        break;
      }
      Serial.print(code);
      Serial.print(activ);
      //output an frequency
      if(code == 4) {
        for(int c=0;c<80;c++)
        {
          analogWrite(greenpin, 255);
        }
      }
      else {
        activ=1;
        change = true;
      }
      delay(500);
    }
 if (change) {
  change = false;
  Serial.print(code);
  Serial.print(activ);
   for(int i=1; i<9; i++)
        setRegisterPin(i, LOW);
      setRegisterPin(activ, HIGH);
      writeRegisters();
 }
      
   /*
  for(int i = 1; i < 9; i++) {
    setRegisterPin(i-1, LOW);
    setRegisterPin(i, HIGH);
    writeRegisters();
    delay(1000);
  }

  /*
  setRegisterPin(2, HIGH);
  setRegisterPin(3, HIGH);
  setRegisterPin(4, LOW);
  setRegisterPin(5, HIGH);
  setRegisterPin(7, HIGH);
 
  writeRegisters();  //MUST BE CALLED TO DISPLAY CHANGES
  //Only call once after the values are set how you need.
  */
}

Je suis loin d'être un pro du C, mais ton utilisations de "else if" me perturbe ! Peut être que c'est une façon de faire propre au C, mais j'en doute.

Bonjour, pourquoi donc ?
Ca me permet d'executer le code quand je relache le bouton seulement. Sinon il s'effectue plusieurs fois tant que je suis appuyé.
Je n'ai pas pris le temps de regarder d'autres codes donc peut être (sûrement) qu'habituellement on ne fait pas comme ca, mais ca fonctionne

Pour faire un front descendant il déjà un anti-rebond en amont (matériel ou logiciel)

Ensuite le plus simple c'est de faire un et logique entre la valeur du bouton et ça valeur précédente :
Moi je fais un truc dans ce genre là (je te laisse traduire en C)

LectureBouton = DigitalRead(MonBouton)

SI (LectureBouton = Faux ET PreviousLectureBouton = Vrai) {
--Action à faire en cas de front descendant--
}

PreviousLectureBouton = LectureBouton

C'est ainsi qu'on fait dans les automates programmables et dans quantité de programmes depuis très longtemps.

Maintenant peut être qu'on peut faire a ta façon, cette utilisation de Else If me parait peu orthodoxe; mais des pro du C me contrediront peut être.

Ton code est complexe, les tests sont imbriqués : ça rend difficile d'en prévoir le comportement. Tu devrais le tester par morceaux ou faire afficher l'ensemble des variables importantes (code, valid, activ, change, etc). Tu peux faire une fonction pour ça puisque les variables sont globales.

Merci pour vos réponses.
A la base j'avais des if/else if a la place du switch sans tests imbriqués (avec if activ=5 && code=1). J'ai changé pour voir si ca venait pas de la.
Mon code est degeu parce que je l'ai beaucoup modifié. Je vais le reecrire completement en utilsiznt la bibliotheque proposée pour les boutons poussoirs et je reviens vers vous.
Cependant, avez-vous une idée de l'origine possible de mon probleme ?

Bonjour

L'expérience du C nous apprend que :

Quand on a un programme qui se comporte de manière non attendue, nous y collons des mouchards sur les variables (ici Serial.print) pour essayer de comprendre ce qui se passe.

Et là, il arrive de constater qu'une variable évolue de manière incontrôlée, d'où le

kreys83:
Je m'arrache les cheveux dessus sans comprendre...

A ce stade, il faut chercher un débordement mémoire, car c'est l'explication la plus courante.
Et le débordement le plus courant concerne les tableaux.

Et ça tombe bien, il y a justement un tableau dans ton code :

...
bool change = true;
 
//How many of the shift registers - change this
#define number_of_74hc595s 1 
 
//do not touch
#define numOfRegisterPins number_of_74hc595s * 8
 
boolean registers[numOfRegisterPins];

...

void setRegisterPin(int index, int value){
  registers[index] = value;
}

...


 if (change) {
  change = false;
...
   for(int i=1; i<9; i++)
        setRegisterPin(i, LOW);
...

registers est un tableau de taille 8
l'index va de registers[0] à registers[7] inclus

Si le programme modifie index[8] (ce qui est bien le cas ici), tu vas tout simplement modifier le contenu de la RAM dans un endroit qui ne correspond plus au tableau registers, mais à la variable suivante en RAM.

Et sous réserve des paramètres du compilo, les variables globales sont rangées en RAM dans l'ordre inverse de leur apparition dans le code. Donc en RAM, juste après registers, on doit trouver la variable bool change;. Modifier registers[8] revient à modifier le contenu de la variable change.

Pas sûr que ce soit le seul problème de ton programme, mais il y a au moins celui-là

Bonjour,
Merci d'avoir pris le temps me faire cette reponse complète.
Effectivement j'ai mis des mouchars partout (print activ et print code) et j'ai fait 40 000 tests pour voir ou ca deconne. Code s'incremente bien mais des le prochain tour im retombe a 0 (au debut du loop).
Je vais me pencher plus sérieusement sur ton explication ce soir. Merci beaucoup.