Faire clignoter une LED dans la fonction setup() avec millis

Bonjour

J’ai fait une petite classe en C++ pour gérer les LED. Ca fonctionne niquel pour allumer ou etindre une led, maintenant j’aimerais faire une fonction dans cette classe pour faire clignoter une led au début de la fonction setup() afin d’indiquer que le setup débute. Je ne veux pas utiliser delay pour éviter que ce clignotement soit bloquant.
Le soucis je ne sais pas trop comment faire pour utiliser millis dans le setup tous les exemlpes que je vois sont dans la fonction loop(), est-ce possible de le faire ou pas dans la fonction setup()?

Mon but est de faire clignoter ma led pendant 5s environ (sans bloquer la suite de l’execution du code) au debut du setup() (mon setup prend enviton 15secondes à se dérouler)

est-ce possible de le faire ou pas dans la fonction setup()?

n'as tu pas essayé ?

millis() commençant à compter dès la mise sous tension , est utilisable dans setup()

J'ai essayé oui mais sans succès voici ce quej'ai fait au debut de mon setup();

Led led_rouge(LED_ROUGE)
void setup() {
  SerialUSB.begin(115200);
  while (!SerialUSB)
    delay(10);

  unsigned long current_millis = millis(); 
  led_rouge.setup();
  led_rouge.clignote(current_millis, 200);

  //reste du code qui prendr eentre 15-20s
}

void loop(){
}

Dans mon fichier de classe voici la fonction clignote

void Led::clignote(unsigned long current_millis, int interval){
  if(current_millis - last_millis_update > interval) {
    last_millis_update = current_millis;   
       
    etat = !etat;
    rafraichir(); 
  }
}

rafraichir est une simple fonction qui fait le digitalWrite et last_millis_update est initialisé à 0 dans le constructeur de la classe. Et etat soit 0 ou 1 en ofnction de HIGH ou LOW

Le soucis c'est que mon programme ne passe qu'une fois dans ma fonction clignote en faite, ma led s'allume et reste allumé elle ne clignote pas.
Je doit faire quelque chose de mal avec current_millis je pense

Non, tu n'as rien fait de mal, ta fonction et juste très mal nommée.
Tu l'appelles clignote(), alors qu'elle devrait s'appeler attendre_et_inverser_etat()
Parce ce que c'est exactement ce qu'elle fait (relis ton code)
Donc c'est normal qu'elle ne clignote pas, puis que tu l'appelle 1 fois !
Rhaa là là, tu n'as pas tésté ta classe ... :grin:

