comment sortir d'une boucle ?

Bonjour, je me suis déjà présenté et je ne voudrais pas faire un copié collé de ce que j'ai déjà écrit.
j'ai imaginé un petit chenillard avec quatre led qui serait commander par un bouton poussoir. (Histoire que je comprenne bien les boucles)
Pour le moment, lorsque j'appuie sur le poussoir le chenillard démarre mais je n'arrive pas à le stopper en ré appuyant sur le poussoir. Je me casse la tête avec les boucles et n'arrive plus à en sortir. Si je post c'est que déjà j'y est passé bien des heures. Je vous remercie pour votre aide.

voici la bête :

/*Ce petit programme que j'ai créé fait le schéma suivant : toutes les led sont étientes, puis lorsqu'on appui sur le 
bouton poussoir, elles s'allument les unes après les autres sans s'arrêter....je n'arrive pas à le finaliser ...réappuyer 
sur le poussoir pour que le cycle s'arrête, puis redémarre lorsqu'on réappui !!!!

*/


const int LED [4] = {2,3,4,5};      //DECLARATION DE TABLEAU DE LED ET DE PIN UTILISE
const int BP = 6;                   // DECLARATION DE BOUTON POUSSOIR EN PIN 6
int BPap = 0;                       //VARIABLE ETAT BP SI APPUYE
int BPval =1;                       //VARIABLE ETAT BP SI PAS APPUYE

void setup(){
 for(int i=0; i<4; i++){           //TABLEAU EN PIN MODE SORTIE
   pinMode(LED[i], OUTPUT);
 }   //FIN FOR
 pinMode(BP, INPUT);               //POUSSOIR EN MODE ENTREE
 digitalWrite(BP, HIGH);          //Poussoir raccordé au + INTERNE
}
void loop(){
BPval = digitalRead(BP);          //LECTURE DE L ETAT DU POUSSOIR
delay(250);                       //ANTI REBOND
if (BPval == LOW){          //si BP appuyé

 for(int i=0;i<4;i++){     //fonction for allumage led à tour de role
   digitalWrite(LED[i], HIGH);
   delay(250);
   digitalWrite(LED[i], LOW);
 }                        //FIN FOR
}                          //FIN IF                  
 BPval = digitalRead(BP);  //POUR QUE CELA TOURNE EN BOUCLE, RE LECTURE DU BP
 while (BPval == LOW){       //TANT QUE BPval EST AU NIVEAU BAS
   
 for(int i=0; i<4;i++){    //fonction for POUR CONTINUER LE CYCLE...
 digitalWrite(LED[i], HIGH);
 delay(250);
 digitalWrite(LED[i], LOW);
 delay(250);
 }                        //FIN FOR
}                         //FIN WHILE
 }                           //fin loop

hello
ICI

Tu devrais faire ton digitalWrite dans LED[ i ] et pas LED :
    digitalWrite(LED[i], xxx);xxx = HIGH ou LOW

Par contre, aucune raison de faire un digitalWrite sur BP, tu dois le déclarer en INPUT_PULLUP :

  pinMode(BP, INPUT);               //POUSSOIR EN MODE ENTREE
  digitalWrite(BP, HIGH);          //Poussoir raccordé au + INTERNE

devient  pinMode(BP, INPUT_PULLUP); 

Pour ton problème d'arrêt et relance du chenillard, il faut définir un état comme

boolean ChenillardOK = true;

Puis dans la loop, tu boucles sur le chenillard selon son état (allumé si ChenillardOK est à true, éteint sinon) tout en scrutant l'état du bouton : si le bouton est appuyé, tu changes l'état (true devient false, false devient true)

ChenillardOK  = !ChenillardOK ;

Pour éviter que ça aille trop vite, tu pourrais mettre un delay mais tu risquerait de louper un appui sur le bouton : il faut utiliser millis (cherche des tutos sur le forum). Enfin, pour l'antirebond, un delay(25) est suffisant (250 c'est trop long)

A toi de jouer ! Si tu dois poster un code, utilise les balises CODE (bouton </>)

Pour faire cela maintenant

pinMode(BP, INPUT);               //POUSSOIR EN MODE ENTREE
  digitalWrite(BP, HIGH);          //Poussoir raccordé au + INTERNE

onutilisepinMode(BP, INPUT_PULLUP);

