Controler plusieurs Leds avec plusieurs boutons poussoirs en mode ON/OFF

Bonjour,

Pour ma part, j'ai compris la philosophie, sauf pourquoi il fallait éviter de mettre les nombres magiques
"Les sept nombres magiques vérifiés expérimentalement sont : 2, 8, 20, 28, 50, 82, 126a (suite A018226 de l'OEIS)."

Autres remarque/question:

D'une part, il y a dans le setup

const int ledPin[] = {10, 11, 12, 13, A0, A1, A2, A3}; // Tableau des pin des LED
//const int ledNombre = sizeof(ledPin) / sizeof(ledPin[0]); // Nombre de LED = nombre d'éléments du tableau calculé à partir du nombre d'octets occupés par l

Et d'autre part, vous écrivez:

Mais il me semble que les 8 élements du tableau sont
ledPin[0]
...
ledPin[7]
et
ledNombre = 8 (de 1 à 8)

Est-ce que je me trompe?

;)

L'expression "nombre magique" est apparue dans le domaine de la programmation dans les années 1960, notamment dans les langages de bas niveau, pour décrire des valeurs numériques qui semblaient surgir "magiquement" dans le code, sans explication apparente.

Ces valeurs étaient souvent utilisées dans les premières étapes de l'informatique pour des configurations matérielles spécifiques, des adresses mémoire, ou des paramètres système, et les programmeurs qui lisaient le code sans connaître la signification de ces nombres pouvaient les percevoir comme des "incantations" mystérieuses.

L'expression "nombre magique" en programmation de nos jours désigne une valeur littérale, souvent numérique, qui apparaît dans le code sans explication ni contexte. Elle est directement insérée dans le code pour que celui-ci fonctionne, mais sa signification ou son origine n'est pas apparente, ce qui rend le code difficile à lire et à maintenir.

L'absence de clarté sur l'origine de ce nombre crée un risque d'erreur si des changements futurs sont effectués (par exemple, ajouter ou retirer une LED ou un bouton dans le cas présent). Pour éviter cela, il est recommandé d'utiliser des constantes nommées et calculées automatiquement si possible, qui rendent l’intention du code explicite et facilitent les modifications ultérieures.

C'est devenu une expression un peu péjorative pour désigner des valeurs non documentées dans le code, qu’il est préférable de remplacer par des constantes explicites pour améliorer la lisibilité et la maintenance du code.

Je me réponds à moi même avec un exemple

// For selon Jef59
int inPin[]={1,2,3,4,5,6,7,8};//8 valeurs
const int ledNombre = sizeof(inPin) / sizeof(inPin[0]);

// --------------------------------------------------------------
void setup(){
  
  Serial.begin(115200);

  Serial.print("ledNombre = ");
  Serial.println(ledNombre);

  for (int i=0; i<ledNombre; i++){
    //pinMode(inPin[i], INPUT_PULLUP);

    Serial.print("for i = ");
    Serial.print(i);
    Serial.print(" / inPin[i] = ");
    Serial.println(inPin[i]);
    
    
  }

  Serial.println("_______________________");

}
// --------------------------------------------------------------
void loop(){
}

Le but est de voir quelle valeur ou "espace mémoire d'un tableau" va consulter la boucle "for" en commencant par 0.

A voir dans le moniteur série.

0 c'est la première valeur du tableau, et pour un tableau de 8 valeurs, la dernière valeur du tableau c'est celle en position 8-1.

Je n'emploie surement pas les bons termes.

Edit: j'ai amélioré le sketch de ma démo

Sur le moniteur série, je lis

ledNombre = 8
for i = 0 / inPin[i] = 1
for i = 1 / inPin[i] = 2
for i = 2 / inPin[i] = 3
for i = 3 / inPin[i] = 4
for i = 4 / inPin[i] = 5
for i = 5 / inPin[i] = 6
for i = 6 / inPin[i] = 7
for i = 7 / inPin[i] = 8

