comment faire une tempo pour un affichage

Bonjour
il y a quelques temps j'ai sollicité votre aide
https://forum.arduino.cc/index.php?topic=574440.0
Mais je suis a nouveau confronté a un autre problème:

  • appuie bouton 1 = incrémente ma variable.
  • appuie bouton 2 = décrémente ma variable.
  • appuie sur les deux boutons = envoie mes données vers l'écran de débug.
  • appuie de nouveau sur les deux boutons = sortie du mode 'envoie vers écran' de débug.

Mon soucis c'est que quelques fois en sortant (donc appuie sur mes deux boutons) j'incrémente ou décrémente ma variable.

Je cherche donc une solution simple, peut être une tempo pour que lorsque je quitte le mode d'affichage ce dernier reste encore actif afin de bien vérifier la valeur de ma variable (qui est affichée sur cet écran).

pour l'instant voila comment je m'y prend (grand débutant)

initialisation:

int pinBouton1 = 11; // Bouton  1 branché sur le pin 11
int pinBouton2 = 12; // Bouton  2 branché sur le pin 12

void setup() {
  //définition des modes
  pinMode(pinBouton1, INPUT_PULLUP);
  pinMode(pinBouton2, INPUT_PULLUP);
  Serial.begin(9600);  
}

Puis dans mon Loop:

 boolean etatBouton1 = digitalRead(pinBouton1);
  boolean etatBouton2 = digitalRead(pinBouton2);
  if (etatBouton1 == LOW) //test si bouton 1 appuyé pour decrementer
  {
    Decrementation ();
  }

  if (etatBouton2 == LOW) //test si bouton 2 appuyé pour incrementer
  {
    Incrementation();
  }

  if (etatBouton1 == LOW && etatBouton2 == LOW)// teste si  2 boutons appuyees
  {
    AllumeEcran ();
  };

mes sous routines pour tester:

void AllumeEcran (void) {
  led_allumee = !led_allumee; //inversion du bouléen
  digitalWrite(pin_led, led_allumee ? HIGH : LOW);
}

void Decrementation (void) {
  MaVarible = MaVarible - 0.10;
  Serial.print("variable decremente : ");
  Serial.println(MaVarible , 2);
  delay(500);
}

void Incrementation (void) {
  MaVarible = MaVarible + 0.10;
  Serial.print("variable incremente : ");
  Serial.println(MaVarible , 2);
  delay(500);
}

Donc je fait juste la mise au point sur ce petit bout de code avant de l'intégrer.

Pour simuler L'envoie ou non vers l'écran j'allume simplement la led 13.
Tout marche a peu près comme je le voudrais, sauf que je n'arrive pas a trouver une solution simple pour maintenir en fonction mon affichage d'écran (pour test ma led 13) quelques secondes apres avoir fait un appuie simultané sur mes deux boutons.

Je suis preneurs de pistes. Merci par avance
Alain

Ton problème se situe au niveau de la lecture des boutons : elle se fait si rapidement que lorsque tu appuies sur les deux "à la fois" (c'est à dire pour toi, qui n'est qu'un humain donc bien moins rapide qu'un Arduino), le petit intervalle de temps entre l'appui sur le premier et l'appui sur le second permet à l'Arduino d'exécuter des instructions. Par exemple, supposons que tu appuies sur le bouton 1 d'abord puis sur le 2 en pensant appuyer sur les 2 en même temps.

L'Arduino capte l'appui sur le 1 et ne voit pas encore l'appui sur le 2 : il exécute tes tests et décrémente, possiblement plusieurs fois (ça dépend du reste du programme qui peut le ralentir par ailleurs). Puis il capte l'appui sur le 2 : pour lui, les 2 boutons sont appuyés : il allume alors l'écran. Mais entre temps il y a eu une décrémentation...

Pour éviter ça, tu dois lire les boutons de manière différente et faire attendre l'Arduino un petit moment pour qu'il s'assure que tu n'appuies que sur un seul bouton.
Un pseudo code :

lire bouton 1
lancer un chrono
tant que le chrono est inférieur au temps d'attente : lire le bouton 2
traiter en fonction de l'état des 2 boutons

