Tempo temps reel double avec millis()

bonjour a tous

j'ai besoin dans un programme d'avoir deux tempos differentes. j'utilise la fct millis() mais j'ai quelques soucis.

1- j'ai l'impression que la tempo fait un peu ce qu'elle veut (meme si je n'en mets qu'une)... si je teste "lentement" j'ai bien ma tempo mais si par exemple je teste plusieurs fois dessuite le tempo n'est plus respectée (elle est tres courte voire inexistante)

2- Avec 2 tempo dans le meme programme c'est encore pire! et encore une fois les tempos ne sont pas respectés tout le temps

voila un bout de programme pour illuster mon soucis

/* test tempo */

#define bouton1 31
#define bouton2 30
#define bouton3 29

#define action1 1
#define action2 2
#define action3 3

int BT_1_2 = LOW;
int BT_1_3 = LOW;

long previousMillis_1 = 0;
long previousMillis_2 = 0;

long delay_1 = 1000;
long delay_2 = 3000;

void setup() {

pinMode(action1, OUTPUT);
pinMode(action2, OUTPUT);
pinMode(action3, OUTPUT);
pinMode(bouton1, INPUT);
pinMode(bouton2, INPUT);
pinMode(bouton3, INPUT);
}

void loop(){

int et_bouton1 = digitalRead(bouton1);
int et_bouton2 = digitalRead(bouton2);
int et_bouton3 = digitalRead(bouton3);

BT_1_2 = (!et_bouton1 && !et_bouton2);
BT_1_3 = (!et_bouton1 && !et_bouton3);

if (BT_1_2 == HIGH)
{
digitalWrite(action1, BT_1_2);
unsigned long currentMillis_1 = millis();

if (currentMillis_1 - previousMillis_1 > delay_1)
{
previousMillis_1 = currentMillis_1;
digitalWrite(action2, BT_1_2);
}
}
else
{
digitalWrite(action1, LOW);
digitalWrite(action2, LOW);
}

if (BT_1_3 == HIGH)
{
digitalWrite(action1, BT_1_3);
unsigned long currentMillis_2 = millis();

if (currentMillis_2 - previousMillis_2 > delay_2)
{
previousMillis_2 = currentMillis_2;
digitalWrite(action3, BT_1_3);
}
}
else
{
digitalWrite(action1, LOW);
digitalWrite(action3, LOW);
}
}

Merci de votre aide

        if(currentMillis_1 - previousMillis_1 > delay_1)

à remplacer par

        if(currentMillis_1 > (previousMillis_1 + delay_1))

pour prendre en compte le problème du débordement de millis au bout d'un moment

long previousMillis_1 = 0;
long previousMillis_2 = 0;

à remplacer par

unsigned long previousMillis_1 = 0;
unsigned long previousMillis_2 = 0;

car millis() retourne un unsigned long et non un long

Comme on ne sait pas vraiment quel comportement tu attends lors de l'appui sur les boutons on ne peut pas t'aider beaucoup. Un petit organigramme, une explication claire de l'attendu serait la bien venue.

Par contre on peut déjà dire que comme tu n'as aucun code qui prenne en compte le rebond des boutons tu peux avoir des transitions successives qui induisent un comportement inattendu.

Ensuite les if.. else ... imbriqués ne sont pas toujours très sûr. Une petite machine à état est souvent plus clair dans son fonctionnement.

Merci de ton aide

j'ai fait ce programme simple (qui est la version extra light de mon programme final) afin d'illustrer mon soucis

ce programme (de test) devrait:

  • si j'appuie sur n'importe quel bouton cela ne fait rien
  • si bt 1 et bt2 sont activés ==> action1 activé puis action2 s'active apres 2sec. le tout s’arrête dès qu'un bouton est relâché
  • si bt 1 et bt3 sont activés ==> action1 activé puis action3 s'active apres 3.5sec. le tout s'arrete dès qu'un bouton est relâché

le soucis est qu'actuellement la tempo n'est pas respectée à tous les coups. Souvent les deux actions s'activent en meme temps!

