Comment définir un delay avec millis?

Mon programme est simple, mais j’ai un petit problème: je veux allumer une LED pendant un certain temps. J’ai fait pas mal de recherche mais je ne comprend pas comment on peut le faire avec la fonction millis, car oui, je veux utiliser millis() et non le delay qui met en pause le programme.

/* Bibliotheque pour le moteur (une fonction) */

#include <Stepper.h>

/* Partie "capteur IR"  */

const int lampeLed = 8;          // broche de la lampe
int capteurIR = 10;               // broche du capteur IR
int etatCapteurIR = 0;           // variable pour la valeur du capteur IR
int lampeStat = LOW;

/* Partie "photoresistance"  */
int capteurLU = 0;               // pin de la photoresistance (analogique)
int valeurResistance = 0;        // variable pour la valeur de la photoresistance                   

/* Partie "moteur" */
int autorise = 0;               // variable pour autoriser le moteur a ouvrir la porte
int moteurPP = 10;               // variable pour le moteur
int nbrPas = 3072;               // 3072 pas soit 48*64 pas 

Stepper Moteur(nbrPas,2,3,4,5);  // définie le nombre de pas, et les broches 

/* Partie temporisation */
unsigned long previousMillis=0;
int interval=10000;

void setup() 
{
  Serial.begin(9600);
  Moteur.setSpeed(9.9);           // vitesse maximale que le moteur peut atteindre (9.9 tr/min)
  pinMode(lampeLed, OUTPUT);      // lampe => sortie
  pinMode(capteurIR, INPUT);      // capteur => entrée
}
 
void loop()
{
etatCapteurIR = digitalRead(capteurIR);    // regarde la valeur du capteur IR
 Serial.println(etatCapteurIR);
if (etatCapteurIR == HIGH)                 // regarde si il y'a une tension
  {            
    valeurResistance = analogRead(capteurLU); // regarde la valeur de la photorésistance (resistance)
    Serial.println(valeurResistance);
    
    if (valeurResistance > 940)               // compare la valeur de la résistance
    {
     digitalWrite(lampeLed, HIGH); // allume la lampe
     } 
     else
     {
  unsigned long currentMillis = millis();
     if ((unsigned long)(currentMillis - previousMillis) >= interval)
     {
      digitalWrite(lampeLed, LOW);
      previousMillis = currentMillis;  
     }
   }  
}

if (moteurPP == autorise)
    { 

      Moteur.step(3072/6);  //=> Fais tourner le moteur de pas.<=//
 
     delay(10000); //=> Délai de 10 seconde pour laisser la porte ouverte pour que l'utilisateur entre.<=//
    
      Moteur.step(-3072/6);  //=> Fais la meme chose, mais dans le sens inverse.<=//
     
     autorise=0;
    }     
}

Ouvre l'exemple "BlinkWithoutDelay" dans ton IDE, et inspire toi!

Justement, ce programme fonctionne en faisant clignoter une led avec millis mais j’ai beau le retourner dans tous les sens je ne comprend pas comment je peut faire : je n’arrive “vraiment” a comprendre le programme. En faite je peut utiliser la fonction millis pour faire 1 delay une seule et unique fois, car évidement après, le temps “millis” devient grand (car je la compare avec une duré de 10 seconde).
Comment faire pour répéter cette action?

C'est comme si tu disais :

Là il est 20h13. Je ne sais pas comment faire pour compter 15 minutes à partir de maintenant.
Je ne sais compter 15 minutes que si je démarre à minuit pour arriver à 0h15.

hello
imagine que lorsque le prg démarre, il y a en interne un compteur qui s'incrémente de 1 toutes les millisecondes.

au bout de 1000 millisecondes, le compteur vaut 1000. au bout d'une heure, le compteur vaut 3600000
et ce compteur compte ainsi pendant 40 et qq jours.

toi, tu ne peux pas le remettre à zéro à ta guise.
la fonction millis(); te permet de relever la valeur de ce compteur.

donc si tu veux chronométrer un événement,
tu relèves la valeur du compteur au début de ton événement: unsigned long début=millis();,
puis tu relèves la valeur du compteur à la fin de ton événement unsigned long fin=millis();.
pour connaitre la durée de ton événement il te suffit de faire la soustraction fin - début .

si tu as un deuxième événement, tu recommences: début= compteur puis le 2ème évenement terminé:fin = compteur et durée = fin - début

tu peux avoir plusieurs événement qui se chevauchent

debut_1=millis();
début_2=millis();
debut_3=millis();
fin_1=millis();durée_1=fin_1-début_1;
debut_4=millis();
fin_3=millis();durée_3=fin_3-debut_3;
fin_4=millis();durée_4=fin_4-debut_4;
fin_2=millis();durée2=fin_2-debut_2;