Le temps d'attente doit être réglé en fonction de ta vitesse d'appui sur les deux boutons (c'est un peu l'équivalent d'un double clic sur une souris : si la souris n'attend pas un petit peu pour savoir si tu cliques une fois ou deux fois, elle ne captera jamais le double clic). Je pense que 100 ms est suffisant, peut-être même un peu trop. A régler...

bonsoir a tous.

merci pour cette réponse:

Ton problème se situe au niveau de la lecture des boutons : elle se fait si rapidement que lorsque tu appuies sur les deux "à la fois" (c'est à dire pour toi, qui n'est qu'un humain donc bien moins rapide qu'un Arduino), le petit intervalle de temps entre l'appui sur le premier et l'appui sur le second permet à l'Arduino d'exécuter des instructions. Par exemple, supposons que tu appuies sur le bouton 1 d'abord puis sur le 2 en pensant appuyer sur les 2 en même temps.

oui. C'est exactement ce que j'ai pensé.
Par contre je ne voit pas comment y remédier simplement.D'ou l'idée de contourner ce soucis par un affichage temporisé afin d'avoir le temps de contrôler la valeur de la variable.

Et pire encore je ne saisi pas l'explication donnée!

j'imagine que c'est dans le "code" de test sur un seul bouton qu'il faut que je réfléchisse!
Je dois dire au prog d'attendre avant de faire quelque chose de vérifier si je ne serais pas dans le cas du test a deux boutons pressées?
Je nage.... Je flotte!!
Alain

Bonsoir,

Si tu veux garder la structure de ton programme, je plus simple est de faire une petite pause en entrant dans les fonctions incrementation() et decrementation(), puis de regarder si l'autre bouton est pressé.
Si c'est le cas tu appelles ta fonction allumeEcran() suivi d'un return pour sortir de ta première fonction.
Juste une petite remarque, sans delay (à l'identique des deux autres fonctions) dans ta fonction allumeEcran(), ça va faire sapin de Noël.

Je t'encourage néanmoins à utiliser la fonction millis() pour la gestion du temps dans tes prochains programmes.

Ce que j'appelle un chrono, c'est en effet l'utilisation de la fonction millis : elle compte les millisecondes depuis le boot de l'Arduino.

Ça utilise une variable de type unsigned long :

unsigned long chrono;

Dans la loop, après avoir lu le bouton 1:

 boolean etatBouton1 = digitalRead(pinBouton1);

Tu initialises le chrono :

chrono = millis();

Et tant que le chrono est inférieur au délai, tu lis le bouton 2:

while (chrono < temporisation) etatBouton2 = digitalRead(pinBouton2);

temporisation aura été défini plus haut:

#define temporisation 50

la variable etatBouton2 doit avoir été définie en boolean auparavant.
Maintenant, tu fais tes tests comme dans ton code.

  if (etatBouton1 == LOW && etatBouton2 == HIGH) Decrementation ();
  if (etatBouton1 == HIGH && etatBouton2 == LOW) Incrementation();
  if (etatBouton1 == LOW && etatBouton2 == LOW) AllumeEcran ();

A tester...

bonsoir
Vraiment merci pour tous ces conseils.
Je ne peux vous remercier qu'en réussissant.
Je vais donc en début de semaine tester tout ça bien tranquillement et revenir vers vous pour vous dire si cela fonctionne ou si j'ai raté une marche.
Mon soucis étant de retrouver le sujet.
Sur ce forum j'ai bien du mal a suivre les sujets anciens.
Merci
Alain

Re bonsoir
je viens de réfléchir!
Est ce que je dois comprendre comme cela?

↓ signifie: bouton pressé.

lecture du bouton :

si:
1 =↑ 
tempo qui me permet de m'assurer de la position du bouton 2 (appuyé ou pas)
2 =↓
je me trouve en présence  de bouton 2


si:
1 =↓
tempo qui me permet de m'assurer de la position du bouton 2
2 =↑
je me trouve en présence  de bouton 1


et si je cherche a appuyer simultanément les deux boutons:
1 =↓
tempo qui me permet de m'assurer de la position du bouton 2
2 =↓
je me trouve en présence  de l'appuie simultané sur les deux bouton

Votre cheminement est comme cela?

Il faut faire une machine à état...

Vous avez 2 états pour vos boutons, Bouton 1/2 Appuyé, Bouton 1/2 Relâché qu’on note B1A, B1R et B2A,B2R

L’état de votre système dépend de la combinaison des états, du chemin suivi et d’un temps à définir) passé dans un certain état pour valider cet état et déclencher les actions associées

