Combinaison de boutons poussoir

Bonjour,
Vous vous en doutez, vous lisez un message de détresse, comme c’est de coutume sur ce forum.
J’ai suivi un petit “cours” en ligne pour faire un coffre à ouverture par combinaison de boutons poussoirs.

Vous pouvez le consulter ici : http://www.wikidebrouillard.org/index.php?title=Coffre_à_code_avec_Arduino&oldid=23463

Etant donné qu’il ne correspond pas exactement à ce que je souhaite faire, j’ai essayé de le modifier, de m’en servir de base pour mon cablage et pour mon programme.

Voilà donc ce que j’ai fait niveau cablage : (je voulais insérer mon image ici mais je n’ai pas réussi, du coup je l’ai attachée en pièce jointe)

Et voilà mon programme :

void remiseZeroCode(void);
void ouvrirPorte(int value);
void afficherCodeActuel(void);

int switchPin1 = 2;    // input switch 1 - interrupteur sur la patte 2 de l'arduino ( entrée numérique )
int switchPin2 = 3;    // input switch 2 - interrupteur sur la patte 3 de l'arduino ( entrée numérique )
int switchPin3 = 4;    // input switch 3 - interrupteur sur la patte 4 de l'arduino ( entrée numérique )
int switchPin4 = 5;    // input switch 4 - interrupteur sur la patte 5 de l'arduino ( entrée numérique )
int switchPin5 = 6;    // input switch 5 - interrupteur sur la patte 6 de l'arduino ( entrée numérique )

//============

int ledPin1 = 13;      // select the pin for the LED1 - La led 1 doit être placée sur l'entrée/sortie numérique 13 de l'arduino
int ledPin5 = 9;      // select the pin for the LED5 - La led 5 ( blanche qui signale l'ouverture du coffre) doit être placée sur l'entrée/sortie numérique 9 de l'arduino

//============

const int sizeCode=5;

int code[sizeCode]={2,3,5,1,4};    
int codeActuel[sizeCode]={0}; 

int emplacementActuelTableau=1;   //indexeur sur le tableau codeActuel
int porteOuverte=0;     //Indique quand la porte est ouverte (1) ou fermée (0)
int ouverturePorte=1;   //Indique quand il faut ouvrir la porte(1), ou la fermer (0);
int antirebond=0;       //permet d'éviter qu'à la suite d'un appui sur plusieurs boutons simultanément ou un appui long, le code tapé soit mal interpreté.
                        //permet également d'éviter qu'un appui court sur un bouton soit compté plusieurs fois dans le programme
int alarme=0;


int sensorSwitch1 = 0;   //recupère la valeur du bouton poussoir1
int sensorSwitch2 = 0;   //recupère la valeur du bouton poussoir2
int sensorSwitch3 = 0;   //recupère la valeur du bouton poussoir3
int sensorSwitch4 = 0;   //recupère la valeur du bouton poussoir4
int sensorSwitch5 = 0;   //recupère la valeur du bouton poussoir5

void setup() 
{

  pinMode(ledPin1, OUTPUT);    
  pinMode(ledPin5, OUTPUT); 
  Serial.begin(9600);
  
  pinMode(switchPin1, INPUT);  
  pinMode(switchPin2, INPUT); 
  pinMode(switchPin3, INPUT); 
  pinMode(switchPin4, INPUT); 
  pinMode(switchPin5, INPUT); 
}
//============

void ouvrirPorte(int value)

{  if (value==1) 
  {
     digitalWrite(ledPin5, HIGH);  //Allumage de la led verte signalant l'ouverture de la porte
     digitalWrite(ledPin1, LOW);  //Extinction de la led rouge
     porteOuverte=1;               //On met cette variable à 1 pour dire que la porte est ouverte !
  }
  if (value==0)
  {
    digitalWrite(ledPin5, LOW);    //Extinction de la led verte
    digitalWrite(ledPin1, HIGH);    //Allumage de la led rouge
    porteOuverte=0;            //la porte est refermée, cette variable est donc mise à zero
  }
}

//============

void afficherCodeActuel(void)
{
     Serial.println("--------Affichage du code actuel-------");
     Serial.print(codeActuel[1]);
     Serial.print(codeActuel[2]);
     Serial.print(codeActuel[3]);
     Serial.print(codeActuel[4]);
     Serial.println(codeActuel[5]);
}

//============

