Partage
  • Partager sur Facebook
  • Partager sur Twitter

Problème Bouton Poussoir

Sujet résolu
    5 juin 2020 à 11:25:02

    Bonjour !

    Je suis débutant sur Arduino et je rencontre un petit problème que je ne comprend pas.

    Lorsque j'appuie sur le bouton poussoir mon programme se déclenche mais quand je rappuie,  le programme ne s'éteint pas et reste allumé. Quelqu'un pourrait-il m'expliquer mon erreur ?

    //déclaration des variables
    int ledBasGauche = 2;
    int ledBasDroite = 3;
    int ledCentre = 4;
    int ledHautGauche = 5;
    int ledHautDroite = 6;
    int pinBouton = 8;
    int nbalea;
    boolean allumage = 1;
    
    void setup()
    {
      //on fait une boucle pour mettre les leds en mode OUTPUT
      for (int p = 2; p < 7; p++)
      {
        pinMode(p, OUTPUT);
        digitalWrite(p, LOW);
      }
    
      Serial.begin(9600);
      randomSeed(analogRead(0));
    
      //on met notre bouton poussoir en mode INPUT_PULLUP
      pinMode(pinBouton, INPUT_PULLUP );
      Serial.println("**************PROGRAMME DU DES******************");
    }
    
    void loop()
    {
      // Lecture de l'etat du bouton et stockage dans une nouvelle variable
      boolean etatBouton = digitalRead(pinBouton);
      Serial.println(etatBouton);
      //Si on appuie sur le bouton(donc la valeur du bouton devient 1)
      if (etatBouton == 0)
      {
        //Et que les leds étaient allumées
        if (allumage ==  0 )
        {
          // Alors on éteint les lumières
          allumage = 1;
        }
        //Sinon
        else
        {
          //Alors on allume les lumières
          allumage = 0;
        }
        delay(200);
      }
      //si le bouton poussoir = 1
      if (allumage==0)
        //Alors ...
      {
        //On tire un chiffre au hasard
        nbalea = random(0, 6);
        //On affiche ce chiffre dans la console
        //Et on appelle notre fonction qui allume nos leds(allumageLed)
        allumageLed(nbalea);
        delay(1000);
        zero();
      }
      //Si le bouton pressoir = 0
      else  
      {
        zero();
      }
      delay(200);
    }
    
    // On crée une fonction pour allumer les leds en fonction du chiffre aléatoire tiré (nbalea)
    void allumageLed(int nombreAleatoire)
    {
      //si le nombre aléatoire est 1
      if (nombreAleatoire == 1)
        //Alors...
      {
        //On allume la ou les leds en question
        digitalWrite(ledCentre, HIGH);
        //On retourne le résultat
        return;
      }
    
      //si le nombre aléatoire est 2
      if (nombreAleatoire == 2)
        //Alors...
      {
        //On allume la ou les leds en question
        digitalWrite(ledHautDroite, HIGH);
        digitalWrite(ledBasGauche, HIGH);
        //On retourne le résultat
        return;
      }
    
      //si le nombre aléatoire est 3
      if (nombreAleatoire == 3)
        //Alors...
      {
        //On allume la ou les leds en question
        digitalWrite(ledHautDroite, HIGH);
        digitalWrite(ledBasGauche, HIGH);
        digitalWrite(ledCentre, HIGH);
        //On retourne le résultat
        return;
      }
    
      //si le nombre aléatoire est 4
      if (nombreAleatoire == 4)
        //Alors...
      {
        //On allume la ou les leds en question
        digitalWrite(ledHautDroite, HIGH);
        digitalWrite(ledBasGauche, HIGH);
        digitalWrite(ledBasDroite, HIGH);
        digitalWrite(ledHautGauche, HIGH);
        //On retourne le résultat
        return;
      }
    
      //si le nombre aléatoire est 5
      if (nombreAleatoire == 5)
        //Alors on crée une boucle qui allume toutes les lumières
      {
        for ( int p = 2; p < 7; p++)
        {
          digitalWrite(p, HIGH);
        }
        //On retourne le résultat
        return;
      }
    }
    
    
    // On fait une fonction pour mettre toutes nos leds éteintes (elle servira pour le 0 du dé)
    void zero()
    {
      //On fait une boucle pour mettre les leds en mode LOW
      for ( int p = 2; p < 7; p++)
      {
        digitalWrite(p, LOW);
      }
    }

    Merci beaucoup pour vos prochaines réponses ! 

    • Partager sur Facebook
    • Partager sur Twitter
      Staff 5 juin 2020 à 12:24:46

      Quand ton programme est éteint, le loop de ton programme se résume pratiquement à un digitalRead puisque l'arduino n’exécute aucun des if.

      Du coup, la réactivité est très bonne puisque ton arduino passe son temps à lire en boucle l'état du bouton.

      En revanche, une fois ton programme activé, l'arduino fait d'autres chose, dont un delay assez long de 1000ms après avoir activé les LED.

      Le problème, c'est que pendant que l'arduino exécute la fonction delay, il ne fait rien d'autre.

      Donc si tu appuis et relâche le bouton pendant que l'arduino était en train de faire un delay, ton appuis sera tout simplement ignoré.

      Avec ton programme actuel, un appuis n'est détecté que lorsque le bouton est enfoncé au moment de la lecture, qui a lieux environ toutes les secondes.

      Tu verras que si tu reste appuyé sur ton bouton pendant une seconde, l'arduino finira par le détecter.

      Pour corriger le problème, plusieurs solutions possibles :

      - utiliser les interruptions en mémoriser le fait que le bouton a été appuyé

      - revoir l'architecture pour ne pas utiliser delay mais plutôt des conditions basée sur l'utilisation de millis

      -
      Edité par lorrio 5 juin 2020 à 12:26:05

      • Partager sur Facebook
      • Partager sur Twitter
        5 juin 2020 à 13:02:34

        lorrio a écrit :

        Pour corriger le problème, plusieurs solutions possibles :

        - utiliser les interruptions en mémoriser le fait que le bouton a été appuyé

        - revoir l'architecture pour ne pas utiliser delay mais plutôt des conditions basée sur l'utilisation de millis


        Cela veut dire quoi au juste ? Désolé pour mon piètre niveau mais il y a un début à tout :ange:.....

        -
        Edité par La Laitière 5 juin 2020 à 13:35:50

        • Partager sur Facebook
        • Partager sur Twitter
          5 juin 2020 à 16:43:04

          Le problème à corriger vient de cette partie

          if (allumage==0)
            { 
              allumageLed(nbalea);
              delay(1000);
              zero();
            }
          

          pendant le delay d'une seconde, on ne regarde pas les boutons, donc on peut appuyer tant qu'on veut sur le bouton pendant cette seconde, ça lui en touche l'une sans remuer l'autre.

          Il faut (évidemment) modifier le programme pour corriger ça. Le problème, c'est que ce n'est pas une petite modification, il faut **complètement** changer de point de vue.

          Bon prenons un autre exemple.

          Spécification : Un bouton, une LED. Quand on appuie sur le bouton, la LED doit s'allumer une seconde.

          On peut penser à cette solution, en première approche

          fonction loop:
          
              si le bouton est appuyé {
                   allumer la led
                   attendre 1 seconde
                   éteindre la led
              }
          

          Bon, admettons. C'est le genre de truc qu'on voit dans les exemples genre "faire clignoter la diode".

          ALors on veut faire mieux, 2 boutons 2 leds

          fonction loop :
             
            si le bouton 1 est appuyé {
                allumer la led 1
                attendre une seconde
                eteindre la led 1
            }
            si le bouton 2 est appuyé {
                allumer la led 2
                attendre 1 seconde
                eteindre la led 2
            }
          

          et ça marche pas. On appuie sur un bouton ça allume une LED, mais si on appuie sur l'autre, la seconde ne s'allume pas. Parce qu'on est coincé sur le délai de la première.

          ---

          Changement radical à effectuer : on ne fait JAMAIS de délais. On surveille constamment les 2 boutons, et quand on a appuyé dessus pour allumer, on note quelque part a quelle heure il faudra éteindre. Et on surveille aussi constamment la pendule - l'heure est donnée par la fonction millis() -

          Solution selon ce schéma

          est_allume = faux
          heure_extinction = 0
          
          fonction loop :
          
              si est_allume et millis() > heure_extinction
              {
                 éteindre la LED
                 est_allumé = faux
              }
              si le bouton est appuyé
              {
                 heure_extinction = millis() + 1 seconde
                 allumer la LED
                 est_allumé = vrai;
              }
          
          

          Et là, on peut traiter les 2 boutons et les deux LEDs sans que l'une bloque l'autre.

          comme on voit, ce n'est PLUS DU TOUT la même logique que de caser un delay() pour tout bloquer.





          -
          Edité par michelbillaud 5 juin 2020 à 16:45:58

          • Partager sur Facebook
          • Partager sur Twitter
            5 juin 2020 à 17:21:42

            Merci énormément  pour cette explication détaillée , la communauté Arduino est top :D !

            Je vais de ce pas faire les changements nécessaires !

            • Partager sur Facebook
            • Partager sur Twitter
              Staff 5 juin 2020 à 17:42:32

              Ce qu'évoque michelbillaud correspond à la seconde solution que j'évoquais : revoir l'architecture pour ne pas utiliser delay mais plutôt des conditions basée sur l'utilisation de millis

              Cette solution est plus lourde à mettre en place quand on en a pas l'habitude mais elle offre l'avantage d'être plus générique et ne pas dépendre des capacité hardware du processeur (le nombre de pin d'interruption est limité sur arduino).

              Pour les interruptions, je te conseille d'aller faire un tour sur https://www.arduino.cc/reference/en/language/functions/external-interrupts/attachinterrupt/

              Dans leur code d'exemple, ils se servent de l'interruption pour changer l'état d'une variable avec state = !state; tandis que la fonction loop se charge d'écrire la valeur en boucle.

              Dans ton cas, tu pourrais utiliser l'interruption pour mémoriser que le bouton a été enfoncé, et agir ensuite.

              Exemple:

              const byte ledPin = 13;
              const byte interruptPin = 2;
              
              int state = 0;
              volatile byte pressed = 0;
              
              void setup() {
                  pinMode(ledPin, OUTPUT);
                  pinMode(interruptPin, INPUT_PULLUP);
                  attachInterrupt(digitalPinToInterrupt(interruptPin), bpirq, FALLING);
              }
              
              void loop() {
              	delay(5000);
              	if ( pressed == 1 ) {
              		pressed = 0;
              		state = !state;
              		digitalWrite(ledPin, state);
              	}
              }
              
              void bpirq() {
              	pressed = 1;
              }
              

              Pendant le delay de 5000ms, il ne se passe rien, hormis le fait que l'interruption associée au bouton est bien exécutée, passant la variable pressed à 1.

              Une fois le delay terminé, le code prendra en compte l'appuis sur le bouton et changera l'état de la LED.

              -
              Edité par lorrio 5 juin 2020 à 17:43:32

              • Partager sur Facebook
              • Partager sur Twitter

              Problème Bouton Poussoir

              × Après avoir cliqué sur "Répondre" vous serez invité à vous connecter pour que votre message soit publié.
              • Editeur
              • Markdown