Action sur bouton poussoir

Bonjour à tous,

Je cale sur une petite routine qui me pose un problème.

Matériel, Arduino Mega 2560, un encodeur rotatif KY-040

Il s'agit d'incrémenter une variable "consigne", si et seulement si le bouton poussoir "SW" est actionné.
Cette partie là à l'air de fonctionner.

Mais il s'agit également d'arrêter l'incrémentation et sortir de la routine, si l'on pousse une deuxième fois sur le poussoir, et pouvoir recommencer à l'envi.
C'est cette partie là qui ne fonctionne pas, serait-ce un problème de "while" ou de lecture du bouton?

Je soumet ce problème à votre sagacité et vous remercie par avance des réponses que vous voudrez bien y apporter.

Marc.

#include <Wire.h>
#include <Bounce2.h>

const byte SW = 5;
int CLK = 3;  // Pin 3 de CLK sur encodeur
int DT = 4;  // Pin 4 de DT sur encodeur
int consigne = 1; 
int rotation;
int value;
int valeur;
unsigned long DernierePression = 0;

Bounce bouton = Bounce();

void setup()
{
  Serial.begin(9600);
  Serial.println("REBOOT");
  pinMode (CLK,INPUT);
  pinMode (DT,INPUT);
  pinMode (SW,INPUT_PULLUP);
  bouton.attach(SW);  
  bouton.interval(10);

  digitalWrite(CLK, true);
  digitalWrite(DT, true);
  digitalWrite(SW, true);


}

void loop()
{
 bouton.update();
 int valeur = bouton.read();

    if (valeur == LOW) {
                       if (millis() - DernierePression > 50) {
                       Serial.println("Boutton pressé!");
                       rotation = digitalRead(CLK);
                       consigne = 0;
                                                             while (valeur == LOW) {  
                                                                                   value = digitalRead(CLK);
                                                                                   if (value != rotation) { 
                                                                                                          if (digitalRead(DT) != value){  
                                                                                                                                       consigne ++;
                                                                                                                                       } 
                                                                                   else {
                                                                                        consigne--;
                                                                                        if (consigne <= -1){
                                                                                                           consigne = 0;
                                                                                                           }
                                                                                        }
                                                                                    Serial.print("Consigne: ");
                                                                                    Serial.println(consigne);
                                                                                                          }
                                                                                    rotation = value;
                                                                                    bouton.update();
                                                                                    int valeur = bouton.read();
                                                                                    }
                                                            }
                        DernierePression = millis();
                        }
}

Bonjour,

Dans ta boucle while tu redéfinis une nouvelle variable valeur

        int valeur = bouton.read();

Il faut que tu supprimes la définition et que tu fasses une simple affectation

       valeur = bouton.read();

j'ai un bout de code d'exemple qui fait cela:
si on appuie sur le bouton, on passe en mode édition de la consigne, qu'on peut alors changer en tournant le bouton, et on en sort quand on appuie sur le bouton à nouveau.

Pour me simplifier la vie, j'utilise la biblothèque Encoder.h qui est super précise et la librairie SimpleBouton de @bricoleau

Voici le code, l'encodeur est connecté en 2 (DT) et 3 (CLK). Le bouton est connecté en 4.

// *** DEFINITION DE L'ENCODEUR ROTATIF ***
#include <Encoder.h> // https://www.pjrc.com/teensy/td_libs_Encoder.html
const byte encodeurDTPin = 2; // Encodeur DT
const byte encodeurCLKPin = 3; // Encodeur CLK
Encoder encodeurRotatif(encodeurDTPin, encodeurCLKPin); // attaché sur pins 2 (Encodeur DT) et 3 (Encodeur CLK)

// *** DEFINITION DU BOUTON ***
#include <simpleBouton.h> // cf @bricoleau cf http://forum.arduino.cc/index.php?topic=375232.0
const byte encodeurBoutonPin = 4;  //Cablage : pin 4 --- Encodeur SW (câblage en PULLUP fait par l'arduino)
simpleBouton boutonEncodeur(encodeurBoutonPin);

// *** CONSIGNE ***
long consigne = 0;

void afficheConsigne()
{
  Serial.print(F("Consigne: "));
  Serial.println(consigne);
}

// *** Machine à état pour la gestion d'un mode modification ***
enum : byte {MODE_NORMAL, MODE_MODIFICATION} modeActuel = MODE_NORMAL;

