Interférence de clignotement de LED avec bouton

Bonjour la communauté,

Je suis complètement nouveau en programmation Arduino mais après quelques semaines de recherches, j'ai réussi à écrire un bout de code pour l'éclairage d'une maquette de vaisseau spatial. Cependant je n'arrive pas trouver comment écrire correctement celui-ci pour que les deux LEDs verte et rouge n'interfèrent pas avec les autres lorsqu'on les active en appuyant sur les boutons. Est-ce que quelqu'un pourrait m'expliquer comment faire pour que les LEDs commandées par des boutons soient complètement indépendantes des autres ? Merci d'avance. Voici mon code:

#include <Adafruit_NeoPixel.h>
#define PIN 9
#define NUM_LEDS 2

// Parameter 1 = number of pixels in strip
// Parameter 2 = pin number (most are valid)
// Parameter 3 = pixel type flags, add together as needed:
//   NEO_KHZ800  800 KHz bitstream (most NeoPixel products w/WS2812 LEDs)
//   NEO_KHZ400  400 KHz (classic 'v1' (not v2) FLORA pixels, WS2811 drivers)
//   NEO_GRB     Pixels are wired for GRB bitstream (most NeoPixel products)
//   NEO_RGB     Pixels are wired for RGB bitstream (v1 FLORA pixels, not v2)
Adafruit_NeoPixel strip = Adafruit_NeoPixel(NUM_LEDS, PIN, NEO_GRB + NEO_KHZ800);

#define BT 4
#define BTN 2
#define Vert 6
#define Rouge 10
#define Blanc 11
#define Orange 12
#define Bleu 13

int Bleu_State = LOW;
int Orange_State = LOW;
int brightness = 0;

unsigned long prevTime_T1 = millis ();
unsigned long prevTime_T4 = millis ();

long interval_T1 = 1500;
long interval_T4 = 500;
    
void setup() {
  Serial.begin(9600);
  pinMode(PIN, OUTPUT);
  pinMode(Blanc, OUTPUT);
  pinMode(Rouge, OUTPUT);
  pinMode(Bleu, OUTPUT);
  pinMode(Vert, OUTPUT);
  pinMode(Orange, OUTPUT);
  pinMode(BTN, INPUT);
  pinMode(BT, INPUT_PULLUP);
  digitalWrite(Blanc, HIGH);
}

void loop() {
  
  unsigned long currentTime = millis();
  
   // Task 1: LED Orange clignote rapidement
  if (currentTime - prevTime_T4 > 500) {
    Orange_State = !Orange_State;
    digitalWrite(Orange, Orange_State);
    
    prevTime_T4 = currentTime;
  }
 
  // Task 2: LED bleu clignote lentement
  if (currentTime - prevTime_T1 > 1500) {
    Bleu_State = !Bleu_State;
    digitalWrite(Bleu, Bleu_State);
    
    prevTime_T1 = currentTime;
  }

  // Task 3: Neopixels s'allument en jaune
  strip.begin();
  strip.fill(strip.Color(255, 128, 0), 0, 2);// pixel color set to yellow
  strip.show();
  
  // Task 3bis: Neopixels commencent à vaciller
  strip.setBrightness(random(150,255)); // random brightness adjust for flicker effect
  strip.show();
  delay(random(0,200)); // random delay for flicker effect
  
  // Task 4: LED Vert s'allume avec BT
  if (digitalRead(BT)) {
    digitalWrite(Vert, LOW);
  } else {
    digitalWrite(Vert, HIGH);
    delay (300);
  }

  if (Serial.available()) {
    brightness = Serial.parseInt();
    if (brightness >=0 && brightness <=255) {
      analogWrite(Vert, brightness);
    }
  }
  
  // Task 5: LED Rouge s'allume avec BTN
  if (digitalRead(BTN) == HIGH){
    for (int i=0; i<4; i=i+1) {
      digitalWrite (Rouge, HIGH);
      delay (100);
      digitalWrite (Rouge, LOW);
      delay (100);
    }
  }
  else{
    digitalWrite(Rouge, LOW);
  } 
}