Cela dit, ton problème est un poil plus compliqué.
Tu veux gérer des intervalles de temps, dans ta classe (jusque là quand tu appelles une méthode de ta classe, c'est ton code à toi qui est exécuté)
PENDANT qu'un autre code (ce qu'il y a dans le setup, ou autre) se déroule, sans le bloquer. !
Ca va pas être possible simplement !
Sur un ordi costaud, on utiliserait un thread (= fil d'exécution parallèle), existe pas sur Arduino.
Il ne reste que les interruptions.
Suis pas spécialiste des interruption du proc de l'Arduino, mais faudrait une interruption générée par un timer, à chaque interruption tu inverses l'état.
Tu mets en place l'interruption quand tu veux et tu l'enlèves quand tu veux : tu mets tout dans le ctor et le dtor d'une classe Cligoteur, et hop:

void setup () {
  Cligoteur cliglo (100); // le cligno commence, à 100 ms

} // l'objet cliglo est détruit, le cligno s'arrête

Tu peux aussi créer l'objet Clignoteur en varaible globale (il ne démarre pas), et lui ajouter des méthodes start(), stop(), changerPeriode()...

Pour les interruptions, c'est pas trop compliqué, il faut fournir une fonction qui sera appellée à chaque interruption. Après perso je ne sais pas quelle interruption choisir, régler un timer harware... Mais y'en en plein qui savent !

Mon but est de faire clignoter ma led pendant 5s environ (sans bloquer la suite de l'execution du code) au debut du setup() (mon setup prend enviton 15secondes à se dérouler)

Si on a besoin d'une fonction non bloquante, c'est parce qu'il y a un code qui s'exécute en même temps. Que veux-tu faire exactement?

  • faire clignoter la led puis finir les 15s du setup?
  • faire clignoter la led pendant 5 secondes, tout en déroulant le setup?
    Si le setup dure 15 secondes en tout sans la led, tu veux qu'avec la led cela dure toujours 15s?

Retour aux bases de la programation d’un microcontroleur :

  • on met tout ce qui ne s’exécute qu’une seule fois dans la fonction setup
  • on met le reste dans une fonction qui tourne en boucle dans une fonction appellée très originalement “loop”

Bien évidement les fonctions setup et loop peuvent appeller autant de fonctions qu’elles veulent.

Si tu veux faire clignoter une led dans setup() elle ne clignotera que le temps que le programme reste dans setup() c’est à dire très très peu de temps.

Très grossierement tu n’écris que setup, loop et fonctions annexes mais l’IDE fourni au compilateur quelque chose qui ressemble à :

#include<Arduino.h>

void main(void)
{
    init();  // configuration du micro "à la sauce Arduino"
    setup();

    while(1)   // la condition dans while est un booléain; 1 correspond à TRUE
    {          //  la condition étant toujours TRUE il est impossible de sortir de la boucle       
       loop(); // dès que l'on sort de loop on y re-entre
    }
}

vileroi:
Si on a besoin d'une fonction non bloquante, c'est parce qu'il y a un code qui s'exécute en même temps. Que veux-tu faire exactement?

  • faire clignoter la led puis finir les 15s du setup?
  • faire clignoter la led pendant 5 secondes, tout en déroulant le setup?
    Si le setup dure 15 secondes en tout sans la led, tu veux qu'avec la led cela dure toujours 15s?

Oui je veux qu'au début de mon setup() ma led commence à clignoter pendant 5 secondes sans que ça bloque le reste de mon setup, en gros que mon setup dure 15s avec ou sans clignotement de led

simon884:
Oui je veux qu’au début de mon setup() ma led commence à clignoter pendant 5 secondes sans que ça bloque le reste de mon setup, en gros que mon setup dure 15s avec ou sans clignotement de led

Vous pouvez utiliser un timer pour cela éventuellement

#include <TimerOne.h>   // https://github.com/PaulStoffregen/TimerOne
volatile bool blinking = true;

void blinkLED() {
  digitalWrite(LED_BUILTIN, digitalRead(LED_BUILTIN) == HIGH ? LOW : HIGH);
  if (millis() >= 5000) {    // arrêter le clignotement au bout de 5s
    Timer1.stop();
    Timer1.detachInterrupt();
    digitalWrite(LED_BUILTIN, LOW);
    blinking = false;
  }
}

void setup(void)
{
  pinMode(LED_BUILTIN, OUTPUT);
  Timer1.initialize(200000UL);        // Toutes les 200ms (periode en µs)
  Timer1.attachInterrupt(blinkLED);   // on appelle le callback
  Timer1.start();

  // faire ce qu'il y a à faire dans le setup
  delay(10000); // simulation du temps nécessaire 

  if (blinking) {           // si le setup a duré moins de 5 secondes
    Timer1.stop();          // on force l'arrêt du clignotement car on quitte le setup()
    Timer1.detachInterrupt();
    digitalWrite(LED_BUILTIN, LOW);
    blinking = false;
  }
}


void loop(void) {
  // ici le code de la loop
}

15 secondes, c’est 15000 ms.
millis est mis à zéro au démarrage de l’Arduino. Donc la condition de durer 15 secondes revient à

while (millis () < 15000ul)

Tu veux clignoter 3 fois donc il y a 6 états qui changent toutes les 15000 / 6 = 2500 ms.
Il suffit donc de changer l’état de la led a chaque fois que millis passe par un multiple de 2500, au sein du while qui dure 15000 ms.

digitalWrite(ledpin,!digitalRead(ledpin));

lesept:
Il suffit donc de changer l'état de la led a chaque fois que millis passe par un multiple de 2500, au sein du while qui dure 15000 ms.

si certains fonctions appelées dans le setup() sont longues ce n'est pas si simple que cela... et sinon vous faites quoi, de l'attente active qui bloque le setup() ?

Il n'y a pas d'attente, le setup fait d'abord les initialisations, genre Serial.begin, puis lance le while. Tout se passe dans le while. Un test vérifie qu'on passe chaque étape de 2500ms, et tout ce qui doit être fait est fait dans le while. L'OP n'a pas précisé pourquoi il ne veut pas de delay, donc on ne sait pas s'il y a autre chose à faire que clignoter la led...
C'est en gros une loop a l'intérieur du setup.

Ah ok - ce n’est pas comme cela que je l’ai compris

J’ai compris qu’il y a des instructions dans le setup qui durent 15s et que l’OP veut que la LED clignote pendant les 5 premières secondes sans perturber les instructions nécessaires au setup qui vont durer chacune plus ou moins longtemps

hello
j’aurais fais comme vileroi, mais en utilisant le toggle dans TCCRA1
c’est ok, ça fonctionne sur la sortie D9.

pour tester, dans le setup, j’ai rajouté un serial.print dans une boucle “for”

elle est sensée afficher 65535 fois la valeur de f,
mais elle va jusqu’à 729 et repasse à 0 et recommence ainsi en boucle

auriez vous une idée du pourquoi du comment?

void setup()
{
  Serial.begin(115200);
  pinMode(9, OUTPUT);
  TCCR1A = 0b01000000; // Pas de comparaisons, mode CTC
  TCCR1B = 0b00001101; // Mode CTC OCR (4), prescaler à /1024 par défaut, 64µs
  OCR1A  = 7812;//15625;//3124; // 3125*64µs = 200ms
  TIMSK1 = 0b00000010; // Interruptions du timer 1 autorisées
  // le setup fait des choses longues pour 15 Secondes ou plus
  for(int f=0;f < 65535;f++)
  {
    Serial.print("f= ");Serial.println(f);Serial.flush();
  }
  // fin du setup
  TCCR1B = 0b00000000; //stoppe le timer donc le clignotement
}

void loop(){}

note:

for(int f=0;f < 65535;f++)

un int est toujours inférieur à 65535, la valeur maximale est d’ailleurs 32767…

Mais ce n’est pas cela qui plante le code de @dfg. Il y mise en place de la fonction d’interruption par
TIMSK1 = 0b00000010; // Interruptions du timer 1 autorisées

Comme la routine d’interruption:
ISR(TIMER1_COMPA_vect) // Appelée toutes les (7812+1)*64µs = 0,5s
n’est pas définie, il est possible que le vecteur reste initialisé à 0, ce qui correspond à un reset.

Donc le programme tourne et 0,5s après l’interruption fait un reset de la carte. Donc le programme redémarre (attente courte pendant laquelle il ne s’affiche encore rien) puis se met à compter pendant 0,5s et tout recommence.

EN 500ms, il n’a le temps de compter que jusqu’à 729. et si un caractère bizare apparait à 729, c’est parce qu’au milieu de la transmission arrive le reset et que le dernier caractère n’a pas été complètement envoyé.

Pour que cela fonctionne, il suffit de ne pas déclencher d’interruptions. Supprimer la ligne
TIMSK1 = 0b00000010; // Interruptions du timer 1 autorisées

et changer le 65535 en une valeur inférieur à 32767.

hello
merci Vileroi
maintenant, le cdc de notre ami est respecté
la boucle for dans le setup dure environ 15 secondes
le clignotement s’effectue pendant les 5 premieres secondes du setup
dans l’ISR, la variable “compteur” doit etre comparée à une valeur impaire pour s’assurer que la fin du clignotement est sur led éteinte.

int compteur=0;
ISR(TIMER1_COMPA_vect)
  {compteur++;if (compteur>11){TCCR1B = 0b00000000;}}
void setup()
{
  Serial.begin(115200);
  pinMode(9, OUTPUT);
  TCCR1A = 0b01000000; // mode CTC avec toogle sur D9
  TCCR1B = 0b00001101; // Mode CTC OCR (4), prescaler à /1024 par défaut, 64µs
  OCR1A  = 7812;       // 7812*64µs = 500ms
  TIMSK1 = 0b00000010; // Interruptions du timer 1 autorisées
  // le setup fait des choses longues pour 15 Secondes ou plus
  for(int f=0;f < 3700;f++)
  {
    Serial.print("boucle pour 15 Secondes f = ");Serial.print(f);
    Serial.print("   compteur= ");Serial.println(compteur);Serial.flush();
  }
}

  void loop(){}

exit la contraine du chiffre impair
et complément pour arret clignotement en fin de set up si celui ci est plus court que 5 secondes

int compteur=0;
ISR(TIMER1_COMPA_vect)
  {compteur++;if (compteur>12){TCCR1B = 0b00000000;TCCR1A = 0b00000000;}}
void setup()
{
  Serial.begin(115200);
  pinMode(9, OUTPUT);
  TCCR1A = 0b01000000;      // mode CTC avec toogle sur D9
  TCCR1B = 0b00001101;      // Mode CTC OCR (4), prescaler à /1024 par défaut, 64µs
  OCR1A  = 7812;            // 7812*64µs = 500ms
  TIMSK1 = 0b00000010;      // Interruptions du timer 1 autorisées
  for(int f=0;f < 3700;f++) // le setup fait des choses longues pour 15 Secondes ou plus
  {
    Serial.print("boucle pour 15 Secondes f = ");Serial.print(f);
    Serial.print("   compteur= ");Serial.println(compteur);Serial.flush();
  }
  TCCR1B = 0b00000000;      //si le setup est plus court que 5 secondes
  TCCR1A = 0b00000000;      //éteinds la led (toggle à zero)
}

  void loop(){}

le code posté en #7 faisait déjà ça "en plus lisible" avec la bibliothèque TimerOne

j’ai viré la boucle for pour mettre un delay(1000);

int compteur=0;
ISR(TIMER1_COMPA_vect)
  {compteur++;if (compteur>10){TCCR1B = 0b00000000;TCCR1A = 0b00000000;}}
void setup()
{
  Serial.begin(115200);
  pinMode(9, OUTPUT);
  TCCR1A = 0b01000000;      // mode CTC avec toogle sur D9
  TCCR1B = 0b00001101;      // Mode CTC OCR (4), prescaler à /1024 par défaut, 64µs
  OCR1A  = 7812;            // 7812*64µs = 500ms
  TIMSK1 = 0b00000010;      // Interruptions du timer 1 autorisées
  delay(10000);
  TCCR1B = 0b00000000;      //si le setup est plus court que 5 secondes
  TCCR1A = 0b00000000;      //éteinds la led (toggle à zero)
}
  void loop(){}

@jml
tout est question de sensibilité
ton code en #7 fait le boulot, mais pour moi, il n’est pas clair.
en le lisant, je ne sais pas ce que font les instructions.(j’exagère un peu)
je préfère écrire en “direct” dans les registres plutôt que de passer par une librairie qui s’apparente à une “boite noire” .

tout est question de sensibilité

oui c'est sûr ... ou de compréhension des registres.

La bibliothèque permet de régler simplement la période, d'attacher une fonction, de démarrer ou arrêter les interruptions de ce timer.