bool verifConsigne()  // retourne vrai si la consigne a été modifiée
{
  bool consigneChangee = false;
  static long ancienneConsigne = 0;
  static long anciennePosition = 0;

  boutonEncodeur.actualiser();
  
  switch (modeActuel) {
    
    case MODE_NORMAL: // on vérifie si le bouton a été appuyé, alors on passe en mode modification
      if (boutonEncodeur.vientDEtreEnfonce()) {
        encodeurRotatif.write(0); // on met le compteur à 0
        ancienneConsigne = consigne;
        anciennePosition = 0;
        Serial.print(F("MODE MODIFICATION, ")); afficheConsigne();
        modeActuel = MODE_MODIFICATION;
      }
      break;
      
    case MODE_MODIFICATION:
      if (boutonEncodeur.vientDEtreEnfonce()) {
        Serial.print(F("MODE NORMAL, ")); afficheConsigne();
        modeActuel = MODE_NORMAL;
      } else {
        long nouvellePosition = encodeurRotatif.read() >> 1; // mon encodeur envoie 2 impulsions par tick, donc je disvise par 2
        if (nouvellePosition != anciennePosition) {
          consigne = ancienneConsigne + nouvellePosition;
          anciennePosition = nouvellePosition;
          consigneChangee = true;
        }
      }
      break;
  }
  return consigneChangee;
}

// *** LE PROGRAMME ***
void setup()
{
  Serial.begin(115200);
  Serial.println(F("PRET !"));
}

void loop()
{
  if (verifConsigne()) afficheConsigne(); // si la consigne a changé on l'affiche
  // ici on peut faire autre chose de non bloquant
}

