Partage
  • Partager sur Facebook
  • Partager sur Twitter

timer qui démare tout seul...

ARDUINO

Sujet résolu
    18 juillet 2014 à 22:08:30

    Bonsoir,

    Je fais appel à vous car je suis vraiment désespéré, mon code ne fait pas ce que je souhaiterais qu'il fasse, d'ailleurs le voici:

    #include <MemoryFree.h>
    
    const int led = 10;
    const int button = 6;
    int button_state = 0;
    unsigned long time = 0;
    long tempsfixe = 20000;
    
    
    void setup()
    {
      pinMode(button, INPUT);
      pinMode(led, OUTPUT);
      Serial.begin(9600);
    }
    
    void loop()
    {
      button_state = digitalRead(button);
    
      time = millis();
      tempsfixe = 20000;
    
    
      if (button_state == LOW)
      {
        delay(500);
        digitalWrite(led, HIGH);
        delay(500);
        digitalWrite(led, LOW);
    
      }
    
      if (button_state == HIGH)
      {
        if (tempsfixe > time)
        {
          digitalWrite(led, HIGH);
          Serial.print("Temps :");
          Serial.println(time);
          Serial.println(freeMemory());
          delay(1000);
        }
      }
      if (tempsfixe < time)
      {
        digitalWrite(led, LOW);
    
      }
    
    
    
    }
    

    Pourtant j'ai l'impression que c'est une erreur vraiment bête, mais pas moyen... :'( Voici le déroulement de monde code:

    * Lorsque le bouton est à l'état relâché, la LED doit cligoter (ça c'est OK)...

    * Lorsque la fonction millis() dépasse la valeur fixée, la LED devrait s'éteindre, mais ce n'est pas le cas...

    * Idem lorsque le bouton est enfoncé (ou pas), parce que même si il n'est pas enfoncé, le timer démare quand même...

    Merci d'avance pour vos réponses :(

    -
    Edité par tone5846 18 juillet 2014 à 22:09:29

    • Partager sur Facebook
    • Partager sur Twitter
      Staff 19 juillet 2014 à 11:19:47

      Je suppose que c'est la suite de ton précédant sujet non ?

      Du coup, je répète plus ou moins ce que j'ai dit : les delay sont à bannir !

      Pendant que tu fais un delay(500) pour clignoter ta led, ton programme ne test pas le bouton.

      Idem pendant que tu fais un delay(1000)...

      Du coup, ton programme perd énormément en réactivité puisqu'il peut s'écouler une seconde avant que l'état du bouton ne soit réellement pris en compte.

      Un bon programme n'utilise pas (ou très peu) les delay et fait tout à l'aide de la fonction millis en comparant des temps.

      Ton programme devrait plus ressembler à ça :

      const int buttonPin = 6;
      const int ledPin = 10;
      
      int ledState;
      
      unsigned long lastBlinkTime; // Valeur de millis() au dernier clignotement
      unsigned long lastLoopTime;  // Valeur de millis() au dernier passage dans loop()
      
      long timeLeft; // Temps restant (décrémenté progressivement)
      
      
      
      void setup() {
      	
      	// Initialisation des pin
      	pinMode(buttonPin, INPUT);
      	pinMode(ledPin, OUTPUT);
      	
      	// Initialisation du Serial
      	Serial.begin(9600);
      	
      	// Initialisation des variables
      	ledState = HIGH;
      	lastBlinkTime = 0;
      	lastLoopTime = 0;
      	timeLeft = 20000;
      	
      }
       
      void loop() {
      	
      	int buttonState = digitalRead(buttonPin);
      	unsigned long loopTime = millis();
      	
      	// Si le bouton est LOW, on est en mode pause (clignotement)
      	if ( buttonState == LOW ) {
      		
      		// Si le timer est écoulé, la led est forcément off
      		if ( timeLeft <= 0 ) {
      			
      			ledState = LOW;
      		
      		// Sinon, l'état de la led dépend du clignotement
      		} else {
      			
      			// Si il s'est écoulé 500ms, alors on change l'état de la led (clignotement)
      			if ( ( loopTime - lastBlinkTime ) > 500 ) {
      				
      				// Changement état
      				if ( ledState == LOW ) {
      					ledState = HIGH;
      				} else {
      					ledState = LOW;
      				}
      				
      				// Et surtout, on n'oublie pas de mettre à jour lastBlinkTime
      				lastBlinkTime = loopTime;
      			
      			}
      		
      		}
      	
      	// Sinon (bouton HIGH), on est en mode chronomètre (led on/off)
      	} else {
      		
      		// Si millis() a changé, on met à jour timeLeft
      		if ( loopTime != lastLoopTime ) {
      		
      			// Soustraction du temps écoulé
      			timeLeft -= ( loopTime - lastLoopTime );
      			
      			// Petite protection pour ne pas descendre en dessous de 0
      			if ( timeLeft < 0 ) {
      				timeLeft = 0;
      			}
      			
      		 }
      		 
      		 // Calcul de l'état de la led en fonction du timer
      		if ( timeLeft > 0 ) {
      			ledState = HIGH;
      		} else {
      			ledState = LOW;
      		}
      		
      	}
      	
      	// Affectation de l'état de la led
      	digitalWrite(ledPin, ledState);
      	
      	// Affectation de lastLoopTime
      	lastLoopTime = loopTime;
      	
      }

      Je te laisse adapter un peu pour rajouter la gestion du serial sans les delay !

      Pour ce faire, tu auras surement besoin d'un variable lastSerialTime

      Tu remarqueras que je ne fais aucun delay ;)

      La fonction loop tourne en boucle donc le programme va tester le bouton, faire les calculs de temps et affecter la led des millions de fois par secondes et donc être très réactif !

      -
      Edité par lorrio 19 juillet 2014 à 11:22:22

      • Partager sur Facebook
      • Partager sur Twitter
        19 juillet 2014 à 16:20:56

        D'accord merci, donc c'est les delay qui plombent tout mon code! -_-
        • Partager sur Facebook
        • Partager sur Twitter
          24 août 2014 à 15:29:49

          salut! :D

          Ayant pratiquement terminé mon projet, je suis face à un problème de taille qui m'empêche de terminer. Mon problème se situe autour d'opérations sur le Timer. Je souhaiterais qu'avec mon code que vous pouvez voir ci-dessous, démarrer la fonction millis() lorsque mon bouton poussoir est enfoncé et que lorsque je le relâche, la dernière valeur de millis() de la première condition soit sauvegardée lorsque le bouton serait relâché pour être réinjectée lorsque le bouton sera renfoncé 

          const int button = 4;
          int button_state;
          unsigned long val_stock;
          
          
          void setup()
          {
          
          	 pinMode(button, INPUT);
          	 Serial.begin(9600);
               val_stock = 0;
          }
          
          void loop()
          {
          	
          unsigned long temps;
          
          	 if (button_state == LOW) // si le bouton est enfoncé
          	 {
          		 unsigned long chrono = millis(); // on initialise le chronomètre
          		 chrono = chrono / 1000; // convertit millisecondes en secondes
          		 
          		 temps = val_stock + chrono; /* additionne la valeur stockée par "val_stock" 
          		                                (si le bouton a été relâché, ou dans le cas
          										contraire, la valeur stockée est égale à 0 */
          		 
          		 
          	 }
               
          	 else if (button_state  == HIGH) // sinon si le bouton n'est pas enfoncé ou relâché
          	 {
          		 val_stock = temps; /* on recupère le contenu de la variable "temps"
          		                       pour la copier dans "val_stock" qui sera utilisée lorsque
          							   le bouton sera enfoncé */
          		 
          		 
          	 }
          }

          Cependant, je ne trouve pas le moyen de sauvegarder la dernière valeur de la variable "temps" lorsque je passe dans le HIGH. L'idéal serait de sauvegarder "val_stock" dans une variable en RAM qui ne bouge pas comme si elle était en EEPROM (j'avais aussi pensé à l'enregistrer en EEPROM mais je ne pense pas que ce soit la bonne solution), après j'avais aussi pensé à carrément mettre le Timer0 en pause mais cela perturberait le reste de mon programme, notamment le clignotement des leds. Donc si quelqu'un a une idée ce serait vraiment sympa :)

          Merci d'avance à tous!

          -
          Edité par tone5846 24 août 2014 à 15:32:28

          • Partager sur Facebook
          • Partager sur Twitter
            Staff 24 août 2014 à 16:27:18

            Le code tel qu'il est ne s'exécute pas sur un changement d'état mais sur un état.

            En clair, ton arduino qui tourne à 8 MHz va entré plusieurs millions de fois par second dans le if, ou le else.

            Or, faire plusieurs millions d'initialisation ou de sauvegarde par seconde, je ne pense pas que c'est ce que tu veux faire.

            Il te faut donc gérer une sauvegarde de l'état du bouton :

            int etatBtnPrecedant;
            int etatBtnActuel;
            
            void loop() {
            
                // Lecture du bouton
                etatBtnActuel = digitalRead(...);
            
                // Si l'ancien état est HIGH et que le nouveau est LOW
                // Cela signifie que le bouton vient d'être enfoncé
                // => Le contenu de ce if est exécuté qu'une seule fois
                if ( etatBtnPrecedant == HIGH && etatBtnActuel == LOW ) {
                    ...
                }
            
                // Si le nouveau état est LOW
                // Cela signifie simplement que le bouton est enfoncé
                // Il peut donc s'agir d'un appui ou simplement d'un maintient enfoncé
                // => Le contenu de ce if est exécuté des millions de fois
                if ( etatBtnActuel == LOW ) {
                    ...
                }
            
                // Si l'ancien état est LOW et que le nouveau est HIGH
                // Cela signifie que le bouton vient d'être relaché
                // => Le contenu de ce if est exécuté qu'une seule fois
                if ( etatBtnPrecedant == LOW && etatBtnActuel == HIGH ) {
                    ...
                }
            
                // Si le nouveau état est HIGH 
                // Cela signifie simplement que le bouton n'est pas enfoncé
                // => Le contenu de ce if est exécuté des millions de fois
                if ( etatBtnActuel == HIGH ) {
                    ...
                }
            
                // Et surtout, on n'oublie pas cette ligne avant la fin du loop
                // Parce que si on ne la met pas, ça ne marchera pas !
                etatBtnPrecedant = etatBtnActuel;
            
            }



            • Partager sur Facebook
            • Partager sur Twitter
              24 août 2014 à 18:35:05

              Merci d'avoir répondu aussi rapidement ;)

              J'ai essayé avec la méthode que tu m'a donné mais aucune réactivité lorsque j'appuie sur le bouton, j'ai fais le test pour contrôler avec la fenêtre série, je n'ai absolumment aucune idée d'ou cela pourrait venir, j'ai vérifié mon code plusieurs fois... Peut être que "val_stock = temps" n'est pas mémorisé mais cela serait bizarre...

              const int button = 4;
              int button_state;
              unsigned long val_stock;
              
              int etatBtnPrecedant;
              int etatBtnActuel;
              
              unsigned long temps;
              unsigned long chrono = millis();
              
              void setup()
              {
              
                pinMode(button, OUTPUT);
                Serial.begin(9600);
                val_stock = 0;
                chrono = 0;
              }
              
              void loop()
              {
              
                 etatBtnActuel = digitalRead(button);
                 
                
                  if ( etatBtnPrecedant == HIGH && etatBtnActuel == LOW ) // bouton vient d'être enfoncé (code executé qu'une seule fois)
              	{
              	    chrono = 0;
              		
                  }
                  
                  
                  if ( etatBtnActuel == LOW ) // bouton simplement enfoncé (code executé en boucle)
              	{
              	    chrono = chrono / 1000;
              		temps = val_stock + chrono;
              		Serial.println(temps);
              		// actions quelconque ex: allumer moteur
                  }
                  
                 
                  if ( etatBtnPrecedant == LOW && etatBtnActuel == HIGH ) // bouton vient d'être relâché (code executé qu'une seule fois)
              	{
              		val_stock = temps;
              	}
              	    
                  
                 
                  if ( etatBtnActuel == HIGH ) // bouton n'est simplement pas enfoncé (code executé en boucle)
              	{
              	    // action quelconque ex: faire clignoter led 
              		
                  }
                  
                  
                  etatBtnPrecedant = etatBtnActuel;
              
              }
              



              • Partager sur Facebook
              • Partager sur Twitter
                Staff 24 août 2014 à 19:14:53

                Une petite initialisation des variables au début pourrait être utile.

                int etatBtnPrecedant = HIGH;
                int etatBtnActuel = HIGH;

                Maintenant, si je te dis que ton arduino te spam de 0, je me trompe ?

                A vrai dire, c'est logique :

                Dans le if == LOW (qui je le rappelle, est exécuté des millions de fois par secondes quand le bouton est enfoncé), tu fais chrono = chrono / 1000; donc peu importe la valeur de chrono, celle-ci vaudra 0 en une fraction de secondes.

                Si c'est juste un chrono qui défile lorsque le bouton est enfoncé, pas besoin de faire une machine à gaz, quelques utilisations de millis bien placé et c'est gagné ;)

                const int button = 4;
                
                unsigned long currentMillis = 0;    // Millis actuel
                unsigned long lastMillis = 0;       // Millis sauvegardé
                unsigned long elapsedMillis = 0;    // Millis écoulé entre currentMillis et lastMillis
                
                unsigned long counter = 0;          // Valeur du chrono
                unsigned long counterPrint = 0;     // Valeur du chrono lors du dernier print
                
                void setup() {
                    pinMode(button, INPUT);
                    Serial.begin(9600);
                }
                
                void loop() {
                    
                    // Mise à jour des temps currentMillis, elapsedMillis et lastMillis
                    // Note : vu que loop est exécutée des millions de fois par seconde, dans 99% des cas, 
                    //        currentMillis aura la même valeur que lastMillis donc elapsedMillis vaudra 0
                    currentMillis = millis();
                    elapsedMillis = ( lastMillis - currentMillis );
                    lastMillis = currentMillis;
                    
                    // Si le boutopn est enfoncé, on fait tourné le chrono
                    if ( digitalRead(button) == LOW ) {
                        
                        // Ajout du temps écoulé
                        counter += elapsedMillis;
                        
                        // Affichage de la valeur toutes les secondes
                        if ( ( counterPrint + 1000 ) < counter ) {
                        
                            Serial.println( counter / 1000 );
                            
                            counterPrint = counter;
                            
                        }
                        
                    }
                    
                }

                Si tu fais beaucoup d'appels de fonction assez lourde en temps CPU (Serial.print par exemple), je te conseille de remplacer la ligne 35 par counterPrint = counter - ( counter % 1000 ); afin d'éviter d'accumuler des offset de temps sur tes prints

                -
                Edité par lorrio 24 août 2014 à 19:17:19

                • Partager sur Facebook
                • Partager sur Twitter
                  24 août 2014 à 21:02:11

                  Oui en effet je veux juste faire un chrono qui défile lorsque le bouton est enfoncé ^^ Mais du coup je voudrais que quand je relâche le bouton, le chrono se fige et reprenne ou il s'est arrêté quand je réappuie dessus et j'arrive pas a determiner si le code que tu m'a proposé au-dessus fait ça?

                  Et encore merci de prendre de ton temps pour m'aider ;)

                  • Partager sur Facebook
                  • Partager sur Twitter
                    25 août 2014 à 10:13:43

                    Franchement merci beaucoup! Ton code fonctionne super bien, tu m'enlève une grosse épine du pied ;)
                    • Partager sur Facebook
                    • Partager sur Twitter
                      31 août 2014 à 10:48:53

                      Salut,

                      si ton souci est résolu, pense à passer le topic comme tel, cela pourrait aider quelqu'un ayant le même problème que toi.

                      Bonne continuation.

                      • Partager sur Facebook
                      • Partager sur Twitter

                      Stringman devient Bonhomme !! | Jeux de plateforme : Nouvelle Démo. (màj : 01 Juin 2020)

                        5 mai 2020 à 12:33:40

                        bonjour les amis; je veux faire un lavage de main automatique. j'utilise un capteur infrarouge et je fais le code avec la fonction millis mais je n'arrive pas à réussir; aidez moi voici mon code

                         int inputPin = 8;               

                                  int val = 0;

                              long temps = 1000;

                              boolean etat = 0;

                                  void setup() 

                                  {

                                pinMode(inputPin, INPUT); 

                                pinMode(2,OUTPUT);

                                pinMode(3,OUTPUT); 

                                  }

                                  void loop(){

                                    val = digitalRead(inputPin); 

                                    if (val == HIGH) 

                                    {  

                                      digitalWrite(2,HIGH);

                                    }

                                    else

                                    {

                                    digitalWrite(2,LOW);  

                                      digitalWrite(3,LOW);  

                                 }  

                                        if ( (millis() - temps) < 1000 )

                                    {

                                    etat = !etat;

                                    digitalWrite(3, etat);

                                    temps = millis();

                                    }

                        • Partager sur Facebook
                        • Partager sur Twitter
                          Staff 5 mai 2020 à 19:47:05

                          Avec un code bien indenté et les balises codes, c'est tout de suite bien plus lisible :

                          int inputPin = 8;
                          
                          int val = 0;
                          long temps = 1000;
                          boolean etat = 0;
                          
                          
                          void setup() {
                          	pinMode(inputPin, INPUT); 
                          	pinMode(2,OUTPUT);
                          	pinMode(3,OUTPUT); 
                          }
                          
                          
                          void loop() {
                          
                          	val = digitalRead(inputPin); 
                          
                          	if (val == HIGH) {
                          	
                          		digitalWrite(2,HIGH);
                          	
                          	} else {
                          
                          		digitalWrite(2,LOW);  
                          		digitalWrite(3,LOW);  
                          
                          	}  
                          
                          	if ( (millis() - temps) < 1000 ) {
                          		etat = !etat;
                          		digitalWrite(3, etat);
                          		temps = millis();
                          	}
                          
                          }

                          A voir ton programme, celui-ci se décompose en 2 parties :

                          • La gestion de l'input et les affectations qui en découlent
                          • La gestion du timer avec le clignotement

                          Concernant le bouton :

                          • Si ton input et HIGH, alors la pin 2 est passée à HIGH
                          • Et sinon, alors la pin 2 et 3 sont passées à LOW

                          Et en parallèle de ça, il y a la gestion du timer qui fait clignoter la pin 3 toutes les secondes.

                          Mais il y a comme qui dirait un problème car a fonction loop est exécutée en boucle donc juste après le clignotement du timer, si l'input est à l'état LOW, alors la pin 3 est forcée à l'état LOW.

                          Donc à moins que ton input soit toujours à l'état HIGH, ton timer ne sert strictement à rien car toutes ses actions sont annulées juste après.

                          Que souhaites tu faire exactement ???

                          • Partager sur Facebook
                          • Partager sur Twitter

                          timer qui démare tout seul...

                          × Après avoir cliqué sur "Répondre" vous serez invité à vous connecter pour que votre message soit publié.
                          • Editeur
                          • Markdown