Je ne vois pas d'interaction dans ton code, juste une temporisation de presque une seconde lorsque tu appuies sur le bouton de la led rouge.
Peux-tu expliquer ce qui se passe, et qui n'est pas ce que tu attends ?

Au fait pourquoi ne pas mettre les deux boutons en INPUT_PULLUP ?

Bonsoir hypsi

Quel est le type de ton bouton bt, NF ou NO?

Tu initialise bt en PULLUP et tu le lis
if (digitalRead(BT))
C'est le cas pour un bouton NF.

Cordialement
jpbbricole

Bonjour Lesept,

Quand j'appuie sur un des boutons les LEDs bleue et orange arrêtent de clignoter le temps que la rouge ou la verte fassent leur travail. Ou bien il ne se passe rien quand on appuie sur un des boutons une fois ou deux avant que ça ne réagisse.

J'ai essayé différente version pour les boutons en essayant de supprimer cela. C'est pour ça que les deux boutons ne sont pas en INPUT_PULLUP. Mais ça n'a pas réglé mon problème.

Bonjour jpbbricole,

Quand je disais que je n'étais pas doué pour les langues étrangères... :stuck_out_tongue_winking_eye:
Je ne sais pas ce que veut dire NF ou NO. Je dessine mon circuit avec Tinkercad. DOnc le bouton présenté par défaut. Qui ressemble à ce que je veux utiliser quand je passerai à la réalisation physique.

Ca c'est bien le résultat que tu veux obtenir ?

Dans ton code lorsque tu appuis sur ton bouton if (digitalRead(BTN) == HIGH)
Tu ne fais rien pour arrêter le clignotement des autres LED.

La majorité de ton programme(ou le programme que tu as récupéré) exécute des actions en "parallèle", c'est à dire que chaque "Task" s'exécute indépendamment.
Enfin en partie car certaines "Task" contiennent des délais(fonction delay), qui casse complétement la logique des Task.

Je pense que dans un premier temps, il faudrait que tu rétablisse la logique multi-tâche.
Sauf si tu veux que ta LED rouge clignote 4 fois, puis plus rien jusqu'au relâchement du bouton.
Et encore cela n'empêche de garder la même logique tout au long du programme.

Donc peut tu redéfinir exactement et précisément ce que tu veux faire.
Par exemple "le temps que la rouge ou la verte fassent leur travail" n'est pas assez précis, car cela correspond à une multitude d'action possible.

NO = Normalement ouvert donc ferme le circuit quand pressé.
NF = Normalement fermé donc ouvre le circuit quand pressé.
image

Dans Thinkercad, si tu as opté pour le grand classique:
image
C'est un NO.

Donnes un lien sur ton montage.

A+
Cordialement
jpbbricole

Hello,

@jpbbricole vous avez du mal avec les BP NF ou NO, en général, ces BP n'ayant qu'un seul contact, qu'il soit NO ou NF, un PULL-UP ou un PULL-DOWN (à câbler en hard) ne fait pas de mal pour fixer les états et que l'entrée Arduino ne soit pas flottante dans un des 2 états du BP.

1/ Si vous avez 1 NO, qu'il est relié à 1 coté au + 5V, quand il est ouvert, l'entrée Arduino est flottante, il faut 1 PULLDOWN.
Idem pour 1 NC relié au 5V.

2/ 1 NO relié au 0V, il faut un PULLUP.
Idem pour 1 NC relié au 0V.

Comme il existe des PULLUP interne, autant utilisé le cas 2/ avec 1 NO ou NC

Par contre là

Il manque "(digitalRead(BT)==LOW)" ... ou HIGH selon ton BT et ce que tu en attend.

Bref il manque la condition.

Bonjour hypsi

