Clignotement avec deux leds et deux boutons

Bonjour/Bonsoir

je suis débutant en Arduino.

Remis en contexte :

Je voudrais faire Clignoter deux leds et deux boutons
(me servir en temps que Clignotant pour VTT
tout fonctionne, mais je n'arrive pas à dire à l'Arduino
que si la led 'A' clionne déja, alors l'éteindree quand
on appuis sur le 2ème boutton pour allumer la 'B'

Voici le script :

int e = 0;
int antirebond = 500;
#define BB 3  // bouton 'B' pin3 de l'arduino uno
#define B 12  // led 'B' de la carte sur pin12
#define AB 2  // bouton 'A' pin2 de l'arduino uno
#define A 13  // led 'A' de la carte sur pin13
void setup()
{
  pinMode(A, OUTPUT);
  pinMode(AB, INPUT_PULLUP);  // pull up interne activé 
  pinMode(B, OUTPUT);
  pinMode(BB, INPUT_PULLUP);  // pull up interne activé 
}

void loop()
{
  if (digitalRead(AB) == LOW && e == 0) //si on appui sur le btn on lit etat bas vu pullup interne
    
  {
   
    e = 1;
    
    delay(antirebond);
    
    while (e = 1) //tant que (clignotement de la led jusqu'au prochain appui sur le btn)
    {
      digitalWrite(A, HIGH);
      delay(500);
      digitalWrite(A, LOW);
      delay(500);
      if (digitalRead(AB) == LOW && e==1) //si appui sur le btn
      {
        
        delay(antirebond);
        digitalWrite(A, LOW); // led éteinte
        e = 0;
      
        break; //interruption
      }
    }
  }
  
  if (digitalRead(BB) == LOW && e == 0) //si on appui sur le btn on lit etat bas vu pullup interne
  

  {
    e = 2;
    
    delay(antirebond);
    while (e = 2) //tant que (clignotement de la led jusqu'au prochain appui sur le btn)
    {
      digitalWrite(B, HIGH);
      delay(500);
      digitalWrite(B, LOW);
      delay(500);
      if (digitalRead(BB) == LOW && e==2) //si appui sur le btn
      {
        
        delay(antirebond);
        digitalWrite(B, LOW); // led éteinte
        e = 0;
      
        break; //interruption
      }
    }
  }
  
}

clignotant.ino (1.58 KB)

Ton code est un peu compliqué, mais tu as compris le principal : il faut une variable qui contient l'état de la led (clignote ou pas). Tu as 2 leds, donc il te faut 2 variables d'état.

Ton code peut être fait comme suit :

Lecture bouton A
Si appuyé {état led A = clignotant, état led B éteint} sinon led A = éteint
Lecture bouton B
Si appuyé {état led B = clignotant, état led A éteint} sinon led B = éteint

Fin de lecture des boutons, on s'occupe des leds :
Lecture du temps
Si le temps est "pair", allumer la led qui clignote
Si le temps est "impair", éteindre la led qui clignote

"pair" et "impair", c'est juste un raccourci pour calculer si le moment est venu d'allumer la led. Si le clignotement est temporisé par des attentes de 500 ms comme dans ton exemple, "pair" serait si le temps modulo 1000 est inférieur à 500 et "impair' supérieur à 500.

Ce pseudo code suppose que la led clignote tant que le bouton reste enfoncé. Comme tu n'as pas précisé comment les boutons doivent gérer les leds, c'est une possibilité. Mais il peut y en avoir d'autres : par exemple, un coup sur le bouton lance le clignotement, un second appui l'arrête.

A toi de voir...

91070 : c'est ton code postal (Bondoufle) ?

Merci beaucoup par contre je sais pas du tout comment manipuler cxe que tu m'a dit, pourrait tu (si tu le veut bien) d'essayer de retoucher pour voir ce que ça pourrait donner ? s'il te plait ?

Petit soucis iciwhile (e = 1)

Faudra aussi virer les delay(500) qui vont empêcher la majorité du temps une bonne réactivité des boutons

Lisez l’exemple “blink without delay” il faudra utiliser la même technique avec millis()

(sinon pour bien débuter avec l’arduino, un bon point de départ c’est de lire les tutos d’eskimon, il en a un sur ‘introduire le temps’)

Je peux t'aider en t'aiguillant pour l'écriture de ton code, mais il faut que tu précises le fonctionnement. Notamment celui des boutons.

J'ai compris que si on appuie sur le bouton A ça éteint la led B si elle clignotait, et ça fait clignoter la led A si elle est éteinte. Mais que faire si la led A clignote déjà ? On laisse clignoter ou on l'éteint ?

on l'éteint

en fait comme in clignotant de voiture, je voudrais reproduire la même chose, tout fonctionne mais le problème c'est que :

<<Si la LED "A" clignote déja après avoir puyé sur le bouton "AB" mais qu'après je veux appuyer sur le bouton "BB" je veux que la LED "A" s'éteigne et que la LED "B" clignote>>

c'est un peu Expérimental mais ça devrais fonctionner

L'idée c'est que tu vas utiliser des variables booléennes qui indiqueront l'état (clignotant ou éteint) de chaque led. Les boutons ne feront que mettre les variables à jour.

Il existe des leds qui clignotent toutes seules quand elles sont alimentées - avec un interrupteur 3 positions et ce genre de LEDs il nya pas besoin de programmation

Mais bon pour apprendre c’est bien :slight_smile:

Vous pourriez faire cela avec une petite machine à état sinon en terme de mode de programmation

En effet, il y a de nombreuses façons de faire ce genre de programme.

Voici ce que je ferais pour ma part (dans la loop) :

D'abord lecture des boutons :

bool AetatBouton = digitalRead(AB);
bool BetatBouton = digitalRead(BB);
delay(30); // antirebond

Ensuite mise à jour des états des leds: Si le bouton A est appuyé, la led B ne doit pas clignoter, la ledA doit clignoter si elle était éteinte ou s'éteindre si elle clignotait. Enfin, on initialise un chrono pour commander le clignotement de la led A si elle doit clignoter. Les variables doivent être déclarées en global ou au début de la loop.

if (!AetatBouton) {  // Bouton A appuyé
  AledCligno = !AledCligno;
  BledCligno = false;
  if (AledCligno) Achrono = millis();
  }

Et même chose avec la led B.

Puis on gère les clignotants. Je propose de déclarer des choses en global :

#define AperiodeCligno 1000 // ms
#define ArapportCyclique 50 // %
#define BperiodeCligno 2000
#define BrapportCyclique 75

Le rapport cyclique est le pourcentage de temps allumé lors du clignotement. A priori on met 50 (%) mais j'ai mis une autre valeur pour voir la différence.

Ça donne ensuite dans la loop (led A) :

unsigned long AdureeAllume = AperiodeCligno * ArapportCyclique / 100;
if (AledCligno) {
  if ((millis() - Achrono) % AperiodeCligno < AdureeAllume) digitalWrite(A, HIGH);
  else digitalWrite(A, LOW);
  }

Pour éviter de recalculer AdureeAllume à chaque fois, on peut la déclarer en global et faire le calcul une fois pour toutes dans le setup.

La fonction % (modulo) calcule le reste de la division du premier argument par le second. Le test regarde donc si le temps écoulé depuis le lancement du chrono de la led A (c'est à dire le moment où on a appuyé sur le bouton A pour lancer le clignotement) - module la période de clignotement - est inférieur au rapport cyclique : si oui on allume, sinon on éteint.

Il reste à faire la même chose pour la led B.

Je n'ai pas testé, c'est juste une idée pour l'instant, je te laisse voir si tu veux le mettre en oeuvre.

Pour éviter de recalculer AdureeAllume à chaque fois, on peut la déclarer en global et faire le calcul une fois pour toutes dans le setup.

Je ne sais pas si vous avez vérifié mais il se peut que unsigned long AdureeAllume = AperiodeCligno * ArapportCyclique / 100;ne vous donne pas le résultat escompté à cause d’un calcul fait en entier. Le compilo va remplacer les define par leur valeur et vous aurez 1000 * 50 / 100 et 50*1000 ça ne rentre pas dans un int de base.
Soit vous rajoutez des ul aux define, soit ceinture bretelle et vous dites au compilateur les types attendus - et vous pouvez même laisser le compilo tout calculer pour vous en définissant des constantes globales typées pour éviter tout soucis lié aux calculs entiers

const unsigned long  AperiodeCligno = 1000ul ; // ms
const unsigned int  ArapportCyclique = 50; // %
const unsigned long  BperiodeCligno = 2000ul;
const unsigned int  BrapportCyclique = 75;
const unsigned long AdureeAllume = AperiodeCligno * ArapportCyclique / 100;

l’optimiseur se chargera de bien gérer la mémoire et les registres.

Comme vous le savez j’aime bien quand on respecte les notions de cohérence de types plutôt que de laisser faire le compilo dans votre dos, donc perso (même si c’est pareil) je préfère écrire

bool boutonA_Appuye = (digitalRead(AB) == LOW); // PULLUP actif
bool boutonB_Appuye = (digitalRead(BB) == LOW);

ce qui a l’avantage aussi de montrer qu’on est conscient du mode PULLUP (ou mettre HIGH si pulldown)

Oui, je me suis dit qu'à ce niveau là, on pouvait louper quelques millisecondes, on ne verrait pas la différence. Mais la manière de faire que tu proposes est plus rigoureuse. Merci

lesept:
Oui, je me suis dit qu'à ce niveau là, on pouvait louper quelques millisecondes, on ne verrait pas la différence. Mais la manière de faire que tu proposes est plus rigoureuse. Merci

Pour le premier point (je suis sur mon portable peut pas tester) vous risquez surtout un calcul faux - à vérifiez si vous pouvez faire tourner sur un UNO

#define AperiodeCligno 1000 // ms
#define ArapportCyclique 50 // %

void setup()
{
  unsigned long AdureeAllume = AperiodeCligno * ArapportCyclique / 100;
  Serial.begin(115200);
  Serial.println(AdureeAllume);
  Serial.println(AperiodeCligno * ArapportCyclique);
}

void loop() {}

pour voir ce que ça donne, ce serait intéressant

Sur un nano, j'obtiens :

4294967141
-15536

et avec tes définitions on a les bonnes valeurs :

500
50000

OK - donc c'est bien le soucis du calcul par défaut en entiers

50 x 1000 ça fait 50000 normalement mais comme un int déborde à 32767 on se retrouve avec -15536 en "faisant le tour"

parce que 32767-50000= -17233 et (-17233 + -15536 + 1) ==> -32 768 soit la valeur min possible

Quand vous stockez le résultat dans un unsigned long, le signe négatif se propage et vous obtenez ainsi 4294967141 ==> on est loin de votre "on pouvait louper quelques millisecondes, on ne verrait pas la différence" :slight_smile:

Je vois ! Je pensais que le fait de déclarer
unsigned long AdureeAllume = AperiodeCligno * ArapportCyclique / 100;imposait un calcul en unsigned long pour toutes la valeurs utilisées !

je vois que les calculs sont un peut 'Expérimental" pour moi mais

le message : Clignotement avec deux leds et deux boutons - #9 by lesept - Français - Arduino Forum
de "lesept"

je vais essayer de réaliser ça ce soir, je recherche aussi de mon coté

Merci beaucoup à vous de continuer à chercher mon problème :slight_smile:
ça fait plaisir d'avoir une communauté d'électronique FR pour s'entraider aux soucis des autres.

unsigned long AdureeAllume = AperiodeCligno * ArapportCyclique / 100;

imposait un calcul en unsigned long pour toutes la valeurs utilisées !

Non, il faudrait préciser le type des valeurs comme ceci :

#define AperiodeCligno 1000UL // ms
#define ArapportCyclique 50UL // %

Il me semble que les deux notations fonctionnent : LU ou UL.

@+