nota: les variables qui servent à stocker les valeurs de millis() doivent être impérativement des unsigned long car les valeurs qui peuvent y être stockées peuvent être énormes. ( plus de 40 jours en millisecondes)

en espérant avoir été simple et clair

Dans votre code il faudrait que previousMillis soit initialisé à la valeur de millis quand vous allumez la led et le test d'extinction doit se faire si la led est allumée et que le délai est dépassé alors vous éteignez

Merci pour vos réponse, j'essai plusieurs choses pour le moments pour voir si je trouve une solution avec vos informations ^^. Et si jamais je ne veux pas faire faire "plusieurs" événements mais répéter ceci : la LED s'allume pendant 10 secondes puis s'éteint.
Mais je doit mettre cette fonction dans un "void loop" et je dois donc pouvoir la répéter plusieurs fois.
Je vais travailler dessus ^^.

J'ai essayer de faire le système de soustraction pour comparer la durée avec le temps (l’intervalle) que l'on veut, et donc j'ai fait ce programme

const int ledPin =  8;      

int tempsDuree;
         
const long interval = 5000; 

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

void loop() 
{
unsigned long tempsDebut = 0; 
// événement 1: allumage de la lampe
digitalWrite(ledPin, HIGH);
unsigned long tempsAllumer = millis();

tempsDuree = tempsAllumer-tempsDebut;

//événement 2: lampe éteint toi au bout de 5 secondes svp wallah frère
if (tempsDuree  >= interval)
 {
   tempsDebut = tempsAllumer;
   digitalWrite(ledPin, LOW);
  
   } 
}

Mais sa ne fonctionne pas en boucle: la lampe ne s'éteint pas, il y'a comme une "baisse" de tension au niveau de la LED mais je ne comprend pas cette baisse de tension...
Je pense peut être que la lampe s'allume et s'éteint rapidement d'ou l'effet de la baisse de tension mais je ne suis pas sur, ma manière de faire est-elle bonne ou non?

Bonjour,

tenpsDebut doit être déclaré static autrement il est réinitialisé à 0 à chaque entrée dans loop

static unsigned long tempsDebut = 0;

Merci pour ta réponse j’avais pas fait attention ^^, j’ai essayer de trouver une solution :
_je sais comment faire un intervalle…
_mais je ne sais pas comment le répéter seulement quand j’en ai envie car je doit allumer la lampe que dans certaines conditions : il doit faire nuit et le capteur de présence doit détecter l’individu.
(il y’a aussi un moteur mais on s’en fou)

J’ai donc fait ce programme:

/* Bibliothèque pour le moteur (une fonction) */
#include <Stepper.h>

/* Partie "capteur IR"  */
const int lampeLed = 8;          // broche de la lampe
int capteurIR = 10;               // broche du capteur IR
int etatCapteurIR = 0;           // variable pour la valeur du capteur IR

/* Partie "photoresistance"  */
int capteurLU = 0;               // pin de la photorésistance (analogique)
int valeurResistance = 0;        // variable pour la valeur de la photorésistance                   

/* Partie "moteur" */
int autorise = 0;               // variable pour autoriser le moteur a ouvrir la porte
int moteurPP = 10;               // variable pour le moteur
int nbrPas = 3072;               // 3072 pas soit 48*64 pas 

Stepper Moteur(nbrPas,2,3,4,5);  // définie le nombre de pas, et les broches 

/* Partie temporisation */
int interval = 10000;
int tempsDuree;
int abdoula;
unsigned long tempsDebut = 0; 
void setup() 
{
  Serial.begin(9600);
  Moteur.setSpeed(9.9);           // vitesse maximale que le moteur peut atteindre (9.9 tr/min)
  pinMode(lampeLed, OUTPUT);      // declare LED as output
  pinMode(capteurIR, INPUT);      // declare sensor as input
}
 
void loop()
{
etatCapteurIR = digitalRead(capteurIR);    // regarde la valeur du capteur IR
 Serial.println(etatCapteurIR);
if (etatCapteurIR == HIGH)                 // regarde si il y'a une tension
  {            
    valeurResistance = analogRead(capteurLU); // regarde la valeur de la photorésistance (résistance)
    Serial.println(valeurResistance);
    if (valeurResistance > 1000)               // compare la valeur de la résistance
    { 
        // événement 1: allumage de la lampe
        digitalWrite(lampeLed, HIGH);
        unsigned long tempsAllumer = millis();
        tempsDuree = tempsAllumer-tempsDebut;

        //événement 2: lampe éteint toi au bout de 10 secondes svp 
        if (tempsDuree  >= interval)
         {
          tempsDebut=tempsAllumer;
          digitalWrite(lampeLed, LOW);
        } 
    }  
}

if (moteurPP == autorise)
    { 

      Moteur.step(3072/6);  //=> Fais tourner le moteur de pas.<=//
 
     delay(10000); //=> Délai de 10 seconde pour laisser la porte ouverte pour que l'utilisateur entre.<=//
    
      Moteur.step(-3072/6);  //=> Fais la même chose, mais dans le sens inverse.<=//
     
     autorise=0;
    }     
}

