Serrure qui s'ouvre selon un rythme produit par l'utilisateur

Bonjour,
Je m'excuse tout d'abord si ce que je dis semble brouillon, j'ai des bases très faibles en programmation et ne connais sans doute pas les conventions.
Je suis étudiant en 2eme année de licence de physique, et nous avions un projet d'électronique a rendre pour la fin de l'année, mais le COVID et les fermetures d'établissements ont un peu bousculé l'organisation.
Nous avons choisi avec mon binôme de créer un système de serrure, qui ne s'ouvre que si un certain rythme à été tapé avec nos mains, et ce projet avait été validé par les enseignants, malheureusement la communication avec eux s'est faite difficile pendant ces quelques mois, et sans réponse depuis bientôt un mois, je tente ma chance ici.

int Rythme = 13 ;       //Led qui servira de Métronome
int Clap = 2 ;         //Entrée du Microphone qui détecte les claquements de mains/doigts
int Faux = 12 ;         //Led qui affichera si une erreur à été faite
int Fermeture = 3;      
float temps_debut, temps_ecoule;     //Temps qui serviront a calculer le rythme                
bool ouvert = false;
int phase = 0;                       //variable pour savoir a quel moment du rythme nous sommes

void setup() {                                    
  Serial.begin(9600);
  attachInterrupt(digitalPinToInterrupt(Clap),arrivee_signal,RISING);       //Un AmpliOp sera utilisé, on attend alors une élévation de 0 à 5V
  attachInterrupt(digitalPinToInterrupt(Fermeture), Fermer, RISING);        //C'est un simple bouton poussoir, élévation de 0 à 5V encore 
  pinMode(Rythme, OUTPUT);
  pinMode(Clap, INPUT);
  pinMode(Faux, OUTPUT);

}

void arrivee_signal() {                   
  if (phase = 0) {                      //premier clap, alors prendre le temps de debut
     temps_debut=millis();
     phase = 1;                         //passer a la phase suivante
  }
  else {
    temps_ecoule = millis()-temps_debut ;     //calculer le temps ecoulé depuis les dernier clap
    if (phase = 1) {                          //détecte a quelle phase nous sommes
      if (temps_ecoule > 500 and temps_ecoule < 600) {      //verifie que le temps écoulé soit le bon, avec un certain interval
      phase =+1;                                //passer a la phase suivante
      temps_debut = millis();                   //reinitialiser le temps de référence
    }
    else {
      digitalWrite(Faux, HIGH);                 //si une erreur a été faite, allumer la LED d'erreur
      delay(1000);
      digitalWrite(Faux, LOW);                  //laisser la Led allumée une seconde
      phase = 0;
    }
    }
    else {
      if (phase = 2) {
         if (temps_ecoule > 500 and temps_ecoule < 600) {
      phase =+1;
      temps_debut = millis();
    }
    else {
      digitalWrite(Faux, HIGH);
      delay(1000);
      digitalWrite(Faux, LOW);
      phase = 0;
    }
      }
    }
    }
  }


void Fermer() {
  if (ouvert = true ){
                            //Fermer la serrure 
  }
  else {
    for (int i=0; i<=10; i++) //La serrure est déja fermée, le montrer en faisant clignoter la LED d'erreur
     digitalWrite(Faux, HIGH);
      delay(80);
      digitalWrite(Faux, LOW);
      delay(80);
  }
}
void loop() {
    if (phase=3){
      digitalWrite(Rythme, HIGH);
                                        //ici ouvrir la serrure
      ouvert = true;
    }
}

Nous avons été conseillé d'utiliser des interruptions pour détecter les clappements, ce qui semble effectivement être la solution, mais après avoir envoyé une première version du code, certaines erreurs ont été relevées qui ont entrainées des questions auxquelles nous n'avons pas eu de réponses:

-Il n'est apparemment pas une bonne idée de traiter l'interruption dans le sous programme de l'interruption, car cela empêche une autre interruption, mais alors comment détecter qu'une interruption a eu lieu dans le programme principal?

-Après la fin du traitement du sous programme d'interruption, ou "reprend" le programme ? Ou il en etait, ou revient il au debut de la boucle loop?

-Nous aimerions avoir une Led qui clignotte afin de servir de métronome pour taper le rythme, est il possible de la faire clignoter avec le même programme?

-Nous utilisons une serrure solénoide qui demande trop d'intensité pour arduino, quel critères faut il regarder pour choisir un relais?

Une difficulté supplémentaire ici est que nous n'avons pas accès au matériel, tout est purement théorique donc et e projet ne sera jamais réalisé, ce qui n'aide pas a découvrir les choses par nous même comme il était initialement prévu. Je vous remercie d'avance pour avoir lu jusque ici, en espérant que vous ayez des réponses a nos questions.

-Il n'est apparemment pas une bonne idée de traiter l'interruption dans le sous programme de l'interruption, car cela empêche une autre interruption, mais alors comment détecter qu'une interruption a eu lieu dans le programme principal?

On conseille fortement d'avoir des fonctions d'interruptions courtes. Dans le cas de cet exemple, on ne peut pas faire le traitement dans la fonction d'interruption, il est trop long. Mais on peut positionner des variables que l'on va lire dans le programme principal dans loop. Il faut déclarer ces variables avec volatile en plus.

Par exemple arrivee_signal() ne va que positionner temps_debut. Le reste est analyser dans loop.

Effectivement quand on rentre dans une fonction d'interruption, cela désactive les interruptions, on ne peut en traiter qu'une à la fois. Et delay(1000) qui utilise le résultat d'une interruption (le timer 0 remet à jour le temps système par interruption) ne peut pas marcher (le temps système est bloqué).

On ne peut pas employer delay dans une interruption, et millis retournera toujours la même valeur tant qu'on ne sort pas de l'interruption. Mais on peut utiliser millis pour mettre à jour temps_debut.