J'ai donc 8 led numérotée de 0 à 7, et je dois faire une boucle

for (int i=0; i<ledNombre; i++)

Là est l'erreur de @vincentm0911 je crois.

oui les indices d'un tableau en C ou C++ commencent toujours à 0, donc pour un tableau de N éléments, les indices vont de 0 à N-1

Lire (ou pire écrire) en dehors de la mémoire réservée pour le tableau déclenche ce que l'on appelle une "undefined behavior" pour le compilateur. Le code peut faire n'importe quoi ensuite car on a rompu une promesse implicite faite au compilateur qu'on n'irait pas faire des choses en dehors de la mémoire prévue.

Bonjour vincentm0911

L'étape suivante sera de passer aux LED adressables:

Ca simplifie le câblage et ça décuple les possibilités.

Une petite démonstration:

Le programme:

/*
    Name:       AF_Controle_8_LED_8_boutons_E.ino
    Created:	11.11.2024
    Author:     jpbbricole

	Palette:	https://www.rapidtables.com/web/color/RGB_Color.html
*/
#include <Adafruit_NeoPixel.h>

//------------------------------------- Définition des interfaces, boutons
struct interfacesDef
{
	const int btnPin; // Pin du bouton
	unsigned long ledColor;
};
                        //   Rouge vif      Bleu vif      Vert citron     Orange
interfacesDef intf[] =	{{2, 0xFF0000}, {3, 0x0000FF}, {4, 0xADFF2F}, {5, 0xFFA500},
						//  Bleu ciel      Gris moyen       Rose      Rouge foncé
						{6, 0x87CEEB}, {7, 0x808080}, {8, 0xFFC0CB}, {9, 0x8B0000}}; // Initialisation des boutons
const int intfNombre = sizeof(intf) / sizeof(intf[0]); // Nombre d'interfaces

const int ledPin = 12;             // Pin de données du strip WS2812
const int ledNombre = intfNombre;    // Nombre de LEDs dans le strip (une par bouton)
const int ledLuminosite = 150; // Luminosité générale

Adafruit_NeoPixel strip = Adafruit_NeoPixel(ledNombre, ledPin, NEO_GRB + NEO_KHZ800);

int timeDelay = 20; // Delay pour éviter les rebonds du bouton poussoir

void setup()
{
	strip.begin(); // Initialisation du strip WS2812
	strip.show(); // Éteindre toutes les LEDs au démarrage
	strip.setBrightness(ledLuminosite); // Régler la luminosité (0-255)

	//--------------------------------- Initialisation des boutons
	for (int i = 0; i < intfNombre; i++)
	{
		pinMode(intf[i].btnPin, INPUT_PULLUP); // Pins boutons en entrée avec pull-up
	}
}

void loop()
{
	for (int i = 0; i < intfNombre; i++)
	{
		if (digitalRead(intf[i].btnPin) == LOW)
		{
			ledAllumer(i); // Allume la LED correspondante
		}
	}
}

void ledAllumer(int ledNum)
{
	for (int i = 0; i < intfNombre; i++)
	{
		if (i == ledNum) // Si c'est la LED sélectionnée
		{
			//strip.setPixelColor(i, strip.Color(255, 0, 0)); // Allume en rouge la LED sélectionnée
			strip.setPixelColor(i, intf[i].ledColor); // Allume la LED sélectionnée
		}
		else
		{
			strip.setPixelColor(i, strip.Color(0, 0, 0)); // Éteint les autres LEDs
		}
	}
	
	strip.show();  // Met à jour les LEDs pour afficher les changements
	delay(timeDelay);
}

A+
Cordialement
jpbbricole

Ok, par inadvertance, je crois que c'est un peu le cas de @vincentm0911

la bibliothèque Adafruit utilise uint32_t (unsigned long) pour représenter les couleurs. Ce n'est pas un "drame" parce qu'il y a une promotion implicite dans la représentation du uint32_t quand on passe un long et qu'une valeur non signée est attendue, mais c'est mieux de prendre le bon type.

Bonsoir J-M-L

Oh que oui!

Merci!

Bonne soirée
jpbbricole

Pour ajouter un détaille à l'explication de @J-M-L, on peut trouver un intérêt de centraliser la valeur de fonctionnement dans des constantes plutôt que des valeurs directement dans des formules ou instructions de contrôle bien documenté.
Car il y a de forte chance que si tu doit modifier ton programme, tu oubli de changer ces valeurs, alors que si celle-ci sont en début de programme, il a plus de chance de ne pas la louper.

oui et encore mieux si on peut la calculer.

par exemple au lieu de faire

const int btnPin[] = {2, 3, 4, 5, 6, 7, 8, 9};         // Tableau des pin des boutons
const int ledPin[] = {10, 11, 12, 13, A0, A1, A2, A3}; // Tableau des pin des LED

et utiliser ensuite 8 dans le code parce que l'on sait qu'il y a 8 éléments dans les tableaux, on pourrait effectivement déclarer des constantes qui valent 8

const byte nombreDeBoutons = 8;
const byte nombreDeLeds = 8;
const int btnPin[nombreDeBoutons] = {2, 3, 4, 5, 6, 7, 8, 9};         // Tableau des pin des boutons
const int ledPin[nombreDeLeds] = {10, 11, 12, 13, A0, A1, A2, A3};    // Tableau des pin des LED

Le compilateur mettra un message si le compte n'y est pas.

Mais le mieux est de calculer cela dynamiquement et cerise sur le gâteau vérifier la cohérence (on doit avoir autant de LEDs que de boutons)

// À CONFIGURER
const byte btnPin[] = {2, 3, 4, 5, 6, 7, 8, 9};         // Tableau des pin des boutons
const byte ledPin[] = {10, 11, 12, 13, A0, A1, A2, A3}; // Tableau des pin des LED

// TAILLES CALCULÉES À LA COMPILATION
const byte nombreDeBoutons = sizeof btnPin / sizeof *btnPin;
const byte nombreDeLeds    = sizeof ledPin / sizeof *ledPin;

//  VÉRIFICATION DE CONFORMITÉ À LA COMPILATION
static_assert(nombreDeBoutons == nombreDeLeds, "Le nombre de boutons et de LEDs doit être le même.");

Bonsoir,
J'ai eu une carte UNO à prêter pour tester mon programme et j'ai un soucis :slight_smile:
Il semblerait que les PIN 10 11 12 et 13 ne soit pas reconnues comme sorties.
J'ai testé du coup ton programme JPBBRICOLE mais même celui là ne fonctionne pas
Les leds sur A0 A1 A2 A3 s'allument bien, de même, si je branche des leds sur A4 et A5 mais si je déclare sur les sorties 10 à 13 rien ne se passe.
J'ai juste la led L de la carte qui s'allume au lieu de le pin 13.
Je dois avoir un loupé un paramétrage dans IDE mais je ne trouve pas la solution .
Merci de votre aide

Postez le code et le montage utilisé pour cela

Je me réponds à moi même : je pensais avoir trouvé la solution en faisant une mise à jour de la carte sur MBLOCK mais maintenant ce sont les pin A0 à A3 qui ne s'allument pas ...
Je n'y comprends rien.
C'est comme si la carte ne voulait pas allumer plus de 4 leds !!

J'ai TROUVE !!!!!!
J' utilise une vieille carte de prototypage (modèle des années 70 je pense :slight_smile: )
Et sur ma plaque, la ligne de la masse est séparée en 2 au milieu au niveau d'une lettre W.
J'avais testé plusieurs plaques (3 au total) et j'avais forcément le même problème :slight_smile:

non ce ne sont pas forcément des vieilles. En effet de nombreuses breadboard ont cette coupure.

on rajoutera des petits jumpers pour assurer la continuité