Appel aide : panneau simulation, interrupteur et encodeurs rotatifs

Bonjour tout le monde,

J'ai 16 ans, et je compte faire une planche pour flight simulator avec plusieurs interrupteurs on off relié sur un multiplexer CD74HC4067 et 3 encodeurs le tout relies à un arduino pro micro qui agira comme un clavier grace a la library keyboard, pour pouvoir utiliser sur xbox comme pc. Lorsque chaque interrupteur est changé de position il doit envoyer un caractère pour la position off et un caractère different en position off, pour tout des interrupteurs. Pour les encodeurs rotatifs, ils doivent envoyer un caractère pour chaque pas dans le sens horaire et dans le sens anti horaire.
J'ai du mal avec le code j'ai essayé le code suivant sur un arduino une pour me servir de prototype ( il envoie serial.print à la place de keyboard car la library n'est pas compatible avec les uno ) mais il comporte beaucoup problème. Je me demande si quelqu'un peut m'aider s'il vous plait :slight_smile:

#include <light_CD74HC4067.h>
 
 #define inputCLK 4
 #define inputDT 5
 #define inputCLK1 6
 #define inputDT1 7
 #define inputCLK2 2
 #define inputDT2 3


CD74HC4067 mux(A5, A4, A3, A2);

 
 int currentStateCLK;
 int previousStateCLK; 
 int currentStateCLK1;
 int previousStateCLK1; 
 int currentStateCLK2;
 int previousStateCLK2; 
 int previous[16]={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
 const int signal_pin = A1;
 int current[16]={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};

 void setup() { 
   
     
   pinMode (signal_pin,INPUT_PULLUP);
   pinMode (inputCLK,INPUT);
   pinMode (inputDT,INPUT);
   pinMode (inputCLK1,INPUT);
   pinMode (inputDT1,INPUT);
   pinMode (inputCLK2,INPUT);
   pinMode (inputDT2,INPUT);
   
   
   
   // Setup Serial Monitor
   Serial.begin (9600);
   
   
   // Assign to previousStateCLK variable
   previousStateCLK = digitalRead(inputCLK);
   previousStateCLK1 = digitalRead(inputCLK1);
   previousStateCLK2 = digitalRead(inputCLK2);

 } 

 void loop() { 
  
  // Read the current state of inputCLK
   currentStateCLK = digitalRead(inputCLK);
    
   // If the previous and the current state of the inputCLK are different then a pulse has occured
   if (currentStateCLK != previousStateCLK){ 
       
     // If the inputDT state is different than the inputCLK state then 
     // the encoder is rotating counterclockwise
     if (digitalRead(inputDT) != currentStateCLK) { 
       Serial.println("up");
       
     } else {
       // Encoder is rotating clockwise
       Serial.println("down");
       
       
     }
     
   } 
   // Update previousStateCLK with the current state
   previousStateCLK = currentStateCLK;


   currentStateCLK1 = digitalRead(inputCLK1);
    
   // If the previous and the current state of the inputCLK1 are different then a pulse has occured
   if (currentStateCLK1 != previousStateCLK1){ 
       
     // If the inputDT1 state is different than the inputCLK1 state then 
     // the encoder is rotating counterclockwise
     if (digitalRead(inputDT1) != currentStateCLK1) { 
       Serial.println("up");
       
     } else {
       // Encoder is rotating clockwise
       Serial.println("down");
       
       
     }
     
   } 
   // Update previousStateCLK1 with the current state
   previousStateCLK1 = currentStateCLK1;


   currentStateCLK2 = digitalRead(inputCLK2);
    
   // If the previous and the current state of the inputCLK2 are different then a pulse has occured
   if (currentStateCLK2 != previousStateCLK2){ 
       
     // If the inputDT2 state is different than the inputCLK state then 
     // the encoder is rotating counterclockwise
     if (digitalRead(inputDT2) != currentStateCLK2) { 
       Serial.println("up");
       
     } else {
       // Encoder is rotating clockwise
       Serial.println("down");
       
       
     }
     
   } 
   // Update previousStateCLK2 with the current state
   previousStateCLK2 = currentStateCLK2;
 
    for (byte i = 0; i < 16; i++) {
	          mux.channel(i);
	          current[i]= digitalRead(signal_pin);                       // Read analog value
	          if(current[i]!= previous[i]){
              if(current[i]== 0){
                Serial.print(i);
                Serial.println(". on");
                
              } else {
                Serial.print(i);
                Serial.println(". off");
              }
              }
  previous[i]=current[i];
  delay(50);
  }

}

C'est-à-dire?

Déjà, remplacer ceci

par cela

   // Setup Serial Monitor
   Serial.begin (115200);

9600 bauds ce n'est pas très rapide, 115200 bauds fluidifiera un peu la transmission et risquera moins de ralentir le code.

Merci pour le conseil, quand je change de position un interrupteur des fois ça me renvoie la bonne information, c'est à dire soit le numéro de l'interrupteur suivi de "off" soit le numéro de l'interrupteur suivi de "on", Mais dans la plupart des cas il me renvoie comme si plein d'interrupteur changent de position alors que pourtant non, et pour les encodeurs rotatifs, aucun ne marche. C'est peut être lié au fait que je fais tourner le code sur le simulateur WOKWI ? Peut être faudrait il abandonner l'idée du multiplexer ? Je suis un grand débutant dans le domaine votre expérience m'aiderait beaucoup.

Voici quelque image du schéma si cela aide


Faudrait soigner l'indentation. Faire ctrl+T dans l'IDE.

Cela veut dire que current[i] != previous[i], il faudrait monitorer les valeurs que tu manipule pour voir d'où cela peut venir.

Est tu sûre que la selection du chanel et la lecture, ne te donne pas le même résultat pour tout les chanels?

voici un petit exemple qui utilise les bibliothèques et sans CD74HC4067

les détails
#include <Encoder.h>                        // https://www.pjrc.com/teensy/td_libs_Encoder.html
#include <Toggle.h>                         // https://github.com/Dlloydev/Toggle

class Codeur {
    Encoder encodeur;
    char plus, moins;
    long valeurPrecedente = 0;

  public:
    Codeur(const byte dtPin, const byte clkPin, const char p, const char m):
      encodeur(dtPin, clkPin), plus(p), moins(m) {}

    void begin() {
      encodeur.write(0);
    }

    void check() {
      long v = encodeur.read() >> 2; // on divise par 4 car l'encdeur envoie 4 ticks par clicks
      if (v != valeurPrecedente) {
        // la valeur a changé
        if (v > valeurPrecedente) {
          for (long i = 0; i < v - valeurPrecedente; i++) Serial.print(plus);
        } else {
          for (long i = 0; i < valeurPrecedente - v; i++) Serial.print(moins);
        }
        valeurPrecedente = v;
      }
    }
};

class Bouton {
  public:
    Toggle bouton;
    const byte pin;
    char down, up;

  public:
    Bouton(const byte p, const char d, const char u)  : bouton(p), pin(p), down(d), up(u) {};

    void begin() {
      bouton.begin(pin);
    }

    void check() {
      bouton.poll();
      if (bouton.onPress())   Serial.print(down);
      if (bouton.onRelease()) Serial.print(up);
    }
};

Codeur encodeurs[] = {{3, 2, 'a', 'z'}, {6, 5, 'e', 'r'}, {9, 8, 't', 'y'}};
Bouton boutons[] = {{4, 'q', 's'}, {7, 'd', 'f'}, {10, 'g', 'h'}, {11, 'j', 'k'}, {12, 'l', 'm'}, {13, 'w', 'x'}};

void setup() {
  for (Codeur& c : encodeurs) c.begin();
  for (Bouton& b : boutons) b.begin();
  Serial.begin(115200);
  Serial.println(F("PRET!"));
}

void loop() {
  for (Codeur& c : encodeurs) c.check();
  for (Bouton& b : boutons) b.check();
}

cet exemple montre comment encapsuler dans une classe dédiée vos éléments d'interface pour simplifier le code.

La loop est vraiment simple, on demande aux boutons et aux encodeurs de vérifier si quelque chose de notable s'est passé depuis la dernière demande.

void loop() {
  for (Codeur& c : encodeurs) c.check();
  for (Bouton& b : boutons) b.check();
}

On pourrait rajouter 6 boutons en plus sur les pins analogiques - donc avoir en tout 12 boutons (en comptant ceux des encodeurs rotatifs) et 3 encodeurs.

la classe Bouton pourrait être modifiée pour fonctionner avec le CD74HC4067 et ne pas utiliser Toggle.

Normalement chaque chanel me renvoie une info différentes j'ai essayer avec ce code


#include <light_CD74HC4067.h>

#define inputCLK 4
#define inputDT 5
#define inputCLK1 6
#define inputDT1 7
#define inputCLK2 2
#define inputDT2 3


CD74HC4067 mux(A5, A4, A3, A2);


int currentStateCLK;
int previousStateCLK;
int currentStateCLK1;
int previousStateCLK1;
int currentStateCLK2;
int previousStateCLK2;
int previous[16] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
const int signal_pin = A1;
int current[16] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };

void setup() {


  pinMode(signal_pin, INPUT_PULLUP);
  pinMode(inputCLK, INPUT_PULLUP);
  pinMode(inputDT, INPUT_PULLUP);
  pinMode(inputCLK1, INPUT_PULLUP);
  pinMode(inputDT1, INPUT_PULLUP);
  pinMode(inputCLK2, INPUT_PULLUP);
  pinMode(inputDT2, INPUT_PULLUP);



  // Setup Serial Monitor
  Serial.begin(115200);


  // Assign to previousStateCLK variable
  previousStateCLK = digitalRead(inputCLK);
  previousStateCLK1 = digitalRead(inputCLK1);
  previousStateCLK2 = digitalRead(inputCLK2);
}

void loop() {

  // Read the current state of inputCLK
  currentStateCLK = digitalRead(inputCLK);

  // If the previous and the current state of the inputCLK are different then a pulse has occured
  if (currentStateCLK != previousStateCLK) {

    // If the inputDT state is different than the inputCLK state then
    // the encoder is rotating counterclockwise
    if (digitalRead(inputDT) != currentStateCLK) {
      Serial.println("up");

    } else {
      // Encoder is rotating clockwise
      Serial.println("down");
    }
  }
  // Update previousStateCLK with the current state
  previousStateCLK = currentStateCLK;


  currentStateCLK1 = digitalRead(inputCLK1);

  // If the previous and the current state of the inputCLK1 are different then a pulse has occured
  if (currentStateCLK1 != previousStateCLK1) {

    // If the inputDT1 state is different than the inputCLK1 state then
    // the encoder is rotating counterclockwise
    if (digitalRead(inputDT1) != currentStateCLK1) {
      Serial.println("up");

    } else {
      // Encoder is rotating clockwise
      Serial.println("down");
    }
  }
  // Update previousStateCLK1 with the current state
  previousStateCLK1 = currentStateCLK1;


  currentStateCLK2 = digitalRead(inputCLK2);

  // If the previous and the current state of the inputCLK2 are different then a pulse has occured
  if (currentStateCLK2 != previousStateCLK2) {

    // If the inputDT2 state is different than the inputCLK state then
    // the encoder is rotating counterclockwise
    if (digitalRead(inputDT2) != currentStateCLK2) {
      Serial.println("up");

    } else {
      // Encoder is rotating clockwise
      Serial.println("down");
    }
  }
  // Update previousStateCLK2 with the current state
  previousStateCLK2 = currentStateCLK2;

  for (byte i = 0; i < 16; i++) {
    mux.channel(i);
    current[i] = digitalRead(signal_pin);  
    Serial.print(i);
    Serial.print(". ");
    Serial.println(current[i]);
  delay(500);
  }
}

Ok, mais dans ton programme qui ne marche pas correctement tu ne fais pas de delay(500)
Tu es sûre que sans cela le comportement est le même?

Dans la lecture des boutons, il faudrait sortir le delay() de la boucle for, 50ms * 16 cela fait 800ms est ça doit rendre le système peut réactif.
Si tu veux utiliser un delay(), il vaut mieux qu'il soit global.

Il faut mettre l'enable (E) à LOW pour lire le multiplexeur. Sinon sa sortie est en l'air.

merci pour le code je vais bien regarder

Que voulez vous dire par "enable (E) à LOW"

Le code a l'aire de marcher avec un delay(200) par contre le système n'est pas du tout réactif et les encodeurs rotatifs sont inutilisable

Il y a une broche enable sur le CD74HC4067 voir la datasheet du composant

On dirait qu'elle est repérée EN sur le module dans ton post #3.
Ce signal doit être à l'état bas pour pouvoir activer le 4067.
Soit tu le connectes à un I/O de ton Arduino (qu'il faudra mettre en sortie et à l'etat LOW), soit tu le raccordes à 0V

Dans la datasheet du composant utilisé dans ton module, tu as une table de vérité dépendant de la broche Ē, qui doit être je suppose raccordé à la broche dont parle @fdufnews

Je n'ai pas lu la datasheet que j'ai mis en lien, mais le temps de changement de la broche sélectionné doit y être mentionné?

200 est perceptible, mais pas élevé, mais comme tu le multiplie par 16, forcément cela doit impacté la réactivité de ton programme.

Mais as tu identifié que sans ce delay, ton composant ne te renvois pas le bon chanel ?

Le 4067 à un temps de propagation <15ns lorsque le circuit est alimenté en 5V donc c'est pratiquement invisible.
Mais là où il est placé de toute les façons il n'a aucun impact sur le canal sélectionné, le delay() étant placé après la lecture de l'IO et avant le changement du canal. Éventuellement cela fait un antirebond. Mais dans ce cas là, un delay() global, donc hors de la boucle ferait le même effet sans nuire à la réactivité.

Je l'ai fais mais aucun changement

Si je ne mets pas de délai dans la boucle for il me renvoie à l'infini la position on puis off de chaque interrupteur à l'infini

ça m'a l'air prometteur mais vu mon niveau en codage je vais avoir du mal à adapter ça au CD74HC4067

Je viens d'aller regardé les exemples de ta librairie, effectivement ils utilisent un delay de 500 ms
placé comme tu l'a fait.
Ce qui voudrais dire que l'on ne pourrait pas changer de chanel avec x centaines de millisecondes

C'est très surprenant, il faudrait regarder ce que fais cette librairie.
Dans le ReadMe ils parlent d'une autre librairie CD74HC4067, qui prendrait plus de mémoire, l'as tu testé?

Si tu met un delay(1), ca ne marche pas non plus du coup ?

Mais si, mais si, la librairie ne fait que positionner les 4 sorties pour sélectionner le canal actif.
Le delay() ne sert que pour ralentir l'affichage.
Le temps de commutation Sn --> Out est < 60ns.

Éventuellement, par sécurité tu pourrais mettre un delay() entre la sélection et la lecture.

    mux.channel(i);
    delay(1); // ou delay(2) si ,ca te chante
    current[i] = digitalRead(signal_pin);