void loop() {
  // Ici, on charge dans les différentes variables les valeurs recuillies par les capteurs
{ sensorSwitch1 = digitalRead(switchPin1);            //valeur Switch 1
  sensorSwitch2 = digitalRead(switchPin2);            //valeur Switch 2
  sensorSwitch3 = digitalRead(switchPin3);            //valeur Switch 3
  sensorSwitch4 = digitalRead(switchPin4);            //valeur Switch 4
  sensorSwitch5 = digitalRead(switchPin5);            //valeur Switch 5
}


  if((sensorSwitch1==LOW) && (sensorSwitch2==LOW) && (sensorSwitch3==LOW) && (sensorSwitch4==LOW) && (sensorSwitch5==LOW))
  {
      antirebond=0;
  }
  
  //============================================
  
  if (antirebond==0)
  {
    if((sensorSwitch1==HIGH) && (sensorSwitch2==LOW) && (sensorSwitch3==LOW) && (sensorSwitch4==LOW) && (sensorSwitch5==LOW))
    {
        Serial.println("Passage switch 1");
       codeActuel[emplacementActuelTableau]=1;
       emplacementActuelTableau+=1;
        afficherCodeActuel();
        antirebond=1; 
    }
    else if((sensorSwitch2==HIGH) && (sensorSwitch1==LOW) && (sensorSwitch3==LOW) && (sensorSwitch4==LOW) && (sensorSwitch5==LOW))
    {
       Serial.println("Passage switch 2");
       codeActuel[emplacementActuelTableau]=2;
       emplacementActuelTableau+=1;
       afficherCodeActuel();
         antirebond=1;
    }
    else if((sensorSwitch1==LOW) && (sensorSwitch2==LOW) && (sensorSwitch3==HIGH) && (sensorSwitch4==LOW) && (sensorSwitch5==LOW))
    {
       Serial.println("Passage switch 3");
       codeActuel[emplacementActuelTableau]=3;
       emplacementActuelTableau+=1;
       afficherCodeActuel();
       antirebond=1;
    }
    else if((sensorSwitch1==LOW) && (sensorSwitch2==LOW) && (sensorSwitch3==LOW) && (sensorSwitch4==HIGH) && (sensorSwitch5==LOW))
    {
       Serial.println("Passage switch 4");
       codeActuel[emplacementActuelTableau]=4;
       emplacementActuelTableau+=1;
       afficherCodeActuel();
         antirebond=1;
    } 
    else if((sensorSwitch1==LOW) && (sensorSwitch2==LOW) && (sensorSwitch3==LOW) && (sensorSwitch4==LOW) && (sensorSwitch5==HIGH))
    {
       Serial.println("Passage switch 5");
       codeActuel[emplacementActuelTableau]=5;
       emplacementActuelTableau+=1;
       afficherCodeActuel();
         antirebond=1;
    }
  }
  
  ouverturePorte=1; //Variable mise à 1 par defaut
  
  //===============================================================
  
  for ( int i=0; i< sizeCode;i++)
  {
     if (code[i]!=codeActuel[i])
     {
       ouverturePorte=0; // si une anomalie dans le code est detectée, mise à zero de la variable, la porte restera donc fermée pour ce passage dans la fonction loop
     }
  }
  
  if (ouverturePorte==1) /*  && (alarme==0))  */
  {
     //COMMANDE OUVERTURE PORTE!
     ouvrirPorte(1);  
  }      
}

J’ai laissé certains bouts de code qui ne servent à rien pour le moment mais qui n’entravent pas le bon fonctionnement du programme (enfin… je crois).

Vous l’aurez compris, je souhaite programmer une combinaison (exemple 2, 3, 5, 1, 4) qui, si elle est entrée dans le bon ordre, allume ma led verte (en vrai, c’est un prétexte. Elle peut mettre un moteur en marche, activer un électro-aimant, etc.)
Et vous l’aurez tout aussi bien compris, ce que j’ai fait ne fonctionne pas.
J’arrive à afficher dans le moniteur série de l’IDE la combinaison en cours mais, quand j’active avec succés le dernier bouton poussoir, rien ne se passe.
Où sont mes erreurs ?
(je précise que je suis un parfait débutant en la matière)

je ne sais pas où vous avez trouvé votre code de départ mais il n’est vraiment pas top… la gestion de l’anti-rebond par exemple n’est pas fonctionnelle…

sinon un de vos soucis c’est qu’un tableau commence à l’indice 0 et que vous avez emplacementActuelTableau qui commence à 1 donc quand vous faites la boucle de comparaison des codes

