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 !
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
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;
}
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;
}
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
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
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
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.
× Après avoir cliqué sur "Répondre" vous serez invité à vous connecter pour que votre message soit publié.
× Attention, ce sujet est très ancien. Le déterrer n'est pas forcément approprié. Nous te conseillons de créer un nouveau sujet pour poser ta question.
Bonhomme !! | Jeu de plateforme : Prototype.