J'ai analysé ton programme, dans l'ensemble, il est assez bien fait. Mais, mis à part de mettre tes boutons en PULLUP, il y avait une petite erreur dans le test du bouton BT:
Tu as écrit
if (digitalRead(BT == LOW)) {
tu dois écrire
if (digitalRead(BT) == LOW) {
C'est le genre d'erreur qui empoisonne un programme :wink:

Ton programme corrigé (je te laisse jouer au jeux des 7 différences) :wink::

#include <Adafruit_NeoPixel.h>
#define PIN 9
#define NUM_LEDS 2

// Parameter 1 = number of pixels in strip
// Parameter 2 = pin number (most are valid)
// Parameter 3 = pixel type flags, add together as needed:
//   NEO_KHZ800  800 KHz bitstream (most NeoPixel products w/WS2812 LEDs)
//   NEO_KHZ400  400 KHz (classic 'v1' (not v2) FLORA pixels, WS2811 drivers)
//   NEO_GRB     Pixels are wired for GRB bitstream (most NeoPixel products)
//   NEO_RGB     Pixels are wired for RGB bitstream (v1 FLORA pixels, not v2)
Adafruit_NeoPixel strip = Adafruit_NeoPixel(NUM_LEDS, PIN, NEO_GRB + NEO_KHZ800);

#define BT 4
#define BTN 2
#define Vert 6
#define Rouge 10
#define Blanc 11
#define Orange 12
#define Bleu 13

int Bleu_State = LOW;
int Orange_State = LOW;
int brightness = 0;

unsigned long prevTime_T1 = millis ();
unsigned long prevTime_T4 = millis ();

long interval_T1 = 1500;
long interval_T4 = 500;

void setup() {
	Serial.begin(9600);
	pinMode(PIN, OUTPUT);
	pinMode(Blanc, OUTPUT);
	pinMode(Rouge, OUTPUT);
	pinMode(Bleu, OUTPUT);
	pinMode(Vert, OUTPUT);
	pinMode(Orange, OUTPUT);
	pinMode(BTN, INPUT_PULLUP);
	pinMode(BT, INPUT_PULLUP);
	digitalWrite(Blanc, HIGH);
}

void loop() {
	
	unsigned long currentTime = millis();
	
	// Task 1: LED Orange clignote rapidement
	if (currentTime - prevTime_T4 > 500) {
		Orange_State = !Orange_State;
		digitalWrite(Orange, Orange_State);
		
		prevTime_T4 = currentTime;
	}
	
	// Task 2: LED bleu clignote lentement
	if (currentTime - prevTime_T1 > 1500) {
		Bleu_State = !Bleu_State;
		digitalWrite(Bleu, Bleu_State);
		
		prevTime_T1 = currentTime;
	}

	// Task 3: Neopixels s'allument en jaune
	strip.begin();
	strip.fill(strip.Color(255, 128, 0), 0, 2);// pixel color set to yellow
	strip.show();
	
	// Task 3bis: Neopixels commencent à vaciller
	strip.setBrightness(random(150,255)); // random brightness adjust for flicker effect
	strip.show();
	delay(random(0,200)); // random delay for flicker effect
	
	// Task 4: LED Vert s'allume avec BT
	//if (digitalRead(BT == LOW)) {
	if (digitalRead(BT) == LOW) {
		Serial.println("BT");
		digitalWrite(Vert, LOW);
		} else {
		digitalWrite(Vert, HIGH);
		delay (300);
	}

	if (Serial.available()) {
		brightness = Serial.parseInt();
		if (brightness >=0 && brightness <=255) {
			analogWrite(Vert, brightness);
		}
	}
	
	// Task 5: LED Rouge s'allume avec BTN
	if (digitalRead(BTN) == LOW){
		Serial.println("BTN");
		for (int i=0; i<4; i=i+1) {
			digitalWrite (Rouge, HIGH);
			delay (100);
			digitalWrite (Rouge, LOW);
			delay (100);
		}
	}
	else{
		digitalWrite(Rouge, LOW);
	}
}

A+
Cordialement
jpbbricole

Bonjour jef59

Euh non!
Qu'est ce qui te faire dire ça?

Il ne manque pas la condition, elle est optionnelle, écrit ainsi ça correspond à:

if (digitalRead(BTN) == true)
if (digitalRead(BT) == HIGH)

Ca fonctionne.

Cordialement
jpbbricole

Je pense que le point clé est là. Hypsi dit :

On a l'impression que tout doit en effet tourner 'en parallèle'. Or comme dit @terwal une partie du code est bloquante, donc ça ne fonctionne pas en même temps.

@hypsi : il faut que tu dises exactement ce que tu veux obtenir, sinon c'est pas le jeu des 7 différences, c'est le ni oui ni non...

Voici le lien : Login | Tinkercad

Bonjour terwal,

Tu as raison, j'aurais dû commencer par là.
Je veux que toutes les tâches se fassent en paralllèle en effet. Je veux que les LEDs bleue et orange continuent à clignoter quand j'appuie sur un des boutons. De plus je veux aussi que la LED rouge clignote quatre fois rapidement lorsqu'on appuie sur son bouton puis s'éteigne jusqu'au prochain appui. Je souhaite également que la LED verte s'allume une seule fois puis fade out quand on appuie sur son bouton.
Quand je joue sur Tinkercad, j'ai l'impression que lorsque j'appuie sur les boutons, parfois je n'ai pas de réponse de la LED correspondante, ou bien parfois les LEDs bleue et orange arrêtent de clignoter pendant un moment (le temps de l'exécution de la commande du bouton sur lequel j'ai appuyé). Mais peut-être que c'est juste une limite visuelle de Tinkercad.

Bonjour jef59,

J'ai corrigé la condition manquante. Merci.

Je me suis expliqué, j'espère un peu mieux, dans une de mes réponses. Oui je veux tout faire en parallèle. Je comprends que dès qu'on met un delay, il y a blocage. Je ne sais pas encore comment faire pour contourner ce problème et que tout le reste continue à fonctionner.

J'ai fait un petit tuto (en anglais) ici :

Regarde le, et si tu as des questions, pose-les sur ce fil de discussion : je pourrai t'aider.

L'idée est de créer une fonction par tâche et d'utiliser millis() comme tu le fais déjà un peu dans ton code.

Les tâches 3 et 3bis n'en font qu'une seule qu'il faudra simplifier :

  • mettre le strip.begin() dans le setup
  • task 3 devient :
  // Task 3: Neopixels s'allument en jaune
  strip.fill(strip.Color(255, 128, 0), 0, 2);// pixel color set to yellow
  strip.setBrightness(random(150,255)); // random brightness adjust for flicker effect
  strip.show();
  delay(random(0,200)); // random delay for flicker effect

A mettre ensuite dans une fonction pour exécution sans le delay.

Merci lesept. Je vais regarder ça.

Tu ne parles pas de remplacer "ce" delay par une fonction millis(), n'est-ce pas ?

J'ai lu ton tuto et cela semble assez claire (ton exemple est très bon) mais je ne suis pas certain de voir comment utiliser plus la fonction millis() dans mon cas. Est-ce que je peux l'utiliser avec un bouton ? Et si oui, comment ? Merci d'avance.

Si...

Pour les tâches 4 et 5 tu as en effet à la fois le bouton et un delay. Il faut réfléchir à la manière d'utiliser les deux. De toutes façons, je pense que tu peux aussi bien ôter ce delay dans la tâche 4, il ne sert à rien.

Pour la tâche 4 : dans ta fonction, il faut lire le bouton et détecter un changement de son état (passage LOW - HOGH ou l'inverse). Tu peux ajouter un delay(30) pour ne pas être gêné par les rebonds, c'est si court que tu peux utiliser delay ici. Ensuite tu changes l'état de la led, simplement en lui attribuant le même état que le bouton.

En fait, je voulais faire un effet de fade down et non de flash d'ou le delay. Je ne vois pas comment incorporer la fonction FADE dans une fonction conditionnelle IF ELSE.