Evidemment, j’ai fait en sorte que mon programme soit logique, mais sa ne marche pas… Certaines fois le lampe s’éteint après les dix secondes mais seulement une fois… Si je répète le processus, la lampe reste allumer… Quelqu’un peut m’éclairer?

Si je répète le processus, la lampe reste allumée... Quelqu'un peut m'éclairer?

suffit de répéter le processus et la lampe va restée allumée et donc ça va vous éclairer :slight_smile:

blague à part si je comprends bien vous avez un détecteur de chaleur/mouvement (IR) et quand il se passe quelque chose, s'il fait nuit, vous voulez allumer la LED, c'est cela?

Vous pouvez préciser ce que vous avez comme capteur infra-rouge? Parce que généralement il leur fait une phase de calibration de 60 secondes dans le setup avant de s'en servir et quand ils déclenchent ils restent à HIGH (ou LOW pour certains) pendant un temps variable (parfois réglable avec un potentiomètre)

vos 10 secondes donc doivent elles dépendre de la valeur de l'IR ou pas?

J'ai un capteur qui, en effet, doit permettre d'allumer la lampe si une personne est détecter.
en revanche, pour la calibration ce n'est pas un problème car quand je fait des test je regarde dans le moniteur de la carte pour voir si le capteur est a "1" ou a "0", et il n'y a pas de problème a se niveau la: si je passe ma main devant, le moniteur donne "1", sinon il n'y a rien "0".

vous avez un lien sur le capteur? (je suis curieux)

Sinon pour votre code c’est le genre de programme où une “machine à état” simplifie la programmation.

Si je fais abstraction du moteur et de son mouvement - Vous avez grosso modo deux états pour votre machine, soit la LED est allumée, soit elle est éteinte. et vous avez des événements ou conditions qui déclenchent le passage d’un état à un autre. On peut représenter ça comme cela par exemple

le code alors est tout simple ensuite à bâtir (j’ai pas testé, juste tapé en vrac donc à relire)

/* Partie "capteur IR"  */
const byte IRPin = 10;

/* Partie "photoresistance"  */
const byte PhotoresistancePin = A0;       // pin de la photorésistance (analogique)
const int seuilJour = 800;
const int seuilNuit = 1000;

/* Partie "LED" */
const byte LEDPin = 8;
boolean ledEteinte;

/* Partie temporisation */
const unsigned long dureeAllumage = 10000ul; // ul à la fin par bonne habitude pour unsigned long.
unsigned long instantAllumage; // pourrait être dans la loop() en static

// -------------------------------
void setup() {
  Serial.begin(115200);
  pinMode(IRPin, INPUT);// declare sensor as input
  pinMode(LEDPin, OUTPUT); // declare LED as output
  digitalWrite(LEDPin, LOW); // éteinte
  ledEteinte = true; // on pourrait aussi lire la pin de la LED, mais c'est plus rapide avec une variable
}

void loop() {

  if (ledEteinte) {

    // on vérifie toutes les conditions de transition pour allumer la lumière,

    // transition [1] Présence et c'est la nuit
    if ((digitalRead(IRPin) == HIGH) && (analogRead(PhotoresistancePin) > seuilNuit)) {
      digitalWrite(LEDPin, HIGH); // allumée
      instantAllumage = millis();
      ledEteinte = false;
    }
    // pas d'autres conditions d'allumage

  } else {
    // Tant qu'il y a une présence le délai ne court pas
    if (digitalRead(IRPin) == HIGH) instantAllumage = millis();

    // on vérifie tout ce qui peut éteindre la lumière, on en a deux (on pourrait faire un ||)

    // transition [2] Absence et après un délai (on pourrait juste tester le délai car si présence le départ du délai a été modifié juste avant)
    if ((digitalRead(IRPin) == LOW) && (millis() - instantAllumage >= dureeAllumage)) {
      digitalWrite(LEDPin, LOW); // éteinte
      ledEteinte = true;
    }

    // transition [3] il fait jour
    else if (analogRead(PhotoresistancePin) < seuilJour) {
      digitalWrite(LEDPin, LOW); // éteinte
      ledEteinte = true;
    }

  }
}

Merci pour ta réponse ^^ je vais tester cela de suite et pour le capteur IR je n’ai pas vraiment la source car je l’emprunte en revanche c’est un capteur de DFRobot, il fait partie de la “500bp” series (tape dans google tu verra que c’est un capteur PIR simple).
Je n’en sais pas + a son sujet désoler ^^.