Un délai de 15 ou 20ms est suffisant pour l’anti-rebond de la majorité des petits boutons des kits, à 250ms ça va vraiment jouer sur la réactivé de votre montage et être perceptible par l’utilisateur
Surtout si vous le faites à tous les coups

Sinon ça c’est pas bon

BPval = digitalRead(BP);  //POUR QUE CELA TOURNE EN BOUCLE, RE LECTURE DU BP
  while (BPval == LOW){       //TANT QUE BPval EST AU NIVEAU BAS

—> qu’est ce qui change BPVal dans le while ??

Sinon C’est typiquement une définition de programme qui se prête bien à la programmation par machine à états (cf mon tuto éventuellement)

Merci beaucoup pour votre aide.
Je vais m'y replonger...
Olivier

Bonsoir,
j'ai trouvé un truc qui fonctionne comme je le voulais. Je suis sur qu'il doit y avoir plus simple, mais ça fonctionne !!! je suis trop content. Le voici :

/*Ce petit programme que j'ai créé fait le schéma suivant : toutes les led sont étientes, puis lorsqu'on appui sur le 
bouton poussoir, elles s'allument les unes après les autres sans s'arrêter....puis lorsqu'on réappuis  
sur le poussoir le chenillard s'arrête !! c'est un début, c'est pas facile et merci pour les conseils
 
 */


const int LED [4] = {2,3,4,5};      //DECLARATION DE TABLEAU DE LED ET DE PIN UTILISE
const int BP = 6;                   // DECLARATION DE BOUTON POUSSOIR EN PIN 6
const int APPUI = 0;                //CONSTANTE  ETAT DU BP -APPUI SUR NIVEAU BAS
//-----DECLARATION DES VARIABLES GLOBALES ----------
int ETAT_BP=0;       //VARIABLE ETAT BP
/*int ETAT_LED[4] = 0; //VARIABLE ETAT BP*/
// LA FONCTION SETUP () EST EXECUTEE EN PREMIER ET UNE SEUL FOIS, AU DEMARRAGE DU PRG
void setup(){
  for(int i=0; i<4; i++){           //TABLEAU EN PIN MODE SORTIE
    pinMode(LED[i], OUTPUT);        //MET LES LED EN SORTIE
  }   //FIN FOR
  pinMode(BP, INPUT);               //POUSSOIR EN MODE ENTREE
  digitalWrite(BP, HIGH);          //Poussoir rappel au +
}
void loop(){
ETAT_BP = digitalRead(BP);          //LECTURE DE L ETAT DU POUSSOIR ET LA MEMORISER
//TESTER L ETAT DU BP MEMORISER ET ALLUMER LES LED

if  (ETAT_BP==APPUI){          //si BP appuyé
  for(int i=0;i<4;i++){     //fonction for allumage led à tour de role
    digitalWrite(LED[i], HIGH);
    delay(25);
    digitalWrite(LED[i], LOW);
  }                        //FIN FOR
}                          //FIN IF    
              
  ETAT_BP = digitalRead(BP);  //POUR QUE CELA TOURNE EN BOUCLE, RE LECTURE DU BP
  while(ETAT_BP == 0){       //TANT QUE BPval EST AU NIVEAU BAS
    
  for(int i=0; i<4;i++){    //fonction for POUR CONTINUER LE CYCLE...
  digitalWrite(LED[i], HIGH);
  delay(25);
  digitalWrite(LED[i], LOW);
  delay(25);
  }       //FIN FOR
  if (digitalRead(BP)==APPUI){
  digitalWrite(LED[4],HIGH);
  delay (5000);
  digitalWrite(LED[4], LOW);
  break;
 }
 }                         //FIN if
 
/* else {
  
  digitalWrite(LED[4], 0);
 
 }*/
  }                           //fin loop

Tu as vraiment testé et ça marche comme tu veux ? Si tu appuies sur ton bouton pendant les 5 secondes du delay, l'appui ne sera pas pris en compte.

Sinon, c'est possible que ça marche, mais côté programmation (et je suis loin d'être un pro), c'est un peu lourd...

Sérieusement - faut pas être content, c'est du grand n'importe quoi... (désolé d'être un peu "cash")

:slight_smile: :))

Vous avez toujours les soucis de