sinon pour être plus précis, le "vrai" programme utilise:

  • la première tempo pour activer un embrayage X secondes après avoir accélérer le moteur (avec un servomoteur)
  • la deuxième tempo pour couper l'alimentation générale du système X secondes après la détection de coupure d'alimentation du moteur (ceci afin de remettre le servomoteur d’accélération en position initiale)

je peux mettre le programme complet mais il est assez long et ca risque de compliquer les choses pour rien. (mais je peux le poster si tu préfères)

merci de ton aide

fdufnews:

        if(currentMillis_1 - previousMillis_1 > delay_1)

à remplacer par

        if(currentMillis_1 > (previousMillis_1 + delay_1))

pour prendre en compte le problème du débordement de millis au bout d'un moment

Non, son code d'origine est correct ( voir Arduino Playground - HomePage ), sauf qu'il faut remplacer > par >= pour que le délai soit 1000 et non 1001

les deux code fonctionnent sans soucis

par contre j'ai peur que le >= ne fonctionnent pas car c'est un cas particulier qui arrive qu'un bref instant, non?

  • si j'appuie sur n'importe quel bouton cela ne fait rien
  • si bt 1 et bt2 sont activés ==> action1 activé puis action2 s'active apres 2sec. le tout s’arrête dès qu'un bouton est relâché
  • si bt 1 et bt3 sont activés ==> action1 activé puis action3 s'active apres 3.5sec. le tout s'arrete dès qu'un bouton est relâché

Les rebonds peuvent faire croire au relâché d'un des boutons.

Non ca veut juste dire "supérieur ou égal".

Ex:

condition       resultat

(1000 > 1000)   false
(1001 > 1000)   true

(1000 >= 1000)  true
(1001 >= 1000)  true

Je pense que ton problème c'est que tu n'utilise pas de technique de "debounce" pour tes boutons.

ok, j'avais regarder comment faire ce debounce, le soucis est que j'ai 16 entrées et que cela va compliqué enormenent le programme :s

Je ne connais pas la précision nécessaire, mais tu peux filtrer les parasites de début ou de fin de commutation en créant une base de temps de 100ms par exemple.

Ca donne un truc du genre :

if (previousMillis >= millis + 100) {
    previousMillis = millis();
    top100ms = HIGH;           // monte un cycle toutes les 100ms
    }

if (top100ms && !et_bouton1 && !et_bouton2) tps1++;
if (et_bouton1 || et_bouton2) tps1 = 0 ;

if (tps1 >= delay_1) {
       digitalWrite(action2, BT_1_2); // ce que tu veux faire comme action
        tps1 = 0;                             // RAZ de la tempo
      }


//En fin de loop, tu mets 
  top100ms = LOW;

je vais tester merci

je viens de tester l'antirebond, ce n'est pas cela.
je dois avoir une boucle if qui ne dois pas etre au point ce qui provoque le "shunt" de la tempo

Je t'ai fait faire une connerie, je viens de regarder mes prog, moi je fais çà

if (millis() >= previousMillis ){
         previousMillis += 100;
         top100ms = HIGH;         
         }

J'aurais plutôt abordé le problème sous cet angle :

unsigned long Depart;
unsigned long TempsEcoule; 

...

if(digitalRead(bouton1)==HIGH && digitalRead(bouton2)==HIGH) {

Action1(1);

Depart=millis();
while(millis()<(Depart+delay) && digitalRead(bouton1)==HIGH && digitalRead(bouton2)==HIGH) TempsEcoule=millis()-Depart;

if(TempsEcoule>=35000) {

Action3(1);
while(digitalRead(bouton1)==HIGH && digitalRead(bouton2)==HIGH);
Action3(0);

} 

Action1(0);

}

Pareil pour l'autre combinaison.

ce qu'il y a de bien avec la programmation, c'est qu'il y a autant de facon e faire une action qu'il y a de programmeur!

merci de votre aide, j'apprends bcp