État initial B1R_B2R
Transitions possibles vers B1R_B2R —> B1R_B2A ou B1A_B2R ou B1A_B2A

De B1R_B2A —> B1R_B2R ou B1A_B2A ou Timeout
De B1A_B2R —> B1R_B2R ou B1A_B2A ou Timeout
De B1A_B2A —> B1R_B2A ou B1A_B2R ou B1R_B2R ou Timeout

En supposant que vous ayez supprimé les rebonds, vos actions dépendent d’un chemin
B1R_B2R —> B1A_B2R —> B1R_B2R {action appui B1}
B1R_B2R —> B1A_B2R —> Timeout {action appui B1}

B1R_B2R —> B1R_B2A —> B1R_B2R {action appui B2}
B1R_B2R —> B1R_B2A —> Timeout {action appui B2}

B1R_B2R —> B1A_B2A : {action appui 2 boutons}
B1R_B2R —> B1A_B2R —> B1A_B2A {action appui 2 boutons}
B1R_B2R —> B1R_B2A —> B1A_B2A {action appui 2 boutons}

Il faut traiter les cas ou l’utilisateur fait des choses inattendues, Par exemple ne pas relâcher le bouton après l’action et appuyer l’autre:

B1R_B2R —> B1A_B2R —> Timeout {action appui B1} —> B1A_B2A {action ?}

ici doit-on déclencher l’action 2 boutons ? ==> si une action a été effectuée le système doit-il (c’est un choix) attendre de revenir à B1R_B2R avant de recommencer ?

Vous pouvez aussi décider que tenir le bouton appuyé répète l’action
B1R_B2R —> B1A_B2R —> Timeout {action appui B1} —> Timeout {action appui B1} —> Timeout {action appui B1}

Bref à vous de voir quand on est dans un état donné ce qu’il peut se produire (timeOut et changement d’état des boutons) et décider des éléments de mémoire ou états et actions à déclencher. Sans cette étape de spécification fonctionnelle vous ne pouvez pas coder proprement le comportement de votre système.

C'est vrai que j'ai supposé que le bouton 1 était pressé en premier, ce qui n'est pas forcément le cas.
La méthode proposée par J-M-L est la meilleure mais peut-être pas la plus simple.

Une autre possibilité serait de lire les deux boutons pendant le temps de temporisation et d'agir ensuite:

unsigned long chrono = millis();
boolean etatBouton1 = HIGH;
boolean etatBouton2 = HIGH;
while (millis()-chrono < temporisation) {
  if (etatBouton1 == HIGH) etatBouton1 = digitalRead(pinBouton1);
  if (etatBouton2 == HIGH) etatBouton2 = digitalRead(pinBouton2);
  }
if (etatBouton1 == LOW && etatBouton2 == HIGH) Decrementation ();
if (etatBouton1 == HIGH && etatBouton2 == LOW) Incrementation();
if (etatBouton1 == LOW && etatBouton2 == LOW) AllumeEcran ();

Ça devrait fonctionner mieux qu'avant. Et les rebonds sont traités automatiquement.

@lesept

Le soucis avec votre approche c’est que ça ne traite pas le relâchement du bouton donc auto repeat et on pourrait avoir des trucs bizarre si je presse B1 j’attends le délai (donc action déclenchée) et je presse B2 et je relâche B1 pendant le délai - je rate la double pression

Si le cahier des charges est clair et simple on peut bien sûr simplifier la machine

(et les Boolean c’est true ou false pas HIGH ou LOW:) )

J-M-L:
si je presse B1 j’attends le délai (donc action déclenchée) et je presse B2 et je relâche B1 pendant le délai - je rate la double pression

Non, j'ai mis des tests dans la boucle d'attente du délai pour éviter ça. A chaque fois que la loop redémarre, l'état de B1 est remis à HIGH, puis on entre dans la boucle : le bouton est testé (puisque état HIGH) et l'appui est pris en compte. On arrête alors de le tester donc on ne voit pas le relâchement.
... ou bien j'ai mal compris ta remarque ...