Mais si la fonction est courte, les interruptions peuvent s'enchaîner.

-Après la fin du traitement du sous programme d'interruption, ou "reprend" le programme ? Ou il en etait, ou revient il au debut de la boucle loop?

Exactement là ou on l'avait quitté, exactement comme moi si je lis un livre toute la matinée et que je suis interrompu par le facteur, le téléphone, les WC...

Et c'est heureux car toutes les ms environ, le timer 0 remet à jour l'horloge interne, et on ne s'en rend même pas compte (pareil sur un ordi d'ailleurs).

-Nous aimerions avoir une Led qui clignote afin de servir de métronome pour taper le rythme, est il possible de la faire clignoter avec le même programme?

Oui. Si pendant que la led clignote on n'a rien à faire, on peut utiliser delay, sinon on utilise une interruption par exemple du timer 1 pour le faire. Il faudra alors deux ordres: "clignote" et "arrête de clignoter". En allant un peu plus loin, on peut aussi ne donner que l'ordre "clignotte 3 fois" et la procédure d'interruption fera ces 3 flashs.

-Nous utilisons une serrure solénoide qui demande trop d'intensité pour arduino, quel critères faut il regarder pour choisir un relais?

Que l'on utilise un relais ou un mosfet, il faut avoir

  • le solénoïde est utilisé en continu ou en alternatif?
  • sous quelle tension?
  • quel est son courant nominal?

Merci pour cette réponse complète, désolé de ne pas répondre plus tot.
j'ai donc modifié les interruptions afin qu'elles soient plus courtes :

void arrivee_signal() {                   
  temps_ecoule = millis() - temps_debut;
  attente = true;
}
void Fermer() {
  fermeture = true;
}

vileroi:
Si pendant que la led clignote on n'a rien à faire, on peut utiliser delay, sinon on utilise une interruption par exemple du timer 1 pour le faire. Il faudra alors deux ordres: "clignote" et "arrête de clignoter".

Je n'ai pas trouvé comment faire des interruptions qui dépendent d'un temps, mais utilisé ce code afin de faire un métronome :

int Rythme = 13 ;
int Metronome = 600;
boolean Flag;
unsigned long Depart;

void setup() {
  Serial.begin(9600);
  pinMode(Rythme, OUTPUT);
  Depart = millis();
  
}
void loop() {
  if((millis() - Depart )>= Metronome){
    Flag=!Flag;
    digitalWrite(Rythme,Flag);
    Depart=millis();
  }
}

vileroi:
Que l'on utilise un relais ou un mosfet, il faut avoir

  • le solénoïde est utilisé en continu ou en alternatif?
  • sous quelle tension?
  • quel est son courant nominal?

Le solénoide est en courant continu, 12V et 600 mA, est-ce qu'un relais comme celui-la conviendrait? Relais Omron G5V1-12 Omron - Relais miniatures < 5A | GO TRONIC
Que signifie 1 inverseur 1A? il rendrait un courant quand il n'y en a pas dans son entrée et inversement?

il doit exister au moins quelques centaines de projets en lignes. cherchez "knock box arduino" ou "Arduino Secret Knock Detecting Lock"

voici le premier résultat

Le solénoide est en courant continu, 12V et 600 mA, est-ce qu'un relais comme celui-la conviendrait? Relais Omron G5V1-12 Omron - Relais miniatures < 5A | GO TRONIC

C'est sympa quand il y a un lien internet de le mettre ente balise lien. Cela facilite la lecture. On pointe dessus sans avoir à faire un couper coller et d'ouvrir une nouvelle page... Cela peut donner plus de réponses.

Ne pas confondre l'entrée et la sortie du relais. 12V c'est pour l'entrée, la commande de la bobine. Pour ce relais, la sortie est

Pouvoir de coupure: 1 A/24 Vcc ou 0,5 A/125 Vac

. On peut prendre un relais 5V par exemple

Pour alimenter une charge en courant continu, il y a deux écoles, les relais et les transistors.Pour 600mA, un transistor darlinton doit passer, sinon pour les prix actuels, un mosfet genre ILZ44N est largement sur dimensionné. Un 2N2222 est insuffisant, d'autant plus que l'Arduino ne pourra pas fournir le courant de base pour 600mA au collecteur.

Pour le relais, si il est en 12V, il faut absolument mettre un transistor pour le commander à cause de la tension de 12V. Et si on doit mettre un transistor, autant qu'il commande le solénoïde. Dans la même série, il y a un relais 5V, mais il demande une commande en 30mA. Mais demander 30mA à un Arduino fait chuter sa sortie de 1.5V environ,et 1) le relais risque de ne pas coller 2) beaucoup déconseillent de tirer 30mA.

En résumé, soit on met un transistor seul, soit on met un relais commandé par un transistor! La seule différence est qu'un 2N2222 peut commander le relais, si on a ces bêtes en tiroir.

Si le tiroir des pièces détachées est vide, c'est parti pour un Mosfet (éventuellement un darlington)

Avec une solénoïde relais ou transistor, il faut une diode de roue libre en parallèle sur la solénoïde.

Que signifie 1 inverseur 1A? il rendrait un courant quand il n'y en a pas dans son entrée et inversement?

Sortie et entrée sont indépendante. La sortie est équivalente à un bouton va et vient de lumière. Elle ne donnera jamais de courant (elle peut le laisser passer, c'est tout).

Inverseur indique qu'il y a 3 broches pour la sortie, un commun, une broche connectée au commun quand l'entrée est alimentée, et une broche reliée au commun quand l'entrée n'est pas alimentée. Comme un va et vient. 1A indique son pouvoir de coupure sur une résistance (sur charge inductive avec diode aussi)