for ( int i=0; i< sizeCode;i++)  {
     if (code[i]!=codeActuel[i])  {
       ouverturePorte=0; // si une anomalie dans le code est detectée, mise à zero de la variable, la porte restera donc fermée pour ce passage dans la fonction loop
     }
  }

vous comparez bien l’entrée 0 avec le code mémorisé en 0 mais vous n’avez jamais mis le premier code bouton là…

ça combiné au mauvais anti-rebond, combiné au fait que vous ne testiez jamais si emplacementActuelTableau déborde du tableau fait que vous avez potentiellement aussi un joli dépassement mémoire

Oui, je suis en train de repartir du début et je vois que certaines choses ne sont pas jolies jolies...

Je vais recoder tout ça, en prenant en compte vos remarques et je reposte mon code à jour si il ne fonctionne toujours pas.

Merci. :)

bravo - faut pas s'acharner sur un modèle de code pas propre. :)

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

Pour l'anti rebond un simple condensateur de 100 nF en parallèle sur les contacts fera le travail sans avoir besoin d'une seule ligne de code. Par programmation ou par matériel c'est ton choix.

ou un simple delay(15) quand un appui est détecté... c'est le condensateur virtuel du pauvre :) et dans ce genre de programme cette attente n'est pas dramatique

Alors, d’abord merci à tous pour vos aides. :grinning:
J’essaye d’en tenir compte pour corriger mon code mais, avec mon niveau, c’est vraiment compliqué de tout comprendre…
Du coup, pour être sûr de bien aller dans la bonne direction, je vais vous détailler les modifs que je compte faire. Vous pourrez me dire si j’ai bon comme ça.

JML : pour l’antirebond, je ne sais pas le faire, j’ai simplement copié le code original. Le truc du pauvre avec la fonction delay me plaît bien ! C’est bon si je fais comme ça ?

if((sensorSwitch1==HIGH) && (sensorSwitch2==LOW) && (sensorSwitch3==LOW) && (sensorSwitch4==LOW) && (sensorSwitch5==LOW))
    {
        Serial.println("Passage switch 1");
       codeActuel[emplacementActuelTableau]=1;
       emplacementActuelTableau+=1;
        afficherCodeActuel();
        delay(15); 
    }

Pour l’histoire du tableau qui commence à 0, vous parlez bien de ça : for ( int i=0; i< sizeCode;i++) qui veut dire que la variable commence à 0 alors que je la fais commencer à 1 ici : int emplacementActuelTableau=1;, c’est ça ? Si je mets le “int i=1” ça marche ?
Quant au fait de tester si emplacementActuelTableau dépasse, je ne sais pas comment on fait ça…

Je suis toujours bloqué sur ce satané code...

J'ai beaucoup réfléchi et je me suis rendu compte que ce programme ne correspond pas exactement à ce que je m'imaginais.

En fait, je pense que ce qu'il me faut est plus simple : -Chaque BP est associé à une valeur (1, 2, 3, etc.) -Un code est défini en amont (par exemple : 12345) -On crée un tableau de 5 valeurs qui ne mémorise que les 5 derniers BP actionnés (c'est là que j'ai un doute sur la faisabilité). Par exemple, si j'appuie sur les BP 5, 2, 1, 2, 3, 4, 5 (dans cet ordre-là), le tableau affichera : 12345 (les 5 derniers détectés) -Et on compare à tout moment le code cible avec le tableau. Si les 2 correspondent alors on déclenche une action (allumage de ma led verte).

Vous avez pu voir que mon niveau en langage Arduino est limité. Mais je pense tout de même avoir bien ciblé les actions à programmer. Pensez-vous qu'un tel programme serait à ma portée ? Quelques pistes ? Conseils ?

D'avance, merci.

oui ça me semble être une très bonne approche.
n’ait aucun doutes sur la faisabilité, ça me semble assez simple : avant d’écrire dans le tableau, tu commence par décaler toutes valeurs d’une case vers la première puis tu écris dans la dernière. Ou dans l’ordre inverse et tu écris dans la première, peu importe.

Ensuite tu compares case par case avec un autre tableau contenant le bon code.

Tu peux faire cette comparaison dans une fonctions séparée, qui va par exemple retourner true ou false selon le résultat. De la sorte tu peux faire très simplement dans ta loop un truc du genre

if( compare() ) 
{ 
   actions; 
   à; 
   faire;
}

hello
voici un code d’approche
moniteur en 115200

#include <LiquidCrystal.h> 
#define BP1 15 //A1
#define BP2 16 //A2
#define BP3 17 //A3
#define BP4 18 //A4
#define BP5 19 //A5
#define LedRouge 12 //ferme
#define LedVerte 11 //ouvert

