Démultiplexage d'entrées

Bonjour,

je souhaiterai activer une led en fonction des entrées (3 entrées) qui passent à 1.
soit les possibilités suivantes

E1E2E3-->SORTIE
000 --> RIEN
001-->S1
010-->S2
011-->S3
100-->S4
101-->S5
110-->S6
111-->S7

a partir de la premiere entrée détectée, le programme dispose de deux secondes pour lire la suivante. soit 4 seconde pour les deux.
si après 4 secondes les entrées ne sont pas détectées alors le scan repart à 0

preneur de vos experiences et compétences .

je pense à la machine à état de @J-M-L

bonne soirée :slight_smile:

merci

Ce serait une bonne idée :wink:
Vous faites le graphe des états ?

bonjour

je pense à deux façons de faire :

la première :
enum {0001, 0010, 0011,0100...} portB;
lister en binaire ou en hexa toutes les valeurs dans les parenthèses

puis :

switch (etatCourant) {
case 0001:
// faire quelque chose

la deuxième :

lire les entrées qui passe à 1 pendant 4 secondes
si E1 passe à 1 alors sortie 1 passe à un
si E2 passe à 1 alors sortie 2 passe à un
si E3 passe à 1 alors sortie 3 passe à un
si E4 passe à 1 alors sortie 4 passe à un

lire l'état du port de sortie et en fonction de la valeur exécuter une tache

merci pour vos avis

je suis preneur de toutes critiques

la machine doit représenter cela

(sinon on ne met pas des valeurs dans un enum mais des mots clés)

(cf mon tuto éventuellement)

bonjour

un début de travail sur deux entrées

// La librairie de gestion des boutons
#include <OneButton.h>
const byte buttonPin = 2; // notre bouton est sur la pin 4
const byte buttonPin2 = 3;
OneButton button(buttonPin, true); // true pour le mettre en INPUT_PULLUP
OneButton button2(buttonPin2, true); // true pour le mettre en INPUT_PULLUP

// les pins utilisées pour les LEDs
const byte pinLedRouge = 8;
const byte pinLedOrange = 9;
const byte pinLedJaune = 10;
const byte pinLedVerte = 11;

// On introduit le temps comme évènement supplémentaire
unsigned long chrono; // attention, type unsigned long comme millis()
const unsigned long TimeOut = -5000ul; // 5 secondes (le ul à la fin pour unsigned long)

// la liste des états possible de notre système
// ainsi qu'une variable etatCourant prenant une de ces valeurs
enum {REPOS, ETAT_V, ETAT_VJ, ETAT_VJO, ETAT_VJOR} etatCourant;
enum {REPOS2, ETAT_V2, ETAT_VJ2, ETAT_VJO2, ETAT_VJOR2} etatCourant2;


// ------------------------------------------------------
// Cette fonction installe l'état initial
// ------------------------------------------------------
void mettreAuRepos()
{
  digitalWrite(pinLedVerte,  LOW);
  digitalWrite(pinLedJaune,  LOW);
  digitalWrite(pinLedOrange, LOW);
  digitalWrite(pinLedRouge,  LOW);
  etatCourant = REPOS;
}

// ------------------------------------------------------
// La fonction de call back, appellée automatiquement quand on clique
// ------------------------------------------------------
void simpleclick()
{
  switch (etatCourant) {
    case REPOS: // on était au repos et on a un appui, on allume la verte
      digitalWrite(pinLedRouge, HIGH); // LED verte alimentée
      etatCourant = ETAT_V; // on note le nouvel état de notre système
      break;


  }
 

switch (etatCourant2) {
    case REPOS2: // on était au repos et on a un appui, on allume la verte
      digitalWrite(pinLedOrange, HIGH); // LED verte alimentée
      etatCourant2 = ETAT_V2; // on note le nouvel état de notre système
      break;

}



 chrono = millis(); // on vient d'avoir une action donc on ré-arme notre chronomètre





}



void timeOut()
{
  /* // version longue si on veut le switch case
    switch (etatCourant) {
    case ETAT_V:    // pour tous les états
    case ETAT_VO:   // sauf celui au repos
    case ETAT_VOJ:  // on doit tout éteindre
    case ETAT_VOJR: // et revenir à l'état initial
      mettreAuRepos(); // ce que fait cette fonction
      break;
    }
  */
  // version courte, si on n'est pas au repos, alors passer au repos
  if (etatCourant != REPOS) mettreAuRepos();

  // à noter que le timeOut continuera de se déclencher toutes les 15 secondes
  // mais ne fera rien puisqu'on sera au repos
  // ça peut être utile pour continuer à faire autre chose
  // sinon il faut tester avant de l’appeler qu’on n’est pas au repos
}

// ------------------------------------------------------
// On initialise notre système dans le setup
// ------------------------------------------------------
void setup() {
  pinMode (pinLedRouge,  OUTPUT);
  pinMode (pinLedOrange, OUTPUT);
  pinMode (pinLedJaune,  OUTPUT);
  pinMode (pinLedVerte,  OUTPUT);

  //conditions Initiales
  mettreAuRepos();

  // On attache la fonction simpleClick() comme callBack en cas de simple click
  button.attachClick(simpleclick);
  button2.attachClick(simpleclick);


}

void loop() {
  // On vérifie l'état des boutons, ce qui déclenche l'appel d'une des fonctions callBack si nécessaire
  button.tick();
  button2.tick();

  // On vérifie le timer et on déclenche l'évènement si nécéssaire
  // rajouter dans la condition “&& (etatCourant != REPOS)” si vous ne souhaitez pas
  // appeler la fonction au repos
  if (millis() - chrono >= TimeOut) {
    timeOut();
    chrono = millis(); // on ré-arme notre chronomètre
  }

  // ici on peut faire autre chose du moment que ça ne prend pas trop longtemps

}

je ne comprends pas pour quand j appuie sur l'entrée 1 les led1 & 2 s'allument ?
l'appuie sur le bouton 2 ne déclenche rien et la tempo ne fonctionne plus .

helppp

Vous avez dessiné la machine à états?

Bonjour,

ci-dessous :

merci

Que tu appuies sur un bouton ou sur l'autre tu fais appel à la même fonction qui traite indifféremment les 2 machines à état.

Le diagramme de ta machine à états est incomplet il n'indique pas ce qui conditionne la transition d'un état au suivant.

En fait, tu implémentes 2 machines identiques?

oui - il manque aussi les actions à effectuer lors de la transition

bonjour

ce que j essayer de faire c'est de "scanner "les entrées et en fonction du résultat , jouer un scénario , il y a 16 possibilités , je sais pas comment m y prendre

merci

il vous faut déjà une machine à états qui envoie un évènement correspondant à l'état de vos 3 entrées suivant votre règle :

(il faudrait clarifier si les entrées restent à HIGH ou si c'est un front et ce qu'il se passe si dans les 2s la même entrée est à nouveau activée, est-ce que c'est une annulation, est-ce qu'on prolonge de 2s quand même etc)

c'est un truc du genre:

se sont des fronts et toujours dans l'ordre E1 E2 E3 E4

vous avez 4 entrées ou 3 ?

pardon j'en ai 4

En suivant le diagramme ci dessus (mais avec 4 au lieu de 3), la machine à état qui envoie l'action avec une variable qui représente le code reconnu est assez simple à implémenter

voici à quoi ça pourrait ressembler dans le simulateur

on simule les fronts par un appui sur le bouton
l'ordre d'appui n'est pas pris en compte, la fonction action() reçoit un octet dont les bits correspondants aux boutons sont à 1 si le bouton a été appuyé.

le code
/* ============================================
  code is placed under the MIT license
  Copyright (c) 2024 J-M-L
  For the Arduino Forum : https://forum.arduino.cc/u/j-m-l

  Permission is hereby granted, free of charge, to any person obtaining a copy
  of this software and associated documentation files (the "Software"), to deal
  in the Software without restriction, including without limitation the rights
  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  copies of the Software, and to permit persons to whom the Software is
  furnished to do so, subject to the following conditions:

  The above copyright notice and this permission notice shall be included in
  all copies or substantial portions of the Software.

  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  THE SOFTWARE.
  ===============================================
*/

#include <Toggle.h>

const byte brochesBoutons[] = {2, 3, 4, 5};
const byte nbBoutons = sizeof brochesBoutons / sizeof * brochesBoutons;
Toggle boutons[nbBoutons];

enum {REPOS, ACTIVATION} etatEntrees = REPOS;

void action(byte configuration) {
  Serial.print("ACTION\t");
  for (int i = nbBoutons - 1; i >= 0; --i) Serial.print(bitRead(configuration, i));
  Serial.println();
}

void gesionEntrees() {
  static unsigned long t0;
  static byte memoireEntrees = 0;

  switch (etatEntrees) {
    case REPOS:
      for (byte i = 0; i < nbBoutons; i++) {
        boutons[i].poll();
        if (boutons[i].onPress()) {
          Serial.print("Appui bouton "); Serial.println(i);
          t0 = millis();
          memoireEntrees = (1 << i);
          etatEntrees = ACTIVATION;
          break;
        }
      }
      break;

    case ACTIVATION:
      if (millis() - t0 >= 2000) {
        action(memoireEntrees);
        memoireEntrees = 0;
        etatEntrees = REPOS;
      } else {
        for (byte i = 0; i < nbBoutons; i++) {
          if (bitRead(memoireEntrees, i)) continue; // on ne teste pas deux fois
          boutons[i].poll();
          if (boutons[i].onPress()) {
            Serial.print("Appui bouton "); Serial.println(i);
            t0 = millis();
            memoireEntrees |= (1 << i);
            if (memoireEntrees == ((1 << nbBoutons) - 1)) { // si tous les boutons sont choisis
              action(memoireEntrees);
              memoireEntrees = 0;
              etatEntrees = REPOS;
            }
            break;
          }
        }
      }
      break;
  }
}

void setup() {
  for (byte i = 0; i < nbBoutons; i++) boutons[i].begin(brochesBoutons[i]);
  Serial.begin(115200);
}

void loop() {
  gesionEntrees();
}

merci je vais lire et décrypter tout ca

pouvez vous m'éclairer sur la partie suivante ?

void action(byte configuration) {
  Serial.print("ACTION\t");
  for (int i = nbBoutons - 1; i >= 0; --i) Serial.print(bitRead(configuration, i));
  Serial.println();
}

si j'observe betement, la résultat est : (bitRead(configuration, i)) ?

Je ne suis pas sûre d'avoir bien compris ta question.

la fonction affiche sur le moniteur série, la valeur binaire de du byte donné en paramètre(memoireEntrees)
@J-M-L utilisant cette variable pour stocker les appuis sur chaque bouton, le bouton 1(ou 0 en valeur numérique) étant stocké dans le premier bit de cette entier.
Donc si tu appuis sur le bouton 1, tu aura 0001, puis le bouton 2 => 0011

Mode provoque On, c'est une méthode moche, pour éviter de gaspiller bêtement de la mémoire en allouant 8bits par bouton :rofl:

donc le résultat affiché corresponds à la variable memoireEntrees

comment exécuter une action en fonction du résultat ?

if (memoireEntrees = 0001){
do 1
}

Ca dépend des combinaison que tu veux tester.
mais par exemple plusieurs if de la forme (configuration & 0b0001) ou (configuration & 1) ou (configuration & 0b010) ou (configuration & 2)
donc si on reprend ton exemple:

if (memoireEntrees & 0b0001 ){
    //do 1
}

tu ne peux pas tester directement l'égalité.
Si par exemple deux boutons sont appuyer, memoireEntrees sera différent de 1.