ETAT_BP = digitalRead(BP);  //POUR QUE CELA TOURNE EN BOUCLE, RE LECTURE DU BP
while(ETAT_BP == 0){       //TANT QUE BPval EST AU NIVEAU BAS
   ...
}

--> le while ne remettant pas à jour la variable ETAT_BP, vous ne sortirez JAMAIS de ce while, sauf si vous faites un break dans le while....

Et c'est ce que vous faites à la fin après un mega delay de 5 secondes - donc le bouton peut faire ce qu'il veut pendant ces 5 secondes, personne ne regardera - avec le code suivant:

  if (digitalRead(BP)==APPUI){
  digitalWrite(LED[4],HIGH);
  delay (5000);
  digitalWrite(LED[4], LOW);
  break;
 }

et qui plus est, dans ce code vous titillez une pin (soi disant la 5ème LED) en lisant le 5ème élément d'un tableau qui n'en comporte que 4... c'est quoi cette idée?

--> en pratique ce que fait votre code c'est que si vous n'avez pas relâché le bouton en moins de 100ms alors vous rentrez dans le while et si vous ne l'avez toujours pas relâché 200ms encore plus tard alors vous rentrez dans ce second test qui bloque tout pour 5 secondes et execute le break qui sort de la boucle...

ça ne semble pas du tout correspondre à l'énoncé initial...

Vous lisez deux fois l’état du bouton dans la loop, une fois devrait suffire... mettez un drapeau pour dire que vous avez démarré le chevillard et êtes en attente du relâchement du bouton puis au prochain enfoncement vous arrêtez

Sinon le code est assez illisible... sautez des lignes entre les fonctions et appuyez sur ctrl-T dans l’éditeur pour indenter le code correctement

Effectivement tu as raison, les 5 s c'est pas top. J'ai réduit à 50 ms, c'est mieux.
Par contre si je voulais rallonger le temps d'éclairage du chenillard, il faudrait que j'utilise "millis". Pas facile quand même. Dans ce petit essai, je voulais créer un tableau, utiliser une boucle for avec un poussoir pour la commande et finalement j'ai utiliser aussi "break". Je tatonne, mais c'est super.

Merci

C’est bien d’explorer mais prenez de bonnes bases...

Par exemple c'est quoi ce délire   digitalWrite(LED[4],HIGH);vous n'avez aucune LED connectée en LED[4] (avec un peu de chance c'est pas une valeur de pin autorisée, sinon ça peut faire n'importe quoi sur une pin...)

Bon allez - comme j'ai rien de spécial pour m'occuper... tenez voici un petit bout de code (tapé ici donc je ne sais pas si ça compile et si ça marche), pour le principe et qui correspondrait à une petite machine à 4 états.

const byte pinLED[] = {2, 3, 4, 5};
const byte nbLEDs = sizeof(pinLED) / sizeof(pinLED[0]);

const byte pinBP = 6;
const unsigned long antiRebond = 15; // attente de stabilisation du bouton

byte LEDenCours; // le LED qui est allumé lorsque le chenillard tourne
unsigned long chronoDernierAllumage;
const unsigned long duree = 50; // vitesse du chenillard

enum : byte {ATTENTE_1ER_APPUI, ATTENTE_1ERE_RELACHE, ATTENTE_2ND_APPUI, ATTENTE_2NDE_RELACHE} etat;

// ----------------------------------------------------------------------------------------
// Teste si c'est le moment d'allumer la prochaine LED, si oui on le fait
// ----------------------------------------------------------------------------------------
void testePassageLEDSuivante()
{
  if (millis() - chronoDernierAllumage >= duree) {
    digitalWrite(pinLED[LEDenCours], LOW); // on éteint celle en cours
    LEDenCours = (LEDenCours + 1) % nbLEDs; // on passe à la suivante, le modulo fait qu'on va compter 0, 1, 2, 3, puis 0, 1, 2, 3 etc
    digitalWrite(pinLED[LEDenCours], HIGH); // on l'allume
    chronoDernierAllumage = millis(); // on se souvient de quand c'était
  }
}


// ----------------------------------------------------------------------------------------
// configuration initiale
// ----------------------------------------------------------------------------------------
void setup() {
  for (int i = 0; i < nbLEDs; i++) {
    pinMode(pinLED[i], OUTPUT);    // en sortie
    digitalWrite(pinLED[i], LOW);  // éteinte
  }
  pinMode(pinBP, INPUT_PULLUP);
  etat = ATTENTE_1ER_APPUI;
}