byte code []       = {0, 15, 16, 17, 18, 19, 0}; //code: chiffres obligatoirement entre 15 et 19
byte indice_saisie = 0;
byte saisie []     = {0,  0,  0,  0,  0,  0, 0};
byte concordance   = 0;

LiquidCrystal lcd(8, 9, 4, 5, 6, 7);

void setup()
{
  Serial.begin(115200);
  lcd.begin(16, 2);
  pinMode(LedRouge, OUTPUT); digitalWrite(LedRouge, LOW);
  pinMode(LedVerte, OUTPUT); digitalWrite(LedVerte, LOW);
  for (int f = 14; f <= 19; f++)
  {
    pinMode(f, INPUT_PULLUP);
  }
  for (int d = 0; d <= 6; d++)
  {
    Serial.print(saisie[d]); Serial.print("  ");
    Serial.print(code[d]); Serial.println("  ");
  }
}

void loop()
{
  for (int f = 14; f <= 19; f++)
  {
    byte BP = digitalRead(f);
    if (BP == LOW)
    { delay(200);
      Serial.print("BP "); Serial.print(f); Serial.println(" est a LOW ");
      saisie[++indice_saisie] = f;
      Serial.print("indice_saisie "); Serial.print(" = "); Serial.println(indice_saisie);
      Serial.print("tableau_saisie "); Serial.print(indice_saisie); Serial.print(" = "); Serial.println(saisie[indice_saisie]);
      for (int d = 1; d <= 6; d++)
      {
        Serial.print("tableau_saisie "); Serial.print(d); Serial.print(" = "); Serial.println(saisie[d]);
      }
      if (indice_saisie >= 5)
      {
        for (int d = 1; d <= 6; d++)
        {
          saisie [d - 1] = saisie [d];
        } indice_saisie = 5;
      }
      concordance = 0;
      for (int d = 1; d <= 5; d++)
      {
        if (saisie[d] == code[d])
        {
          concordance++; Serial.print(concordance);
        }
      }
      if (concordance == 5)
      { Serial.println(".........................................code bon ");
        digitalWrite(LedRouge, LOW); digitalWrite(LedVerte, HIGH); delay(5000);
        digitalWrite(LedRouge, HIGH); digitalWrite(LedVerte, LOW);
        for (int d = 1; d <= 5; d++)
        {
          Serial.print(saisie[d]); Serial.println("  ");
        }
      }
      else
      {
        digitalWrite(LedRouge, HIGH); digitalWrite(LedVerte, LOW);
      }
      BP = HIGH;
    }
  }
}

arf, je viens de me rendre compte que dfgh t’a déja fait une proposition pendant que j’étais en train d’en faire une… bon bah comme c’est fait, je la met quand même, comme ça tu aura le choix

const int NbPoussoirs = 5;

const int PinPoussoirs[NbPoussoirs] = {2, 3, 4, 5, 6};    // pins d'entrée des poussoirs 1 à 5
//============

const int LedPin1 = 13;      // select the pin for the LED1 - La led 1 doit être placée sur l'entrée/sortie numérique 13 de l'arduino
const int LedPin5 = 9;      // select the pin for the LED5 - La led 5 ( verte qui signale l'ouverture du coffre) doit être placée sur l'entrée/sortie numérique 9 de l'arduino

//============

const int SizeCode = 5;

int Code[SizeCode] = {2, 3, 2, 1, 4};   
int CodeActuel[SizeCode] = {0};

//délai de sécurité : si il y a plus de temps entre deux appuis,le Code est effacé
unsigned long DernierAppui;
const unsigned long Delai = 5E3; // 5000 ms = 10 s

void setup()
{
	Serial.begin(9600);
	
	pinMode(LedPin1, OUTPUT);   
	pinMode(LedPin5, OUTPUT);

	for(int i = 0; i < NbPoussoirs; i++)
		pinMode(PinPoussoirs[i], INPUT);
	
	DernierAppui = millis();
}

void loop() 
{
	lireBoutons();
	
	if( comparerCodes() == true )
	{
		ouvrirPorte();
		//on raz le chrono de sécurité pour ne pas que la porte se referme seule ( il faudra appuyer un des boutons pour la refermer )
		DernierAppui = millis();
	}
	else
		fermerPorte();
	
	if (millis() - Delai > DernierAppui)
		remplirCode(0);
}

//====================

void ouvrirPorte()
{  
	digitalWrite(LedPin5, HIGH);  //Allumage de la led verte signalant l'ouverture de la porte
	digitalWrite(LedPin1, LOW);  //Extinction de la led rouge
}

