decompte 60s pour départ de course.

Bonjour @ ts,

Tout nouveau dans le monde d’Arduino, je voudrai réaliser un projet et malgré pas mal de recherche sur le Net, j’ai un début de code mais je bloque sur la finalisation.
Je viens donc vers vous pour essayer de finir mon projet.

Le projet:

-Au départ afficher 60 (en clignotant 0,5s-0,5s)
-Appui sur un bouton poussoir ou inter M/A
-Faire un décompte de 60s à 0s.
-A 3s je voudrai faire allumer une led (orange) → commander une sortie de l’Arduino (ex 12).
-A 0s éteindre la led (orange) et faire allumer une led verte → commander une sortie de l’Arduino (ex 13) (reste allumée si possible)

Je suis parti du montage suivant.

J’ai réussi à modifier le code pour décompter :smiley: (le code donné pour ce circuit est un compteur de 0 à 99.

J’avoue que je n’ai pas encore étudié de faire clignoter “60” avant l’appui sur le bouton. Je pensais faire une code dans “void setup()”. Ais-je bon ou tout faut?..

Le soucis que j’ai c’est que lorsque j’appuie sur le bouton-poussoir (bp) j’ai bien le décompte qui se fait mais lorsque j’arrive à -1 il repert de nouveau depuis 60.

Hors je voudrai que ça s’arrête.

J’ai essayé de rajouter une variable qui s’incrémenterait et en utilisant les fonctions “if” ou “While”. Mais là soit ça s’affiche “60” ou “00” et là plus rien ne se passe (pas de décompte en appuyant sur le bouton).

Je me doute que sooit ce n’est pas ces fonctions qu’il faut utiliser ou alors je ne les place pas où il faut.

Il en est de même pour commander la sortie “12” lorsque j’arrive à 3s.

Voilà, j’espère ne rien avoir oublié et aussi avoir été assez clair dans mes explications.

Maintenant je m’en remet à vos connaissances d’expert en Arduino et en espérant que vous puissiez m’aider.

Merci par avance pour vos réponses.

Amitiés @ ts

Didier

compteur 0-100-avec BP.jpg

Decompte_60-0_avec_BP.ino (3.84 KB)

Re-Bjr @ ts,

Petit rectificatif, je viens de réussir à faire allumer la sortie 13 à 3s (pour essayer la led de la carte) et l'éteindre à -1.

Par contre je ne vois pas comment incérer le nouveau code. Du coup je vais le coller (la partie modifiée) en dessous.

int n=60; //Setting initial value of n to 0 int d1; int d2; int bp = 2; //bouton poussoir int state = 0; int led = 13; // voyant 3s

void setup() { pinMode(4,OUTPUT); pinMode(5,OUTPUT); pinMode(6,OUTPUT); pinMode(7,OUTPUT); pinMode(8,OUTPUT); pinMode(9,OUTPUT); pinMode(10,OUTPUT); pinMode(11,OUTPUT); pinMode(13,OUTPUT); pinMode(bp,INPUT);

}

void loop() { state = digitalRead(bp); if(state == HIGH) { n--; } if(n==3) { digitalWrite(led, HIGH); }

if(n==-1) { n=60; digitalWrite(led, LOW);

Tu n'expliques pas tout : en lisant ton code, je crois comprendre que le décompte se fait à chaque fois que tu appuies sur le bouton, est-ce exact ?

Pour ton schéma : tu devrais lire un peu de doc sur le bouton poussoir : tu verras que si tu le déclares en : pinMode(bp,INPUT_PULLUP);tu n'as plus besoin des résistances (par contre, il faut le connecter comme c'est expliqué dans le lien). Et tu liras un LOW lorsque le bouton sera appuyé. De plus il faut gérer les rebonds. La bibliothèque bounce2 permet de le faire simplement. Sinon, tu peux aussi ajouter un delay(300); après la lecture du bouton.

Pour faire clignoter l'affichage au début, en effet tu peux le faire dans le setup : je te l'explique en pseudocode

lecture bouton poussoir
tant que le bouton n'est pas appuyé 
  {
  Affichage 60 
  delay(500);
  Affichage vide
  delay(500);
  lecture bouton poussoir
  }

Au passage si tu as un if avec une seule instruction à réaliser, tu n'as pas besoin des accolades. Donc :

 if(state == HIGH)
 {
   n--; 
 }

équivaut à (et c'est plus facile à lire) :if(state == HIGH) n--;

Dernière chose : tu dis que tu as 2 LEDs. Une orange sur la pin 12 et une verte sur la pin 13. Ton code doit donc être :

void loop()
{
 state = digitalRead(bp);
 delay(300);
 if(state == LOW) n--; // BP appuyé = LOW si INPUT_PULLUP
 if(n == 3) digitalWrite(12, HIGH);  
 if(n == - 1) {
   n = 60;
   digitalWrite(12, LOW);
   digitalWrite(13, HIGH);  
  }
}

Et tu peux même le réduire un peu avec :

 state = digitalRead(bp);
if(state == LOW) n--; // BP appuyé = LOW si INPUT_PULLUP

remplacé par

 if(!digitalRead(bp)) n--; // BP appuyé = LOW si INPUT_PULLUP

et le delay(300) juste après.

Encore une remarque : tout ce que tu déclares en 'int' mais qui reste entre 0 et 255 peut être déclaré en 'byte'. Ça diminue la place mémoire utilisée.

Voilà, bonne continuation !

+1 avec lesept
regarde les liens qu’il te propose pour comprendre l’intérêt de câbler en INPUT_PULLUP

je t’ai préparé un code que tu pourras tester, comprendre et modifier
nota: je n’ai pas testé, le moniteur est sur 250000, tu nous diras

//BCD 1
const int hexa_A          = 4;
const int hexa_B          = 5;
const int hexa_C          = 6;
const int hexa_D          = 7;
//BCD 2
const int d_hexa_A          = 8;
const int d_hexa_B          = 9;
const int d_hexa_C          = 10;
const int d_hexa_D          = 11;

unsigned long chrono=0;

int n=60; //Setting initial value of n to 0
int d1;
int d2;
int bp = 2; //bouton poussoir
int state = 0;
int memo_state=0;

void setup()
{ Serial.begin(250000);
  for(int f=4;f<=11;f++){pinMode(f,OUTPUT);}
  pinMode(bp,INPUT_PULLUP);//doit faire contact avec GND lorsqu'appuyé
}

void loop()
{        
 if (!digitalRead(bp))       //s'i y a eu un appui sur BP
 { delay(500);              //anti rebonds
 memo_state = !memo_state;  //appui mémorisé jusqu'à un nouvel appui qui annulera
 Serial.println(memo_state);
 }
 if(memo_state)            //ctrl si le BP à été appuyé
   {                         //oui, on va ajuster la boucle sur 1 seconde
   chrono=millis();        //on initialise le chrono pour la boucle
   n--; 
   
 if(n==-1)
   {
   n=60;
   memo_state = !memo_state; //on stoppe le decomptage
   }
 d1=n%10; // This will divide n by 10 and the remainder will be stored in d1
 d2=n/10; // This will divide n by 10 and the value before decimal will be stored in d2
 gestion_afficheur(1,d1);
 gestion_afficheur(2,d2);Serial.println(n);
 while((millis()-chrono)<1000){;}//on ajuste la durée de la boucle pour 1 seconde
}}
void gestion_afficheur(byte digit,int chiffre)
{
  switch (chiffre)
        { 
         case 0://             D C B A   //chiffre 0
           actionDigital(digit,0,0,0,0);
           break ;
         case 1://             D C B A   //chiffre 1
           actionDigital(digit,0,0,0,1);
           break ;
         case 2://             D C B A    //chiffre 2
           actionDigital(digit,0,0,1,0);
           break ;
         case 3://             D C B A    //chiffre 3
           actionDigital(digit,0,0,1,1);
           break ;
         case 4://             D C B A    //chiffre 4
           actionDigital(digit,0,1,0,0);
           break ;
         case 5://             D C B A    //chiffre 5
           actionDigital(digit,0,1,0,1);
           break ;                         
         case 6://             D C B A    //chiffre 6
           actionDigital(digit,0,1,1,0);
           break ;       
         case 7://             D C B A    //chiffre 7
           actionDigital(digit,0,1,1,1);
           break ;
         case 8://             D C B A    //chiffre 8
           actionDigital(digit,1,0,0,0);
           break ;
         case 9://             D C B A    //chiffre 9
           actionDigital(digit,1,0,0,1);
           break ;
         default:
         break;
       }
  }

   //                      D        C         B         A           
  void actionDigital(byte digit, byte un,byte deux,byte trois,byte quatre)
  {  if(digit==1){
     digitalWrite(hexa_D, un);           // D, est la pinoche 7
     digitalWrite(hexa_C, deux);         // C, est la pinoche 6
     digitalWrite(hexa_B, trois);        // B, est la pinoche 5
     digitalWrite(hexa_A, quatre);       // A, est la pinoche 4
     }
     else{
       if(digit==2){
     digitalWrite(hexa_D+4, un);         // D, est la pinoche 11
     digitalWrite(hexa_C+4, deux);       // C, est la pinoche 10
     digitalWrite(hexa_B+4, trois);      // B, est la pinoche 9
     digitalWrite(hexa_A+4, quatre);     // A, est la pinoche 8
     }
   }
 }

@dfgh : les quatre derniers arguments de la fonction actiondigital sont en fait la traduction en binaire de la valeur de "chiffre" . Il devrait être possible du coup de se passer du switch.

Le premier argument doit valoir (chiffre & 8) , le second (chiffre & 4), etc.

hello le sept et oui, les "mask", bien vu :)

Et aussidelay(500);              //anti rebondsc’est un peu bcp 1/2 seconde...pou rjuste de l’anti rebond 15ms suffisent généralement

Pour moi c’est typiquement une définition de programme qui se prête bien à la programmation par machine à états (cf mon tuto éventuellement). Il y a deux types d'évènements à surveiller, le bouton et le temps

hello JML oui c'est énorme, habituellement, je met beaucoup moins. mais ici, comme la boucle doit faire une seconde, je pouvais me permettre, car je manipais avec un bout de câble. puis j'ai omis de réduire le "delay" avant de poster

Bjr @ ts,

Et merci à tous de vos réponses.

@ "lesept ":

Effectivement, je voudrai pouvoir lancer le décompte lorsqu'on appuie sur le BP, puis une fois terminé (arrivée à -1) relancer le décompte. Hors avec mon code il faut que je laisse le doigt appuyé sur le bouton pour aller jusqu'au bout, mais par contre il ne redémarre pas au prochain coup.

J'ai suivi tes conseils et modifié le câblage et code du bouton. J'avais bien vu ce montage mais j'avais hésité à le faire. Pourquoi, tu me diras? En fait je ne sais pas trop, peut-être à cause du mot "PULLUP" qui m'a fait peur… LOL

Merci également de tes conseils pour réduire les lignes de commande. Est-ce que cela fait gagner beaucoup de place en mémoire, stp? Je te demande ça car pour moi comme sont écrites les lignes c'est plus clair dans ma tête.

Et également merci pour le fait d'utiliser "byte" à la place de "int".

@ "dfgh":

Je te remercie pour ton code et je vais essayer de le comprendre (ça risque de prendre du temps -> je comprend vite, mais faut m'expliquer longtemps, reLOL). J'aime bien comprendre les chose (et ne pas les reproduire bêtement) avant de les mettre en place.

Je ne l'ai pas étudié en détail mais j'ai déjà quelques questions à te poser (certaines te paraitrons sans doute bête, mais, comme je l'ai marqué, je débute avec "Arduino"):

  • Que signifie "unsigned long chrono=0;"

  • Ici "if(memo_state) //ctrl si le BP à été appuyé" cela veut dire que "memostate" a changé d'état et à une valeur "vrai", pas besoin de rajouter "==1"

  • Un truc que je n'arrive à comprendre c'est l'utilisation de "millis" à la place de "delay"

  • Peux-tu m'expliquer l'utlisation de "switch"? Est-ce que cela ressemble à un tableau? Et pourquoi "lesept" et dit que l'on peut s'en passer? Je sais je suis curieux...

Dans mon code j'ai mis "500" pour le delais de comptage c'est pour en fait que ça aille plus vite. Je mettrai "1000" à la fin une fois mon code au point.

Et enfin une question générale sur l'utilisation du forum: Comment faites-vous pour mettre vos codes dans la fenêtre "code:[Select]?

Merci @ ts, @+ Didier

hello
pour le code voir ICI

pour le delay(500): non il faut mettre 30ms.
la dernière ligne du prg s’assure que la boucle dure une seconde.(la ligne du while)

unsigned long chrono = 0;
déclare une variable du nom de chrono de type “long non signé” et l’initialise à zéro ( en principe inutile car le compilo le fait d’office, mais l’habitude étant prise…je le fais quand meme.)
pour les questions de langage, voir ici
tu peux y chercher “unsigned” long en milieu de page dans la partie “variables”.

if(memostate){…} :oui, c’est sous entendu “si memostate==true”

milli();: il faut imaginer que dès que le prg démarre, un compteur interne s’incrémente à la cadence de 1 milliseconde. tu imagines facilement qu’au bout de peu de temps, le compteur aura une valeur énorme.
( d’ou l’emploi de “unsigned long”) et il s’incrémentera ainsi pendant ( je ne sais plus au juste, mais ça tourne autour de 47 ou 49 jours)
un appel à la fonction millis() retourne la valeur du compteur.

maintenant; si tu veux chronométrer un événement. tu mémorises la valeur du compteur au début de l’événement:
exemple: variable de type unsigned long “debut”=millis();
imagine que maintenant “debut” vaut 145263. donc des millisecondes, soit 145secondes et 263 millisecondes.

ensuite ton événement se déroule, et à la fin tu relèves le compteur et tu calcul la durée
nous sommes toujours dans les unsigned long
donc unsigned long duree=millis()-debut;
supposes que milli(); ait retourné 155268 alors durée vaudra 155268-145263=10005. soit 10 secondes et 5 millièmes.

switch(valeur): il faut le voir comme un aiguillage
et entendre si valeur=1, alors exécuter le code qui est contenu dans “case 1”
dans le cas du prg, si valeur =1, on initialise les sorties du µ vers le 4511 avec les valeur qui correspondes aux 4 bits de valeur. puis ont appelle la fonction qui applique ces 4 sorties sur les entrées du 4511 (le 1er ou le 2ème selon le digit à traiter).

le sept dit qu’il y avait plus simple et c’est vrai.
je te joint le code modifié

//BCD 1
const int hexa_A          = 4;
const int hexa_B          = 5;
const int hexa_C          = 6;
const int hexa_D          = 7;
//BCD 2
const int d_hexa_A          = 8;
const int d_hexa_B          = 9;
const int d_hexa_C          = 10;
const int d_hexa_D          = 11;

unsigned long chrono=0;

int n=60; //Setting initial value of n to 0
int d1;
int d2;
int bp = 2; //bouton poussoir
int state = 0;
int memo_state=0;

void setup()
{ Serial.begin(250000);
  for(int f=4;f<=11;f++){pinMode(f,OUTPUT);}
  pinMode(bp,INPUT_PULLUP);//doit faire contact avec GND lorsqu'appuyé
}

void loop()
{        
 if (!digitalRead(bp))       //s'i y a eu un appui sur BP
 { delay(500);              //anti rebonds
 memo_state = !memo_state;  //appui mémorisé jusqu'à un nouvel appui qui annulera
 Serial.println(memo_state);
 }
 if(memo_state)            //ctrl si le BP à été appuyé
   {                         //oui, on va ajuster la boucle sur 1 seconde
   chrono=millis();        //on initialise le chrono pour la boucle
   n--; 
   
 if(n==-1)
   {
   n=60;
   memo_state = !memo_state; //on stoppe le decomptage
   }
 d1=n%10; // This will divide n by 10 and the remainder will be stored in d1
 d2=n/10; // This will divide n by 10 and the value before decimal will be stored in d2
 actionDigital(1,d1&8,d1&4,d1&2,d1&1);//unites
 actionDigital(2,d2&8,d2&4,d2&2,d2&1);//dizaines
 Serial.println(n);
 while((millis()-chrono)<1000){;}//on ajuste la durée de la boucle pour 1 seconde
}}




   //                      D        C         B         A           
  void actionDigital(byte digit, byte un,byte deux,byte trois,byte quatre)
  {  if(digit==1){
     digitalWrite(hexa_D, un);           // D, est la pinoche 7
     digitalWrite(hexa_C, deux);         // C, est la pinoche 6
     digitalWrite(hexa_B, trois);        // B, est la pinoche 5
     digitalWrite(hexa_A, quatre);       // A, est la pinoche 4
     }
     else{
       if(digit==2){
     digitalWrite(hexa_D+4, un);         // D, est la pinoche 11
     digitalWrite(hexa_C+4, deux);       // C, est la pinoche 10
     digitalWrite(hexa_B+4, trois);      // B, est la pinoche 9
     digitalWrite(hexa_A+4, quatre);     // A, est la pinoche 8
     }
   }
 }

Bonsoir “dfgh”

Et à nouveau merci pour tes explications.

Pour ce qui est du langage → lien mis aussitôt dans les favoris (ça peut toujours servir)…

Merci également pour ton nouveau code.
J’ai essayé le 1er et ça fonctionne nickel (je n’en doutais pas)…
Du coup je l’ai un peu modifié et voilà ce que ça donne.
-Pour le code

//BCD 1
const int hexa_A          = 4;
const int hexa_B          = 5;
const int hexa_C          = 6;
const int hexa_D          = 7;
//BCD 2
const int d_hexa_A          = 8;
const int d_hexa_B          = 9;
const int d_hexa_C          = 10;
const int d_hexa_D          = 11;

unsigned long chrono=0;

int n=60; //Setting initial value of n to 0
int d1;
int d2;
int bp = 2; //bouton poussoir
int state = 0;
int memo_state=0;
int ledVerte = 13;
int ledOrange1 = A1;
int ledOrange2 = A2;
int ledOrange3 = A3;
int ledRouge = 3;

void setup()
{ Serial.begin(250000);
  for(int f=3;f<=13;f++){pinMode(f,OUTPUT);}
  for(int g=1;g<=3;g++){pinMode(g,OUTPUT);}
  pinMode(bp,INPUT_PULLUP);//doit faire contact avec GND lorsqu'appuyé
  
}

void loop()
{       
 if (!digitalRead(bp))       //s'i y a eu un appui sur BP
 { delay(500);                //anti rebonds
 memo_state = !memo_state;  //appui mémorisé jusqu'à un nouvel appui qui annulera
 Serial.println(memo_state);
 }

 if(memo_state)            //ctrl si le BP à été appuyé
   {                        //oui, on va ajuster la boucle sur 1 seconde
 
   chrono=millis();        //on initialise le chrono pour la boucle
   n--;
    

 if(n>3)
 {  
   digitalWrite(ledRouge, HIGH); 
 }
if(n==3)
 {
 digitalWrite(ledRouge, LOW);
 digitalWrite(ledOrange1, HIGH);
 }
 if(n==2)
 {
 digitalWrite(ledOrange2, HIGH);
 }
 if(n==1)
 {
 digitalWrite(ledOrange3, HIGH);
 }
if(n==0)
 {
   digitalWrite(ledOrange1, LOW);
   digitalWrite(ledOrange2, LOW);
   digitalWrite(ledOrange3, LOW);
   digitalWrite(ledVerte, HIGH);
 }  
 if(n==-1)
   {
   n=60;
   memo_state = !memo_state; //on stoppe le decomptage
   delay(15000);
   digitalWrite(ledVerte, LOW);
   
   }
 d1=n%10; // This will divide n by 10 and the remainder will be stored in d1
 d2=n/10; // This will divide n by 10 and the value before decimal will be stored in d2
 gestion_afficheur(1,d1);
 gestion_afficheur(2,d2);Serial.println(n);
 while((millis()-chrono)<1000){;}//on ajuste la durée de la boucle pour 1 seconde
}

}
void gestion_afficheur(byte digit,int chiffre)
{
  switch (chiffre)
        { 
         case 0://             D C B A   //chiffre 0
           actionDigital(digit,0,0,0,0);
           break ;
         case 1://             D C B A   //chiffre 1
           actionDigital(digit,0,0,0,1);
           break ;
         case 2://             D C B A    //chiffre 2
           actionDigital(digit,0,0,1,0);
           break ;
         case 3://             D C B A    //chiffre 3
           actionDigital(digit,0,0,1,1);
           break ;
         case 4://             D C B A    //chiffre 4
           actionDigital(digit,0,1,0,0);
           break ;
         case 5://             D C B A    //chiffre 5
           actionDigital(digit,0,1,0,1);
           break ;                         
         case 6://             D C B A    //chiffre 6
           actionDigital(digit,0,1,1,0);
           break ;       
         case 7://             D C B A    //chiffre 7
           actionDigital(digit,0,1,1,1);
           break ;
         case 8://             D C B A    //chiffre 8
           actionDigital(digit,1,0,0,0);
           break ;
         case 9://             D C B A    //chiffre 9
           actionDigital(digit,1,0,0,1);
           break ;
         default:
         break;
       }
  }

   //                      D        C         B         A           
  void actionDigital(byte digit, byte un,byte deux,byte trois,byte quatre)
  {  if(digit==1){
     digitalWrite(hexa_D, un);           // D, est la pinoche 7
     digitalWrite(hexa_C, deux);         // C, est la pinoche 6
     digitalWrite(hexa_B, trois);        // B, est la pinoche 5
     digitalWrite(hexa_A, quatre);       // A, est la pinoche 4
     }
     else{
       if(digit==2){
     digitalWrite(hexa_D+4, un);         // D, est la pinoche 11
     digitalWrite(hexa_C+4, deux);       // C, est la pinoche 10
     digitalWrite(hexa_B+4, trois);      // B, est la pinoche 9
     digitalWrite(hexa_A+4, quatre);     // A, est la pinoche 8
     }
   }
 }

-en vidéo (j’espère qu’elle n’est pas bloquée:

Pour ton nouveau code je vais tout de même l’essayer et le décortiquer pour le comprendre.

Bon je me doute qu’on peut simplifier les choses, mais en regardant au moment du téléversage, ça indique l’occupation mémoire et j’en utilise pas beaucoup.
Je vais peut-être en rester là pour l’instant et par la suite essayer de reduire pour le fun…

En tout cas encore merci pour ton aide.

@+

hello
merci du retour :slight_smile: