(RESOLU)Petits problèmes avec mes leds

Bonjour,

Mon problème :

J'allume, j'éteins et je fais clignoter des leds selon l'état de différents relais. Tout cela est piloté par une MEGA.

Mes leds ont un comportement bizarre : j'arrive à les allumer, les éteindre une par une ou ensemble mais si j'en fait clignoter une, quand elle s'allume, les autres s'éteignent et vice versa.

Mon code complet compile bien et si je code une par une les leds fonctionnent également.

J'utilise les instructions suivantes :
digitalWrite(eclPP, LOW); digitalWrite(ledEclPP, HIGH); pour allumer et éteindre
ou

if (millis() - delai1 > interval5) {
    digitalWrite(ledChauffage, digitalRead(ledChauffage) == LOW ? HIGH : LOW);
    delai1 = millis();
  }

pour le clignotement.

Les GND sont reliés et l'alimentation pour les leds est une alim indépendante de 5V 2A.

J'ai mis le schéma en pièce jointe car je n'arrive pas à l'inclure dans le message et pour le simplifier je n'ai mis que trois leds mais il y en a 10 au total.

Merci par avance de votre aide

Pour le schéma (c'est génial, on en a un, c'est rare), pas besoin de transistor car il n'y a que 2mA par diode environ. Avec le même programme on peut mettre la led et sa résistance série entre la sortie et la masse. On gagne un transistor et la résistance de base.

digitalRead(ledChauffage) == LOW ? HIGH : LOWpeut aussi s'écrire!digitalRead(ledChauffage)cela fait exactement la même chose en moins de code (on met l'inverse de ce qu'il y a).

Par contre pour le problème de clignotement qui éteint les copines, seul le code complet me permet de dire pourquoi.

cela fait exactement la même chose en moins de code (on met l'inverse de ce qu'il y a).

ce n’est juste pas propre de faire cela car dépend de votre connaissance des valeurs HIGH et LOW et des promotions automatiques de bool en entier.. vaut mieux encourager l’usage des bonnes pratiques, donc moi je trouve que c’est très bien comme c’est écrit.

Pas propre?

D'abord voici un extrait du fichier Arduino.h qui me sert de référence:

#define HIGH 0x1
#define LOW  0x0
void digitalWrite(uint8_t pin, uint8_t val);
int digitalRead(uint8_t pin);

Dans la page de référence de digitalRead(); il y a un exemple duquel j'extrais deux lignes:

int ledPin = 13;  // LED connected to digital pin 13
  val = digitalRead(inPin);   // read the input pin

dans la première ledPin est défini comme un entier signé 16 bits, dans la deuxième, il prend la place attendue d'un paramètre entier non signé 8 bits. Il devraient écrire:

int ledPin = 13;  // LED connected to digital pin 13
  val = digitalRead((uint8_t)inPin);   // read the input pin

Cela aurait été plus propre car cela montre la tansformation qui est faite.

Maintenant quand je vois:digitalWrite(ledChauffage, digitalRead(ledChauffage) == LOW ? HIGH : LOW);, je me dis digitalRead retourne un entier signé (16 bits). Il faut donc considérer que LOW est aussi un entier signé (16 bits) vu que l'on compare ces deux valeurs. Mais alors on va passer à digitalWrite un entier signé (16 bits), lui qui attend un entier 8 bis non signé. Cela ne va pas du tout!
Il faut donc écrire:digitalWrite(ledChauffage, digitalRead(ledChauffage) == (int)LOW ? (uint8_t)HIGH : (uint8_t)LOW);C'est propre, mais est-ce bien utile?

Merci pour vos réponses.

J’avais essayé, avant de poster, une autre écriture de ce genre pour la partie clignotement :

If (ledChauffage == HIGH) {
etatLed = HIGH};
else {
etatLed  = LOW;}
digitalWrite(ledChauffage, etatLed);

Cela n’a aucune incidence dans mon cas. Les différents codes testés ont le même résultat (je précise bien dans mon cas de code uniquement). Surement que dans des codes plus complexes cela doit avoir une influence certaine qui m’échappe pour le moment.

Demain je ferais d’autres tests afin de cerner un peu mieux mon problème.

Encore merci pour vos réponses

@ETG59, cette écriture est aussi valide, juste plus verbeuse.

@vileroi, je pense que vous savez très bien ce que je veux dire. Ce que vous faites est fonctionnel mais pas propre parce que dépendant de votre connaissance des valeurs associées à HIGH et LOW qui sont arbitraires (même si attendues) et non fortement typées aujourd’hui. Sinon pour votre explication, le promotion est définie au niveau de la norme donc considérée comme propre. (Et HIGH et LOW étant pour le moment issue d’un define ils sont effectivement des int lorsque injectés dans le code, donc c’est sans promotion que l’on peut comparer le résultat de digitalRead avec HIGH ou LOW)

Pas propre parce que le futur vous réserve peut être des surprise (warnings/erreurs de compilation en perspectives s’ils vont vers un type énuméré). N’oubliez pas qu’on est avec un compilateur C++ et non pas C. true et false font partie intégrante du langage et sont typés.

Cf la discussion ici à ce sujet et le fait que ce qu’ils ont en tête casserait du code, et le plantage de ce code qui ressemble à ce que vous suggérez

digitalWrite(13, !digitalRead(13));  // toggle pin 13

avec le compilateur qui dirait

toggle:2:36: error: cannot convert 'bool' to 'PinStatus' for argument '2' to 'void digitalWrite(pin_size_t, PinStatus)'

A mon avis ils ne feront pas le changement sans ajustements mais ça fait partie des raisons qui poussent à essayer de rester "propre" quand le coût est insignifiant. Ça aide aussi à la maintenance.
—-

Bref mon point était simplement de dire que je ne trouve pas utilie d’encourager une écriture un peu absconse et qui est discutable sémantiquement quand ce qui est écrit est parfaitement lisible. Vous avez bien sûr toute liberté de penser différemment.

Je crois que tu me prêtes des intentions que je n'ai pas. Je suis issu de la programmation Assembleur qui n'est absolument pas typé, puis Pascal et Delphi qui sont des langages fortement typés, et j'en ai gardé des traces. Avec le Pascal de l'époque un int8_t est parfaitement incompatible avec un uint8_t ou avec un booléen. Par exempledigitalRead(ledChauffage) == LOW ? HIGH : LOWne passerait pas car:
-HIGH et LOW ne sont pas typés

  • digitalRead retourne un int qui serait incompatible avec un autre type

Du coup, avec les C qui sont peu typés, je n'ai pas tout compris ce qui se passe sur la possibilité de passer HIGH en enum. Pour moi c'est un peu la pagaille, j'ai l'impression que tous les types entiers sont "compatibles", uint8_t serait compatible avec les enums, les booléens sont compatibles avec les entiers, mais les booléens ne seraient pas compatibles avec les enums.
La solution qui me reste est de faire des essais et de voir ce qui marche et ce qui ne marche pas.

Évidemment, je suis à la merci d'un changement, mais je pourrais m'adapter. Mais il y a plein d'autres endroits ou je suis a leur merci. Si ils décidaient, comme je le souhaite, que millis() s'incrémente toutes les millisecondes, j'aurais pas mal d'ajustements à faire pour une autre bibliothèque qui utilise le timer 0 pour avoir 4 horloges différentes. J'ai aussi un programme qui utilise le timer 1 qui est à la merci d'un changement sur tone() qui pour l'instant utilise le timer 2. Si "ils" décident de descendre la fréquence limite de 31Hz en utilisant le timer 1, il faudra que je repense aussi pas mal de choses.

Oui j’ai bien compris que vous venez de l’assembleur et transposez au C - qui est extrêmement permissif - certaines approches. La différence c’est qu’on est en C++ et pas en C et donc qu’il y a des règles plus contraignantes.

Pour un type énuméré en C il était compatible avec les règles de promotion des entiers. En C++ on peut forcer le type sous jacent de l’énum pour représenter la valeur mais c’est un nouveau type à part entière et le respect de ce nouveau type va venir vous jouer des tours comme dans l’exemple cité ci dessus où ça ne compile plus.

La où vous avez peut être raté un truc c’est quand vous dites

HIGH et LOW ne sont pas typés

le langage dit que ce sont des int par défaut et qu’ensuite les règles de promotions sont appliquées.

digitalRead() retourne un int et donc c’est compatible avec la comparaison avec un int sans même faire de promotion. C’est le même type.

Ensuite HIGH ou LOW étant des constantes littérale si elles sont utilisées seules en paramètre (pas dans un calcul mathématique) elles seront promues à la compilation directement à mon avis - en paramètre d’une fonction comme digitalWrite(HIGH) je pense que le compilateur calculera directement 1 sur 8 bit pour le passer à la fonction et ne génèrera pas un calcul avec le poids faible d’un 1 sur deux octets.

Le point sémantique donc c’est que ces HIGH et LOW ont été définis comme abstraction de la valeur de tension de la pin par les concepteurs. Respecter leur usage permet de se prémunir donc contre les évolutions futures.

Cela dit - ce que vous proposez est fonctionnel et nombre d’adeptes de l’assembleur ou du C pur sont tout à fait à l’aise avec cette écriture qui est fonctionnelle et donnera le résultat attendu sans doute pour de longues années.

Mon propos portait surtout sur l’aspect pédagogique - doit on conseiller un petit hack qui ne fait sans doute rien gagner une fois compilé aux dépens d’une écriture un peu plus verbeuse mais syntaxiquement et sémantiquement correcte ? Je pense que non.

@J-M-L
AMHA HIGH et LOW ne sont pas plus propre que 1 et 0.

HIGH et LOW sont fixés en posant l'affirmation que la logique est "positive", c'est à dire que le niveau correspondant à "VRAI" est le niveau haut ce qui est totalement arbitraire et qui est faux pour le cas de l'I2C.

En I2C la valeur "VRAI" est affectée au niveau bas, on devrait donc écrire que le niveau 0V est HIGH et le niveau LOW est Vcc quand on manipule l'I2C.

Et rien ne prouve, même si c'est hautement improbable, qu'on n'aura pas un jour un microcontroleur fonctionnant avec la masse au plus.
Pour étayer cette "hypothèse improbable" les circuits logiques les plus rapides sont en technologie ECL. Cette techno utilise des paires différentielles de transistors bipolaires et vraiment beaucoup de mA. Quand on veut la meilleure immunité au bruit on utilise ces circuits alimentés avec Vcc = - 0 V et Vee à l'alim - 5V .
Si 0V sera toujours supérieur à - 5V, si on ne change pas la "norme" il n'en restera pas moins vrai que HIGH sera la masse et LOW l'alimentation ce qui ne manquera pas de semer la confusion.

On aura bon tourner le problème dans tous les sens on ne trouvera jamais de solution universelle en dehors de l'abstaction des mathématiques pures. La norme est fortement tributaire des choix technologiques faits pendant la conception du microcontrôleur.

Conclusion : l'acquisition d'une connaissance minimale du fonctionnement des microcontrôleurs ne peut pas être évitée.

A la limite j'aurai plus facilement accepté que digitalX utilise soit VRAI soit FAUX, ce qui me semble plus cohérent avec le fonctionnement d'un microcontroleur qui n'est qu'un assemblage de circuits logiques -> ah j'ai écrit circuits logiques :grin:

A la limite j'aurai plus facilement accepté que digitalX utilise soit VRAI soit FAUX, ce qui me semble plus cohérent avec le fonctionnement d'un microcontroleur qui n'est qu'un assemblage de circuits logiques -> ah j'ai écrit circuits logiques :grin:

Oui, ils auraient pu faire ce choix. Ils auraient pu dans ce cas définir

#define HIGH true
#define LOW  false

mais ils ne l'ont pas fait. La raison sans doute c'est qu'en C++ true n'est pas juste le chiffre 1 et false 0, ce sont des constantes typées du type "valeur de vérité", un type à part entière alors qu'en C ce type n'existe pas. Ce sont les règles de promotion implicite qui font que vous pouvez les "voir" comme ces valeurs.

AMHA HIGH et LOW ne sont pas plus propre que 1 et 0.

techniquement vous avez raison c'est la même chose. Ce que j'essaye d'exprimer, peut-être mal, est sémantique et pédagogique. Je trouve que lire digitalWrite(ledChauffage, digitalRead(ledChauffage) == LOW ? HIGH : LOW);est beaucoup mieux que digitalWrite(ledChauffage, !digitalRead(ledChauffage));

Comme exprimé plus haut, si d'aventure l'équipe Arduino adopte pour les AVR les types énumérés et nouvelles signature des fonctions pinMode(), digitalWrite(), digitalRead() qu'ils ont proposés:

 typedef enum {
  LOW     = 0,
  HIGH    = 1,
  CHANGE  = 2,
  FALLING = 3,
  RISING  = 4,
} PinStatus;

typedef enum {
  INPUT           = 0x0,
  OUTPUT          = 0x1,
  INPUT_PULLUP    = 0x2,
  INPUT_PULLDOWN  = 0x3,
} PinMode;

void pinMode(pin_size_t pinNumber, PinMode pinMode);
void digitalWrite(pin_size_t pinNumber, PinStatus status);
PinStatus digitalRead(pin_size_t pinNumber);

Ça change tout en C++: le type sous jacent de HIGH et LOW ne sera plus un nombre sur lequel les promotions sont applicables, l'usage de NOT (!) sur ce type n'est pas défini à moins de surcharger l'opérateur.

S'ils venaient à faire cette modification, l'écriture avec l'opérateur ternaire restera correcte alors que le petit "hack" en operation booléenne arrêtera la compilation.

Ça cassera pas mal de code et donc je pense que c'est pour cela qu'ils ne l'ont pas encore fait.

Il n'y a pas qu'Arduino.h, il faut aussi regarder le code :

    // digitalWrite
 if (val == LOW) {
 *out &= ~bit;
 } else {
 *out |= bit;
 }
    // digitalRead
 if (*portInputRegister(port) & bit) return HIGH;
 return LOW;

digitalRead() retourne un int et donc c'est compatible avec la comparaison avec un int sans même faire de promotion. C'est le même type.

+1

A mon avis ils ne feront pas le changement sans ajustements mais ça fait partie des raisons qui poussent à essayer de rester "propre" quand le coût est insignifiant. Ça aide aussi à la maintenance.

Il faut espérer.

EGT59:
Les GND sont reliés et l'alimentation pour les leds est une alim indépendante de 5V 2A.

J'ai mis le schéma en pièce jointe car je n'arrive pas à l'inclure dans le message et pour le simplifier je n'ai mis que trois leds mais il y en a 10 au total.

Merci par avance de votre aide

Désolé @EGT59 - on a un peu détourné votre post.

Pour vérifier que ce n'est pas un souci dans votre code (puisque vous n'avez pas tout posté) si vous conservez votre montage tel quel et que vous utilisez le code de blink without delay sur une des pin pilotant une de vos LEDs, voyez vous le même comportement ?

const int ledPin =  22; // UNE DE VOS PINS
int ledState = LOW;
unsigned long previousMillis = 0;
const unsigned long interval = 1000ul;

void setup() {
  pinMode(ledPin, OUTPUT);
}

void loop() {
  unsigned long currentMillis = millis();

  if (currentMillis - previousMillis >= interval) {
    previousMillis = currentMillis;
    if (ledState == LOW) {
      ledState = HIGH;
    } else {
      ledState = LOW;
    }
    digitalWrite(ledPin, ledState);
  }
}

(il faudra peut-être mettre toutes les autres pins utilisées en OUTPUT aussi pour être cohérent)

bon j'ai trouvé l'erreur. Le code n'est pas en cause mais mon circuit led oui.

Je m'explique : comme mes leds étaient trop lumineuses, j'ai ajouté une résistance de 10K (R10) sur le + des leds et c'est ça qui met le b....l

Je l'enlève et ca fonctionne. Mes leds clignotent sans intervenir sur les autres.

Par contre l'intensité lumineuse est beaucoup trop forte, ca pique aux yeux

petit cachotier :slight_smile:

Par contre l'intensité lumineuse est beaucoup trop forte, ca pique aux yeux

augmentez les 150Ω

oui j'ai commencé à dessouder ::slight_smile:

je vais tester jusqu'à obtenir un éclairement satisfaisant.

Merci

This topic was automatically closed 120 days after the last reply. New replies are no longer allowed.