void fermerPorte()
{
	digitalWrite(LedPin5, LOW);    //Extinction de la led verte
	digitalWrite(LedPin1, HIGH);    //Allumage de la led rouge
}


void lireBoutons()
{ 
	for(int i = 0; i < NbPoussoirs; i++)
		if ( digitalRead( PinPoussoirs[i] ) == HIGH ) //bouton appuyé ?
		{
			delay(15); //anti-rebond
			while ( digitalRead( PinPoussoirs[i] ) == HIGH ) {} //on attends d'avoir relaché le bouton
			remplirCode( i+1 ); //et on stocke le numéro du bouton dans le tableau
		}
		
		//si on est arrivé là, c'est qu'aucun bouton n'était appuyé : on retourne 0
}

void remplirCode(int valeur)
{
	//on décale les cases vers la première, qui est CodeActuel[0], car les index commencent toujours à 0 :
	for(int i = 1; i < SizeCode; i++) 
		CodeActuel[i-1]=CodeActuel[i];
	
	//et on remplit la dernière, donc à l'index taille du tableau -1 puisque que l'index commence à 0 :
	CodeActuel[SizeCode-1]=valeur; 
	
	//et comme qqch a changé, on l'affiche
	afficherCodes();
	
	//et enfin on raz le chrono de sécurité
	DernierAppui = millis();
}

void afficherCodes()
{
	Serial.println("--------Affichage du Code actuel-------");
	for(int i=0; i < SizeCode; i++)
	{
		Serial.print(CodeActuel[i]);
		Serial.print(" ");
	}
	Serial.println();
	
	Serial.println("--------Affichage du Code requis-------");
	for(int i=0; i < SizeCode; i++)
	{
		Serial.print(Code[i]);
		Serial.print(" ");
	}
	Serial.println();
}

bool comparerCodes()
{
	for(int i=0; i < SizeCode; i++)
		if (CodeActuel[i] != Code[i]);
			return false; //dès qu'une des valeurs est fausse, quitte et retourne faux
		
		return true; //si on est arrivé là, c'est que le Code est ok, on retourne vrai
}

Wow ! Merci à vous deux, j'en demandais pas tant ! Je vais les essayer tous les 2 en me les appropriant, ça m'obligera à les comprendre et donc à progresser. Je vous tiens au jus si j'ai d'autres questions.

Bricofoy, j'ai essayé ton programme et, pour une raison que j'ignore, la led verte ne s'allume pas quand le bon code est tapé. Le moniteur m'affiche pourtant dans "Affichage du code actuel" le même code que le code recquis mais rien ne se passe... Sur la fonction booléenne à la toute fin, il ne manque pas un "else" avant "return true"?

FoNeTiK47: Bricofoy, j'ai essayé ton programme et, pour une raison que j'ignore, la led verte ne s'allume pas quand le bon code est tapé. Le moniteur m'affiche pourtant dans "Affichage du code actuel" le même code que le code recquis mais rien ne se passe... Sur la fonction booléenne à la toute fin, il ne manque pas un "else" avant "return true"?

Non soit la boucle for trouve une erreur dans le code et elle quitte la fonction directement en retournant false sinon si la boucle a réussi à s’executer Entièrement c’est que tous les codes sont bons et donc on peut retourner true

Le soucis c’est Un ; en trop mais pas besoin de else

[nobbc]if (CodeActuel[i] != Code[i])[/nobbc][color=red][b];[/b][/color]

bon ben voilà, le temps que j’écrive ma réponse, JML à déjà tout dit :slight_smile:

mon indentation est fausse, il y a un en trop devant return true, du coup on dirait qu’il fait partie de la boucle for alors que non, c’est pour ça qu’on dirait qu’il manque un else.

Décidément, un <;>, un … y’a que des trucs en trop dans cette fonction :stuck_out_tongue:

Le principe c’est que le if n’est validé qu’en cas d’erreur de code. En cas d’erreur, le return false est exécuté, ce qui a pour effet de faire quitter la fonction en revoyant la valeur false (même si la boucle for n’a pas terminé son déroulement)
Quand par contre le code est bon, le if n’est jamais vrai ,donc return false n’est jamais exécuté, et la boucle for se termine, puis la suite est exécutée, donc return true.

Pfiou, ça y est ! Tout roule comme sur des roulettes ! Merci pour vos explications et merci pour le temps passé à taper un code qui ne vous sera d'aucune utilité.