(et les Boolean c’est true ou false pas HIGH ou LOW:) )

C'est vrai, mais ça marche aussi comme ça. C'est pour éviter que notre ami se pose des questions si je mettais true/false dans les initialisations et HIGH/LOW dans les tests.

Mais c'est vrai qu'un problème qui semble simple a priori, peut devenir complexe à spécifier et donc à réaliser si on veut prendre en compte toutes les possibilités.

Ah ok

j'avais mal lu (sur mon portable) le code - et je pensais que les déclaration des booléens étaient en global et que vous mettiez le code qui suivait dans la loop (donc pas de réinitialisation à HIGH)

Oui comme ça ça fait le job pour un usage simple (et un break pour éviter d’attendre si les 2 boutons sont LOW gagnerait un peu de temps)

bonjour
Merci pour toutes vos remarques.
Effectivement le code qui m'a ete proposé en premier semble plus a am portée, ou a la portée d'un débutant.

Mais c'est vrai qu'un problème qui semble simple a priori, peut devenir complexe à spécifier et donc à réaliser si on veut prendre en compte toutes les possibilités.

Ha! oui!!
Le soucis lorsque l'on débute c'est que sans expériences il est difficile d'avoir une vision globale. Donc quelquefois on part dans la seule direction que l'on trouve, puis on s'aperçoit que ça ne fonctionne pas toujours comme prévu, et d'amélioration en amélioration ce qui était a première vue simple devient ingérable (toujours pour un débutant)
Par exemple je me demande si comme je ne suis ni limité en place ni en entrée 3 boutons ne seraient pas plus simple.
C'est une illustration de la remarque que vous faite plus haut.

Ceci dit je vais essayer ce bout de code la et je reviens vers vous.
Et si je n'arrive pas simplement je placerais un troisièmement bouton.
Merci

unsigned long chrono = millis();
boolean etatBouton1 = HIGH;
boolean etatBouton2 = HIGH;
while (millis()-chrono < temporisation) {
  if (etatBouton1 == HIGH) etatBouton1 = digitalRead(pinBouton1);
  if (etatBouton2 == HIGH) etatBouton2 = digitalRead(pinBouton2);
  }
if (etatBouton1 == LOW && etatBouton2 == HIGH) Decrementation ();
if (etatBouton1 == HIGH && etatBouton2 == LOW) Incrementation();
if (etatBouton1 == LOW && etatBouton2 == LOW) AllumeEcran ();

La question que je me pose:
Est ce que le code ci dessus ralenti ma boucle loop.
si oui
Est ce qu'il est envisageable de ne faire qu'un seul test:

  • je part du principe que mes boutons sont toujours au repos
  • si bouton 1 ou bouton 2 sont différent de leur position repos
    alors je part dans le test ci dessus

Le code que j'ai est un wattmètre qui me sert a router mon courant pour ne pas injecter (autoconsommation)
sans gestion de modification de variable chaque tours se fait en 20 millisecondes.

bonjour, enfin re.
Décidément je suis trop débutant.
J'interprète mal cette remarque.

et je pensais que les déclaration des booléens étaient en global et que vous mettiez le code qui suivait dans la loop (donc pas de réinitialisation à HIGH)

vous voulez dire que vous pensiez que
boolean etatBouton1 = HIGH;
boolean etatBouton2 = HIGH;
se trouvaient avant le setup?
Merci

C'est bien ça.

Le ralentissement sera dû à la durée de la temporisation : si tu penses que tu peux appuyer sur les deux boutons en un temps inférieur à 100 ms, tu ajoutes avant le setup :

#define temporisation 100

Le plus simple est d'essayer avec différentes valeurs : tu commences à 300 puis tu diminues (200, 150, 100, 80, 70, 60...) jusqu'à ce que la détection de l'appui double devienne moins précise voire aléatoire.

Le code que j'ai est un wattmètre qui me sert a router mon courant pour ne pas injecter (autoconsommation) sans gestion de modification de variable chaque tours se fait en 20 millisecondes.