il y a une machine à état toute simple dans la fonction verifConsigne() qui gère le passage entre mode normal (rien ne se passe si on tourne l'encodeur) et le mode modification (si on tourne, la consigne change) et la consigne. cette fonction renvoie 'vrai' (true) si la consigne a été modifiée.

La loop se réduit alors à une seule ligne:   if (verifConsigne()) afficheConsigne(); // si la consigne a changé on l'affiche

en espérant que cela vous aide - ce ne serait pas difficile à modifier pour que la modification ne se fasse que si le bouton est appuyé.

EDIT: C'est encore plus simple si on modifie la valeur que si le bouton est appuyé, il n'y a même pas besoin de machine à états. voici à quoi le code ressemblerait

// *** DEFINITION DE L'ENCODEUR ROTATIF ***
#include <Encoder.h> // https://www.pjrc.com/teensy/td_libs_Encoder.html
const byte encodeurDTPin = 2; // Encodeur DT
const byte encodeurCLKPin = 3; // Encodeur CLK
Encoder encodeurRotatif(encodeurDTPin, encodeurCLKPin); // attaché sur pins 2 (Encodeur DT) et 3 (Encodeur CLK)

// *** DEFINITION DU BOUTON ***
#include <simpleBouton.h> // cf @bricoleau cf http://forum.arduino.cc/index.php?topic=375232.0
const byte encodeurBoutonPin = 4;  //Cablage : pin 4 --- Encodeur SW (câblage en PULLUP fait par l'arduino)
simpleBouton boutonEncodeur(encodeurBoutonPin);

// *** CONSIGNE ***
long consigne = 20; // exemple de valeur par défaut

void afficheConsigne()
{
  Serial.print(F("Consigne: "));
  Serial.println(consigne);
}

bool verifConsigne()  // retourne vrai si la consigne a été modifiée
{
  bool consigneChangee = false;

  boutonEncodeur.actualiser();
  if (boutonEncodeur.vientDEtreEnfonce()) encodeurRotatif.write(consigne<<1); // on met le compteur à la valeur de la consigne (nombre de ticks x 2)
  
  if (boutonEncodeur.estEnfonce()) {
    long nouvellePosition = encodeurRotatif.read() >> 1; // mon encodeur envoie 2 impulsions par tick, donc je disvise par 2
    if (nouvellePosition != consigne) {
      consigne = nouvellePosition;
      consigneChangee = true;
    }
  }
  return consigneChangee;
}

void setup() {
  Serial.begin(115200);
  afficheConsigne();
  Serial.println(F("PRET !"));
}

void loop() {
  if (verifConsigne()) afficheConsigne(); // si la consigne a changé on l'affiche
  // ici on peut faire autre chose de non bloquant
}

Bonjour,

Merci à tous pour vos réponses.

Je m'en vais essayer vos suggestions, et vous fais part des résultats.

Encore merci. :slight_smile:

Bonjour,

Il semble que cela ne fonctionne pas, car au premier passage compilation, le message d'erreur suivant apparaît, en provenance de l'include simpleBouton:

C:\Users\marcx\OneDrive\Documents\Arduino\libraries\simpleBouton\simpleBouton.cpp:15:41: warning: large integer implicitly truncated to unsigned type [-Woverflow]
const uint8_t masque_pin_simpleBouton = ~(masque_etat_simpleBouton | masque_chgt_simpleBouton);

À J-M-L
Je reviens sur ce que j'ai dit, malgré le message d'erreur au premier passage de compilation, votre première proposition avec la fonction verifConsigne(), fonctionne parfaitement dans l'esprit de ce que je veux faire.

Merci

Le message d’erreur est dans la bibliothèque c’est un warning pas grave

Pour JML,

Dans la petite routine avec fonction "verifConsigne() ", que vous m'avez gentiment transmis, n'y a-t-il pas moyen de la modifier pour qu'elle soit toujours appelée dans "loop" et activée par le changement du bouton poussoir, mais qu'une fois dans la fonction elle y reste jusqu'à ce que le bouton poussoir soit de nouveau activé. C.A.D. que ne retourne dans "loop" une fois la consigne complète.

Si vous ne voulez pas me mâcher le travail, ce que comprendrai, pourriez-vous simplement me donner une indication.

Merci d'avance.

Otermale

pour quelle version ?

pourquoi voulez vous bloquer la loop() ?

Bonjour,

Dans mon projet, il est important de bloquer le reste du programme, saisie de données, pendant l'établissement de la consigne. Quand j'essaie votre routine de consigne associée au reste du programme, l'affichage devient un peu érratique, et diverses données s'affiche en même temps;

C'est pour cela qu'il est nécessaire que après la pression du bouton qui fait entré en mode "modification", on n'en ressort que sur une deuxième pression pour passer en mode "normal".

Une fois la consigne établie, 'loop' reprend le cours normal de sa vie.

Merci.

Otermale

J'ai oublié de préciser la version :

// *** DEFINITION DE L'ENCODEUR ROTATIF ***
#include <Encoder.h> // https://www.pjrc.com/teensy/td_libs_Encoder.html
const byte encodeurDTPin = 2; // Encodeur DT
const byte encodeurCLKPin = 3; // Encodeur CLK
Encoder encodeurRotatif(encodeurDTPin, encodeurCLKPin); // attaché sur pins 2 (Encodeur DT) et 3 (Encodeur CLK)

// *** DEFINITION DU BOUTON ***
#include <simpleBouton.h> // cf @bricoleau cf http://forum.arduino.cc/index.php?topic=375232.0
const byte encodeurBoutonPin = 4;  //Cablage : pin 4 --- Encodeur SW (câblage en PULLUP fait par l'arduino)
simpleBouton boutonEncodeur(encodeurBoutonPin);

// *** CONSIGNE ***
long consigne = 0;

void afficheConsigne()
{
  Serial.print(F("Consigne: "));
  Serial.println(consigne);
}

// *** Machine à état pour la gestion d'un mode modification ***
enum : byte {MODE_NORMAL, MODE_MODIFICATION} modeActuel = MODE_NORMAL;

bool verifConsigne()  // retourne vrai si la consigne a été modifiée
{
  bool consigneChangee = false;
  static long ancienneConsigne = 0;
  static long anciennePosition = 0;

  boutonEncodeur.actualiser();
 
  switch (modeActuel) {
   
    case MODE_NORMAL: // on vérifie si le bouton a été appuyé, alors on passe en mode modification
      if (boutonEncodeur.vientDEtreEnfonce()) {
        encodeurRotatif.write(0); // on met le compteur à 0
        ancienneConsigne = consigne;
        anciennePosition = 0;
        Serial.print(F("MODE MODIFICATION, ")); afficheConsigne();
        modeActuel = MODE_MODIFICATION;
      }
      break;
     
    case MODE_MODIFICATION:
      if (boutonEncodeur.vientDEtreEnfonce()) {
        Serial.print(F("MODE NORMAL, ")); afficheConsigne();
        modeActuel = MODE_NORMAL;
      } else {
        long nouvellePosition = encodeurRotatif.read() >> 1; // mon encodeur envoie 2 impulsions par tick, donc je disvise par 2
        if (nouvellePosition != anciennePosition) {
          consigne = ancienneConsigne + nouvellePosition;
          anciennePosition = nouvellePosition;
          consigneChangee = true;
        }
      }
      break;
  }
  return consigneChangee;
}

// *** LE PROGRAMME ***
void setup()
{
  Serial.begin(115200);
  Serial.println(F("PRET !"));
}

void loop()
{
  if (verifConsigne()) afficheConsigne(); // si la consigne a changé on l'affiche
  // ici on peut faire autre chose de non bloquant
}

Ben vous changez juste la loop alors pour exécuter son code que lorsque vous n’êtes pas en mode édition

void loop()
{
  if (verifConsigne()) afficheConsigne(); // si la consigne a changé on l'affiche
  if (modeActuel == MODE_NORMAL) {
    ...
  }
}

Bonjour J-M-L

It was just that simple!

Je devrais avoir honte de n'avoir pas suffisamment chercher.

Merci et bonne journée.

Otermale

C’est en forgeant qu’on devient forgeron :slight_smile:

Amusez vous bien !