Fonction millis() pendant x secondes

Bonjour à tous,

J’ai une programme simulant le fonctionnement d’un passage à niveau.

Il fonctionne de la manière suivante :

  • détection du train par les capteurs IR A ou B
  • les led clignotent
  • Abaissement des barrières après 7 secondes
  • Les led continuent de clignoter tant que le train n’est pas passé
  • détection du train en sortie B ou A
  • Arret des led
  • Lever les barrières

Je n’arrive pas à faire un clignoter les LED pendant 7 secondes avant l’abaissement des barrières
c’est au niveau de l’appel de la fonction Signal()…

// Détection du passage d'un train par capteur infra-rouge
// Baisser 2 barrières et allumer 2 diodes en clignotement

#include <VarSpeedServo.h> // Inclure dans le programme les fonctions de gestion des servo-moteurs avec gestion de la vitesse

// Attribution des emplacements ou sont reliés les fils sur les broches de la carte Arduino
// Ces emplacements déclarés en constante (const) ne changeront pas durant tout le programme
const int capteurA = 0; // Le signal du capteur A est brancé sur l'entée analogique A0 de la carte Arduino
const int capteurB = 2; // Le signal du capteur B est brancé sur l'entée analogique A2 de la carte Arduino

const int diodeA = 10; // la diode A est reliée à l'entrée/sortie numérique 10 de la carte Arduino
const int diodeB = 12; // la diode B est reliée à l'entrée/sortie numérique 11 de la carte Arduino

const int barriereA = 2; // le servoA est reliée à l'entrée/sortie numérique 2 de la carte Arduino
const int barriereB = 4; // le servoB est reliée à l'entrée/sortie numérique 4 de la carte Arduino

VarSpeedServo servoA;
VarSpeedServo servoB;

unsigned long compteur_temps; // Une varible qui va permettre de compter le temps pour faire clignoter à intervale fixe les leds
unsigned long compteur_delais; // Une varible qui va permettre de compter le délais pour faire abaisser les barrieres

// Déclaration des variables, les variables stockent des informations qui peuvent varier durant le fonctionnement du programme
int angle_barriere_fermee = 110; // angle du servo pour mettre la barriere en position basse
int angle_barriere_ouverte = 40; // angle du servo pour mettre la barriere en position haute

int valeur_capteurA = 1023; // Cette variable recevra l'information du capteurA (plus de 512 si pas de détection et moins de 512 si il y a une détection de passage
int valeur_capteurB = 1023; // Cette variable recevra l'information du capteurA (plus de 512 si pas de détection et moins de 512 si il y a une détection de passage
int premier_capteur = 0; // Cette variable contiendra 1 si c'est le capteurA qui a détecté en premier le train, 2 si c'est le capteur B et 0 autrement

boolean train_engage = false; // variable que l'on met à 0 si il n'y a pas de détection de train et à 1 si un train est détecté
boolean barriere_ouverte; // variable à 1 si les barrières sont ouvertes et à 0 si elles sont fermées

int memo_timer; // une variable qui va permettre de compter le temps pour faire clignoter les leds
boolean etat_signal = false;  // une variable contenat 0 si les leds sont eteintes et 1 si elles sont allumlées

// Au lancement du programme on initialise les broches de la carte et les objets de notre programmation
void setup() {
  // On declare que les broches ou sont reliées les diodes sont des sorties pour la carte Arduino
  pinMode(diodeA,OUTPUT);
  pinMode(diodeB,OUTPUT);
  
  // On relie caque objet servo à la broche qui lui a été désignée
  servoA.attach(barriereA);
  servoB.attach(barriereB);

  // On place les barrières en position ouverte
  servoA.write(angle_barriere_ouverte);
  servoB.write(angle_barriere_ouverte);
  barriere_ouverte = true; 
}