FeuilleDePapier:
Pour le capteur IR je n'ai pas vraiment la source car je l'emprunte en revanche c'est un capteur de DFRobot, il fait partie de la "500bp" series (tape dans google tu verra que c'est un capteur PIR simple).
Je n'en sais pas + a son sujet désolé ^^.

vous pourriez faire l'effort d'aller voir vous même la spec et regardé ce qu'il y est dit... j'y suis allé et ils mentionnent à la fois un délai initial de calibration et que la pin restera HIGH quelques secondes même sans détection après déclenchement... donc à prendre en compte éventuellement dans le code...

A d'accord....désolé ^^ je vais aller voir cela de suite moi même. Et merci pour votre programme sa ma montrer que je fait plein de fonction if alors qu'une seule peut en regrouper deux, du coup votre programme est plus "compacte" je n'avais jamais vraiment penser a le rendre compacte.
Je vais peut être rajouter une calibration du capteur pour que le système soit plus "propre".

Et d’ailleurs votre programme fonctionne ^^, je vais pouvoir voir comment vous avez fait pour le millis() pour ne plus être bloquer par le delay.

J'ai donc pu voir que vous utiliser des choses qui me sont inconnues comme le "const byte" et le "boolean" je vais me renseigner a leurs sujet pour en savoir plus.

Aussi, dans votre programme vous initialisez dans le setup un "serial.begin(115200)" mais je ne comprend pas a quoi il sert...

Merci de m'avoir aider c'est vraiment sympas ^^.

FeuilleDePapier:
Et d’ailleurs votre programme fonctionne ^^, je vais pouvoir voir comment vous avez fait pour le millis() pour ne plus être bloquer par le delay.

Oui il faut bien sûr essayer de comprendre comment ça fonctionne!!

FeuilleDePapier:
J'ai donc pu voir que vous utiliser des choses qui me sont inconnues comme le "const byte" et le "boolean" je vais me renseigner a leurs sujet pour en savoir plus.

const ça pour dire au compilateur que la variable que vous déclarez ne changera jamais; si le compilateur voit plus tard que vous essayez de changer sa valeur, il va vous prévenir à la compilation. ça permet donc de lui donner des indices pour qu'il vous aide à avoir du meilleur code et éviter des erreurs. En plus comme il sait que la valeur ne changera pas, parfois il pourra décider de mettre directement la valeur dans les formules ou appels de fonction sans même réserver de mémoire pour cela. donc ça permet aussi d'optimiser le code

byte c'est un type de base, comme int ou char. ça veut dire allouer 1 octet pour y stocker des valeurs non signées (donc un chiffre entre 0 et 255 ---> c'est très bien pour des PINs)

boolean c'est un type de base, comme int ou char mais c'est fait pour stocker des valeurs de vérité, vrai ou faux (bon on programme en anglais, donc true ou false). bien sûr on peut utiliser d'autres types de variables comme un entier puisque 0 c'est faux et n'importe quoi d'autres sera considéré comme vrai dans les test conditionnels, mais c'est conceptuellement plus beau et plus juste si vous voulez mémoriser quelque chose de vrai ou faux de définir une variable de type boolean

FeuilleDePapier:
Aussi, dans votre programme vous initialisez dans le setup un "serial.begin(115200)" mais je ne comprend pas a quoi il sert...

il sert à rien car je n'affiche rien dans la console dans le programme tel que je l'ai posté :slight_smile:
Mais si vous voulez rajouter des Serial.print() pour voir ce qu'il se passe alors il faut le faire. 115200 c'est la vitesse de communication du port série, il faudra bien sûr alors choisir dans la console Série cette vitesse aussi dans le popup en bas de la fenêtre

FeuilleDePapier:
Merci de m'avoir aider c'est vraiment sympas ^^.

de rien :slight_smile:

Ok merci encore pour ta réponse:
_ le boolean je me suis renseigner et j'ai compris comment il fonctionne et le const byte un peut plus grâce a ta réponse.

Et ok pour le serial.begin du coup sa change rien (je vais donc le laisser a 9600 qui suffit pour le moment.)

bon il sert à rien donc vous pouvez le virer mais pourquoi aller lentement plutôt que vite... prenez l'habitude de mettre 115200 (voir le double) plutôt que 9600. ça évitera de ralentir vos programmes pour rien et de créer potentiellement des effets de bords néfastes: l'écriture sur le port Série devient bloquante si vous avez trop de choses à écrire pour le buffer et le buffer ne fait que 64 caractères - donc vous pouvez vous retrouvez avec un programme qui est à l'arrêt à cause des traces de debug. il n'y a vraiment pas de bonnes raisons d'aller lentement avec les arduinos modernes et un port USB de PC. ça tient sans pb le débit