// ----------------------------------------------------------------------------------------
// GESTION DE LA MACHINE A ETAT
// -----------------------------------------------------------------------------------------
void loop() {
  switch (etat) {

    case ATTENTE_1ER_APPUI:
      // ----------------------------------------------------------------------------------------
      // on est au repos, on ne fait rien tant que le bouton n'est pas appuyé
      // ----------------------------------------------------------------------------------------
      if (digitalRead(pinBP) == LOW) { // on a appuyé
        delay(antiRebond); // anti-rebond du pauvre
        etat = ATTENTE_1ERE_RELACHE;
        LEDenCours = 0;
        digitalWrite(pinLED[LEDenCours], HIGH);
        chronoDernierAllumage = millis();
      }
      break;

    case ATTENTE_1ERE_RELACHE:
      // ----------------------------------------------------------------------------------------
      // le bouton est appuyé, le chenillard tourne; on attend la relâche
      // ----------------------------------------------------------------------------------------
      testePassageLEDSuivante();

      if (digitalRead(pinBP) == HIGH) { // on a relâché
        delay(antiRebond); // anti-rebond du pauvre
        etat = ATTENTE_2ND_APPUI;
      }
      break;

    case ATTENTE_2ND_APPUI:
      // ---------------------------------------------------------------------------------------------
      // le bouton est relâché, le chenillard tourne; on attend le nouvel appui pour éteindre tout
      // ---------------------------------------------------------------------------------------------
      testePassageLEDSuivante();

      if (digitalRead(pinBP) == LOW) { // on a appuyé à nouveau
        delay(antiRebond); // anti-rebond du pauvre
        etat = ATTENTE_2NDE_RELACHE;
        for (int i = 0; i < nbLEDs; i++) digitalWrite(pinLED[i], LOW);
      }
      break;

    case ATTENTE_2NDE_RELACHE:
      // ----------------------------------------------------------------------------------------
      // le bouton est appuyé, le chenillard est arrêté; on attend la relâche pour recommencer
      // ----------------------------------------------------------------------------------------
      if (digitalRead(pinBP) == HIGH) { // on a relâché
        delay(antiRebond); // anti-rebond du pauvre
        etat = ATTENTE_1ER_APPUI;
      }
      break;
  }
}

dans ce code la boucle teste en permanence dans quel état on est et réagit en fonction de cela. On peut être au repos, c'est à dire en attente du premier click sur le bouton (état = ATTENTE_1ER_APPUI). tant qu'on n'a pas appuyé, on ne fait rien.

Au moment où on appui, on allume la première LED, on mémorise le moment d'allumage et on change d'état - on passe à ATTENTE_1ERE_RELACHE. Dans cet état le chevillard doit tourner, donc on appelle la fonction qui vérifie si la durée d'attente entre 2 LEDs et atteinte et si oui on éteint la LED en cours et on allume la suivante, puis on vérifie si le bouton est relâché. tant qu'il n'est pas relâché on reste dans cet état et donc le chenillard tourne.

une fois le bouton relâché, on passe à l'état ATTENTE_2ND_APPUI. Dans cet état on continue le chenillard (donc appelle la fonction testePassageLEDSuivante()) et on vérifie le bouton. Tant qu'il n'est pas appuyé de nouveau le chenillard continue à tourner.

une fois le bouton appuyé à nouveau, on éteint tout et on passe à l'état ATTENTE_2NDE_RELACHE.

une fois le bouton relâché, on repasse à l'état de début ATTENTE_1ER_APPUI et on est prêt à recommencer.

(On pourrait ne faire qu’avec deux états en testant juste appui et relâche et avoir une variable supplémentaire qui dirait si on est en état « chenillard actif » ou pas pour décider de l’action. J’ai préféré 4 états car c’est plus simple à lire comme cela)

c'est le principe de la programmation par machine à états que j'explique dans mon petit tuto si vous voulez mieux comprendre

Voilà - en espérant que ce code fonctionne (à vérifier, je suis dans un train juste sur mon tel) et qu'il vous donnera des pistes pour vos programmes de ce genre.