// On fait une boucle que le programme va executer indéfiniment
void loop() {
  valeur_capteurA = analogRead(capteurA);
  valeur_capteurB = analogRead(capteurB);

  if (train_engage == 1 && premier_capteur == 0) {
    if (valeur_capteurA > 512 && valeur_capteurB > 512) {
      servoA.slowmove(angle_barriere_ouverte,30);
      servoB.slowmove(angle_barriere_ouverte,30);
      barriere_ouverte = true;
      digitalWrite(diodeA,LOW);
      digitalWrite(diodeB,LOW);
      train_engage = 0;
    }
  }

  // Si il n'y a pas de train entre les 2 capteurs
  if (train_engage == false) {
    // On regarde si un capteur détecte une présence
    if (valeur_capteurA < 512 || valeur_capteurB < 512) {
      train_engage = true;
      // On met en mémoire quel capteur à détecté l'arrivée du train
      if (valeur_capteurA < 512) {
        premier_capteur = 1;
      } else {
        premier_capteur = 2;
      }
    }

  // Si un train est engagé entre les 2 capteurs
  } else {
    Signal(); // On met le signal en route
    if (barriere_ouverte == true) { // Un train viens de s'engager et les barrières sont ouvertes donc on ferme  
      // On place les barrières en position fermée
      // servo.slowmove(angle,speed) | Speed 0 or 255: maximum, 1-254 from lower to higher speed
      servoA.slowmove(angle_barriere_fermee,30);
      servoB.slowmove(angle_barriere_fermee,30);
      // On met à 0 la variable d'information sur la position desbarrières
      barriere_ouverte = false;
    }
    // On teste si le 2eme capteur detecte le passage du train pour ouvrir les barrières
    // On regarde si c'est le capteurA qui a détecté l'arrivée du train
    if (premier_capteur == 1) {
      if (valeur_capteurB < 512) {
        premier_capteur = 0;;
      }
    } 
    if (premier_capteur == 2) { // Si non c'est que c'est le 2eme capteur
      if (valeur_capteurA < 512) {
        premier_capteur = 0;
      }
    }
  }
  delay(10);
  

}


//**************************************************************************
// Fonction pour faire clignoter les leds
void Signal() {
  if (millis() > compteur_temps + 800) { //Vitesse clignottement 250
    compteur_temps = millis();
  if (etat_signal == false) {
     etat_signal = true;
      digitalWrite(diodeA,HIGH);
      digitalWrite(diodeB,HIGH);
    } else {
      etat_signal = false;
      digitalWrite(diodeA,LOW);
      digitalWrite(diodeB,LOW);
    }
  }
}