J'ai du mal à comprendre : tu produits de l'électricité que tu consommes. Que viennent faire les 20 ms ? Qu'entends-tu par "sans gestion de modification de variable" ?

Je pense que 100 ms ne changeront pas ta facture d'électricité... Sinon, sors ton gilet jaune ! :grin:

bonjour
Alors, quelques explications.
J'ai installé chez moi deux Panneaux photovoltaïque.
il existe chez ERDF une formule appelée: autoconsommation.
c'est a dire que l'on consomme ce que l'on produit.
En règle générale le but est d'effacer son "bruit de fond" donc la puissance installée est modeste. Dans mon cas deux panneaux de 180Wc.

Donc environ 300W dans le meilleur des cas raccordés a l'aide d'un micro onduleur a son installation électrique de la même manière qu'un simple consommateur (vulgaire lampe)
Jusque la pas de soucis. Une C.A.C (convention d'auto consommation) était signé avec ERDF. Si surplus produit ce dernier partait gratuitement sur le réseau.

Il y a quelque temps ERDF a modifié unilatéralement le contrat C.A.C en C.A.C.S.I
convention d'auto consommation en convention d'auto consommation sans injection!

Il est donc paru sur le net des montages a base d'arduino afin de respecter ce nouveau contrat.

une mesure est faite toute les 20 millisecondes afin de déterminer le sens du courant.
si il y a injection l'arduino dérive le surplus vers un consommateur (en règle générale un chauffe eau électrique)

Ce montage fonctionne parfaitement chez moi depuis environ un ans, mais je dois pour des raisons de charges reprendre de temps en temps la valeur d'une variable.
Donc a chaque fois ressortir le PC.....
J'ai donc acheté un écran et quelques poussoir afin de pouvoir reprendre en "live" tout ça.
J'espère être assez clair, Pas de soucis si votre curiosité est piquée, je vous donnerais les infos qu'ils vous manquent.

Lien vers le routeur:

OK.
La variable se trouve codée en dur dans le programme sur l'Arduino ? D'où les boutons.

Mais les 20 ms me semblent en dehors du problème : tu ne vas pas changer ta variable grâce aux boutons toutes les 20 ms... Sinon, tu dormiras quand ?

Donc ce que tu veux faire, c'est pouvoir régler la valeur de cette variable grâce aux boutons lorsque tu vois qu'il faut le faire. Aucune interférence entre le temps mis par le code de réglage (celui de ce message actuel) et la périodicité des mesures (les 20 ms).

Au mieux, faire le réglage te prendra 10 secondes (je suis large, ça dépend si tu dois changer la valeur de beaucoup ou pas) soit le temps de 500 mesures. Ces 500 mesures seront peut-être fausses, mais pas de quoi en faire un drame (il y en a 4320000 par jour).

Par contre, pour l'instant, le réglage se fait par sauts d'une valeur d'incrément constante (par exemple -1 ou +1). Mais rien n'est prévu pour l'instant pour faire un réglage plus précis. Prenons un exemple : tu dois changer ta valeur de 1.25 à 2.36. Tu vas incrémenter de +1 et passer à 2.25, et c'est tout : la valeur visée n'est pas obtenue.

Autre cas, toujours avec des nombres pris au hasard : tu veux passer de 125 à 236 par pas de 1... Ça va prendre un certain temps voire un temps certain... Il faudrait donc peut-être prévoir de changer le pas d'incrémentation / décrémentation ... donc un bouton supplémentaire. Mais cela, uniquement si tu as besoin de précision.

bonsoir
Alors vraiment merci pour ta patience.
Parce que je suis a peu près sur de ne pas avoir compris ta démarche (vue que je viens d'essayer le code et qu'a première vue ça reste bloqué dans la boucle wille)!
Ca me fatigue de ne pas comprendre...
Sinon:

La variable se trouve codée en dur dans le programme sur l'Arduino ? D'où les boutons.

OUI

Mais les 20 ms me semblent en dehors du problème : tu ne vas pas changer ta variable grâce aux boutons toutes les 20 ms... Sinon, tu dormiras quand ?

je voulais dire que le temps d'exécution du prog (un tour de loop) est de 20 millis secondes.

Donc ce que tu veux faire, c'est pouvoir régler la valeur de cette variable grâce aux boutons lorsque tu vois qu'il faut le faire.

Oui

Aucune interférence entre le temps mis par le code de réglage (celui de ce message actuel) et la périodicité des mesures (les 20 ms).

Ce qui me porte a croire que je n'ai pas compris comment tu raisonne (je dit bien JE n'ais pas compris!

Au mieux, faire le réglage te prendra 10 secondes (je suis large, ça dépend si tu dois changer la valeur de beaucoup ou pas) soit le temps de 500 mesures.

Enfin un truc que j'ai compris: que c'est bon.

Par contre, pour l'instant, le réglage se fait par sauts d'une valeur d'incrément constante (par exemple -1 ou +1). Mais rien n'est prévu pour l'instant pour faire un réglage plus précis. Prenons un exemple : tu dois changer ta valeur de 1.25 à 2.36. Tu vas incrémenter de +1 et passer à 2.25, et c'est tout : la valeur visée n'est pas obtenue.

Alors je règle par pas de 1.
Par défaut ma variable est a 20.
Dans les cas extrêmes je la déplace a 45

j'avais utilisé la bibliothèque de Bricolo (Simple bouton) dedans il y avait un exemple un peu comme les montres c'est a dire un appuie court incrémente au pas de un suivant une tempo et un appuie long incrémente plus rapidement.
Ce ne m'a pas paru utile car je change cette valeur pas très souvent.
et en plus comme je n'arrive pas avec un simple bouton ......

J'arrive pas a comprendre pourquoi je bloque sur un truc apparemment simple, alors que j'ai fait des modifs dans le programme mis a disposition!

Je dois être bloqué sur un truc que je ne voit pas! Je ne dois pas avoir compris quelque chose et du coup ne pas voir un truc qui saute au nez.
En plus je ne maitrise presque pas l'Anglais ça n'aide pas!
j'essais de mettre en piece jointe le prog
la variable a modifier est:
safetyMargin_watts
Merci

SOFT_FINAL.ino (13.5 KB)

Il est compliqué ton code : quelle est la variable qu'il faut changer ?

Pour la gestion des boutons, peux-tu tester ce code :

#define pinBouton1 11
#define pinBouton2 12
#define temporisation 200


void setup() {
  Serial.begin(115200);
  pinMode (pinBouton1, INPUT_PULLUP); // pinBouton1 -- bouton -- GND
  pinMode (pinBouton2, INPUT_PULLUP); // pinBouton2 -- bouton -- GND
}

void loop() {
  unsigned long chrono = millis();
  boolean etatBouton1 = HIGH;
  boolean etatBouton2 = HIGH;
  while (millis() - chrono < temporisation) {
    if (etatBouton1 == HIGH) etatBouton1 = digitalRead(pinBouton1);
    if (etatBouton2 == HIGH) etatBouton2 = digitalRead(pinBouton2);
  }
  if (etatBouton1 == LOW && etatBouton2 == HIGH) Serial.println ("Bouton 1");
  if (etatBouton1 == HIGH && etatBouton2 == LOW) Serial.println ("Bouton 2");
  if (etatBouton1 == LOW && etatBouton2 == LOW) Serial.println ("Les deux");
  if (etatBouton1 == HIGH && etatBouton2 == HIGH) Serial.println ("Aucun Bouton");
}

A priori, comme il ne fait rien d'autre, il est assez rapide : il attend 200 ms pendant lesquelles il scrute les boutons et affiche ensuite le résultat. Ça va donc aller très vite : 5 affichages par seconde...
Tu peux changer les pins des boutons au début du code (11 et 12). Il faut les connecter en input_pullup

bonjour

la variable a modifier est:
safetyMargin_watts

Le code n'est pas de moi, mais je pense que ce n'étais pas utile de le préciser.
Par contre je comprend son fonctionnement dans les grandes lignes car on me l'a bien expliqué et j'arrive a le maintenir et affiner mes réglage.

pour ta curiosité et pour te remercier/
Ce code libre est issue d'un travail collectif car il faut de bonne connaissances en électricité
Tout est expliqué ici:

https://learn.openenergymonitor.org/pv-diversion/mk2/index