Pour éviter des soucis dans une cinquantaine de jour quand milllis() va revenir à 0 il vaut mieux écrire   if (millis() - compteur_temps > 800) { //Vitesse clignotement 250(et le commentaire n'est pas adapté)

j'ai pas lu tout le code, mais appelez vous la fonction Signal() à chaque tour de loop() quand il faut que le signal soit actif ?

il faudrait une variable qui mémorise l'état du signal - attente_ clignotement, clignotement actif, clignotement_terminé. par défaut vous êtes en attente clignotement. au moment du déclenchement du signal vous notez l'heure de départ (pour compter vos 7 secondes) et passez au mode clignotement _actif. tant que vous êtes dans ce mode vous clignotez à la fréquence souhaitée, puis quand vous avez eu les 7 secondes alors vous passez au rouge et au mode clignotement_terminé. La fonction signal saura alors qu'il ne faut plus clignoter. jusqu'à la prochaine initialisation

Je n’ai pas trop de soucis sur les 50 jours, l’arduino ne reste guère plus longtemps que 24h en tension.
Mais merci de la remarque (c’est 800ms de clignotement).

Effectivement la fonction Signal() est appellée à tour de loop() quand le signal est actif (quand indifféremment capteur A ou capteur B passe actif).

Pour cela j’aurais mis une fonction loop() dans la première avec une autre fonction millis()

const long tempo_led = 7000; 

void loop() {

      blablabla

  void loop() {
      unsigned long x = millis();
      while(millis() - x < tempo_led){
          Signal();    
      }
Signal();
et la suite ....

Ce n’est pas possible de mettre une fonction dans une fonction, mais tu peux mettre un bloc while comme tu le fais ici. Ceci est correct

void loop() {

      blablabla

   { // début du bloc
      unsigned long x = millis();
      while(millis() - x < tempo_led) Signal();   
    } // fin du bloc
Signal();
}

"Signal" (avec ou sans majuscule je ne sais plus) est une macro Atmel "deprecated" remplacée par ISR.
N'y a-t-il pas de risque à utiliser ce nom ?

68tjs:
"Signal" (avec ou sans majuscule je ne sais plus) est une macro Atmel "deprecated" remplacée par ISR.
N'y a-t-il pas de risque à utiliser ce nom ?

c'était une macro, tout en majuscule, donc pas de soucis - mais bon réflexe!

Ça fonctionne !
J’ai bien les 7 secondes de délais. Merci !

Mais je ne sais pas pourquoi ça me sort la partie détection de sortie.
Si le capteur A ou B enclenche la fonction clignotement et servos, puis clignotement, normalement il faut que B ou A déclenche l’arrêt de “Signal()” et le mouvement des servos.

Or là ça fonctionne que quand le capteur B est actifs assez longtemps et avec un délais de 7 secondes…

Sans l’ajout du bloc while l’arrêt de Signal() se faisait correctement à l’instant où le capteur opposé était actif.

// Détection du passage d'un train par capteur infra-rouge
// Baisser 2 barrières et allumer 2 diodes en clignotement

#include <VarSpeedServo.h> // Inclure dans le programme les fonctions de gestion des servo-moteurs avec gestion de la vitesse

// Attribution des emplacements ou sont reliés les fils sur les broches de la carte Arduino
// Ces emplacements déclarés en constante (const) ne changeront pas durant tout le programme
const int capteurA = 0; // Le signal du capteur A est brancé sur l'entée analogique A0 de la carte Arduino
const int capteurB = 2; // Le signal du capteur B est brancé sur l'entée analogique A2 de la carte Arduino

const int diodeA = 10; // la diode A est reliée à l'entrée/sortie numérique 10 de la carte Arduino
const int diodeB = 12; // la diode B est reliée à l'entrée/sortie numérique 11 de la carte Arduino

const int barriereA = 2; // le servoA est reliée à l'entrée/sortie numérique 2 de la carte Arduino
const int barriereB = 4; // le servoB est reliée à l'entrée/sortie numérique 4 de la carte Arduino

VarSpeedServo servoA;
VarSpeedServo servoB;

unsigned long compteur_temps; // Une varible qui va permettre de compter le temps pour faire clignoter à intervale fixe les leds
const long tempo_led = 7000; // Une varible qui va permettre de compter le délais pour faire abaisser les barrieres

// Déclaration des variables, les variables stockent des informations qui peuvent varier durant le fonctionnement du programme
int angle_barriere_fermee = 110; // angle du servo pour mettre la barriere en position basse
int angle_barriere_ouverte = 40; // angle du servo pour mettre la barriere en position haute

int valeur_capteurA = 1023; // Cette variable recevra l'information du capteurA (plus de 512 si pas de détection et moins de 512 si il y a une détection de passage
int valeur_capteurB = 1023; // Cette variable recevra l'information du capteurA (plus de 512 si pas de détection et moins de 512 si il y a une détection de passage
int premier_capteur = 0; // Cette variable contiendra 1 si c'est le capteurA qui a détecté en premier le train, 2 si c'est le capteur B et 0 autrement

boolean train_engage = false; // variable que l'on met à 0 si il n'y a pas de détection de train et à 1 si un train est détecté
boolean barriere_ouverte; // variable à 1 si les barrières sont ouvertes et à 0 si elles sont fermées

int memo_timer; // une variable qui va permettre de compter le temps pour faire clignoter les leds
boolean etat_signal = false;  // une variable contenat 0 si les leds sont eteintes et 1 si elles sont allumlées

// Au lancement du programme on initialise les broches de la carte et les objets de notre programmation
void setup() {
  // On declare que les broches ou sont reliées les diodes sont des sorties pour la carte Arduino
  pinMode(diodeA,OUTPUT);
  pinMode(diodeB,OUTPUT);
  
  // On relie caque objet servo à la broche qui lui a été désignée
  servoA.attach(barriereA);
  servoB.attach(barriereB);

  // On place les barrières en position ouverte
  servoA.write(angle_barriere_ouverte);
  servoB.write(angle_barriere_ouverte);
  barriere_ouverte = true; 
}

// On fait une boucle que le programme va executer indéfiniment
void loop() {
  valeur_capteurA = analogRead(capteurA);
  valeur_capteurB = analogRead(capteurB);

  if (train_engage == 1 && premier_capteur == 0) {
    if (valeur_capteurA > 512 && valeur_capteurB > 512) {
      servoA.slowmove(angle_barriere_ouverte,30);
      servoB.slowmove(angle_barriere_ouverte,30);
      barriere_ouverte = true;
      digitalWrite(diodeA,LOW);
      digitalWrite(diodeB,LOW);
      train_engage = 0;
    }
  }

  // Si il n'y a pas de train entre les 2 capteurs
  if (train_engage == false) {
    // On regarde si un capteur détecte une présence
    if (valeur_capteurA < 512 || valeur_capteurB < 512) {
      train_engage = true;
      // On met en mémoire quel capteur à détecté l'arrivée du train
      if (valeur_capteurA < 512) {
        premier_capteur = 1;
      } else {
        premier_capteur = 2;
      }
    }

  // Si un train est engagé entre les 2 capteurs
  } else {
       { // début du bloc
      unsigned long x = millis();
      while(millis() - x < tempo_led) Signal();   
    } // fin du bloc
    Signal(); // On met le signal en route
    if (barriere_ouverte == true) { // Un train viens de s'engager et les barrières sont ouvertes donc on ferme  
      // On place les barrières en position fermée
      // servo.slowmove(angle,speed) | Speed 0 or 255: maximum, 1-254 from lower to higher speed
      servoA.slowmove(angle_barriere_fermee,30);
      servoB.slowmove(angle_barriere_fermee,30);
      // On met à 0 la variable d'information sur la position desbarrières
      barriere_ouverte = false;
    }
    // On teste si le 2eme capteur detecte le passage du train pour ouvrir les barrières
    // On regarde si c'est le capteurA qui a détecté l'arrivée du train
    if (premier_capteur == 1) {
      if (valeur_capteurB < 512) {
        premier_capteur = 0;;
      }
    } 
    if (premier_capteur == 2) { // Si non c'est que c'est le 2eme capteur
      if (valeur_capteurA < 512) {
        premier_capteur = 0;
      }
    }
  }
  delay(10);
  

}


//**************************************************************************
// Fonction pour faire clignoter les leds
void Signal() {
  if (millis() > compteur_temps + 800) { //Vitesse clignottement 800ms H/L
    compteur_temps = millis();
  if (etat_signal == false) {
     etat_signal = true;
      digitalWrite(diodeA,HIGH);
      digitalWrite(diodeB,HIGH);
    } else {
      etat_signal = false;
      digitalWrite(diodeA,LOW);
      digitalWrite(diodeB,LOW);
    }
  }
}

Si vous mettez ça dans la loop()

   { // début du bloc
      unsigned long x = millis();
      while(millis() - x < tempo_led) Signal();   
    } // fin du bloc

vous allez avoir une attente active. rien d’autre ne sera testé pendant le clignotement

c’est typiquement une définition de programme qui se prête bien à la programmation par machine à états (cf mon tuto éventuellement)

par exemple un truc du genre pour donnez des idées:

const byte pinCapteurA = 2;
const byte pinCapteurB = 3;
const byte pinLED = LED_BUILTIN;
const uint32_t dureeClignotement = 7000UL; // 7 secondes
const uint32_t dureePassage = 10000UL; // 10 secondes
const uint32_t demiPeriodeClignotement = 250; // frequence = 2 fois par seconde

enum etatSignal_t : uint8_t {attente_clignotement, clignotement_actif, clignotement_termine, barriere_fermee} etatSignal;

void clignote(bool forceStart = false)
{
  static uint32_t startTime, lastTick;
  if (forceStart) {
    startTime = lastTick = millis();
    digitalWrite(pinLED, HIGH);
    Serial.print(F("CLIGNOTE ["));
    etatSignal = clignotement_actif;
  } else {
    if (etatSignal == clignotement_actif) {
      // a-t-on fini ?
      if (millis() - startTime >= dureeClignotement) {
        digitalWrite(pinLED, LOW);
        Serial.println(F("]"));
        etatSignal = clignotement_termine;
      } else {
        // est-ce le moment de basculer l'état
        if (millis() - lastTick >= demiPeriodeClignotement) {
          // on inverse l'état de la LED
          digitalWrite(pinLED, (digitalRead(pinLED) == LOW) ? HIGH : LOW);
          Serial.write('.');
          lastTick = millis();
        }
      }
    }
  }
}

// pour simplifier on a une durée fixe, faudrait tester un capteur
void attentePassageTrain(bool forceStart = false)
{
  static uint32_t startTime, lastTick;
  if (forceStart) {
    startTime = lastTick = millis();
    Serial.print(F("BARRIERE FERMEE ["));
    etatSignal = barriere_fermee;
  } else {
    // a-t-on fini ?
    if (millis() - startTime >= dureePassage) { 
      Serial.println(F("] OUVERTURE BARRIERE"));
      etatSignal = attente_clignotement;
    } else {
      // est-ce le moment de basculer l'état
      if (millis() - lastTick >= demiPeriodeClignotement) {
        Serial.write('.');
        lastTick = millis();
      }
    }
  }
}


void setup() {
  Serial.begin(115200);
  pinMode(pinCapteurA, INPUT_PULLUP);
  pinMode(pinCapteurB, INPUT_PULLUP);
  pinMode(pinLED, OUTPUT);
  digitalWrite(pinLED, LOW);
  etatSignal = attente_clignotement;
  Serial.println(F("ATTENTE SIGNAL SUR PIN 2 ou 3"));
}

void loop()
{
  switch (etatSignal) {
    case attente_clignotement:
      // est-ce qu'un des capteur s'est activé
      if ((digitalRead(pinCapteurA) == LOW) || (digitalRead(pinCapteurB) == LOW)) {
        clignote(true); // si oui on déclenche le clignotement
      }
      break;

    case clignotement_actif:
      clignote();
      break;

    case clignotement_termine:
      // on a fini de clignoter, faire descendre la barrière et passer le feu au rouge
      attentePassageTrain(true); // on initialise l'attente du passage du train
      break;

    case barriere_fermee:
      attentePassageTrain(); // on attend patiemment
      break;
  }

  // ICI ON PEUT FAIRE AUTRE CHOSE
}

merci !
Je vais essayer en y intégrant la partie test de capteur.

Je touchais au but avec le "while" mais au détriment de la détection.

Dommage qu'il faille que le capteur de sortie soit à 1 pendant X secondes pour sortir de la boucle avec un délais de X secondes.