Je n'ai encore rien codé pour ce petit projet (ni même câblé quoi que ce soit) mais je butte déjà sur le principe... Ça commence mal !
Base de réflexion : ESP32, bouton poussoir unique et son anti-rebond, relais (plus transistor etc évidement). Ça je sais faire...
J'aimerai commander un relais (bref une sortie) avec un bouton poussoir mais qui ne réagisse qu'à une séquence prédéfinie d'appuis façon code morse.
Exemple : le code secret est long - court - court - long. Court est un appui de moins de 0,4 s, long un appui entre 0,8 et 1,5 s Exemples de valeurs arbitraires pour le moment, à affiner à l'usage si besoin.
Si j’appuie long - court - court - long le relais se ferme. Si je fais autre chose, ou des durées anormales, rien ne se passe.
Comment verriez-vous la logique du code ? machine à états ? autres ? J'ai du mal à voir par où prendre le problème.
Merci d'avance pour vos idées.
Edit : pour une version 2.0 (soyons fous) un mode « programmation » qui permet d'enregistrer un nouveau code pourrait être une bonne option, mais je n'en suis pas là, mais peut-être que ça peut influer sur le design du code
Un truc, est de prendre une bibliothèque comme JC_Button, qui gère le long press, ca peut aider.
L'usage de ce genre de bibliothèque est que l'anti rebond est géré.
PS: Si tu n'as rien contre l'IA, tu lui envoies l'intégralité de ton premier message et tu auras des pistes
Si la librairie JC_button gère le longpress, je vais déjà essayer de l'utiliser. On verra ensuite pour la logique de décodage - validation
Pour ce qui est de l'IA, je n'ai rien contre mais la "production" sur les enjeux complexes donne généralement du grand n'importe quoi. Je l’utilise à l'occasion mais pour des contextes très précis.
Je ferais une boucle principal qui calcule le temps d'appuis sur le bouton.
c'est à dire mémorise le temps(millis) au changement d'état lâché-appuis et prise de temps au changement d'état appuis-lâché.
Je déclencherais aussi une prise de temps au relâché, qui réinitialiserais le code secret si aucun appuis pendant un certain temps.
Lors du relâché du coup j'ajouterais le résultat de la prise de temps 0 pour court et 1 pour long.
Pas sûre que ce soit très claire, mais cela me parais simple à faire, si tu as un antirebonds matérielle évidement(sans ca complexifie a peine ).
//Exemple librairie simpleBouton.h
//Affichage des durées d'appui
#include "simpleBouton.h"
const uint32_t point = 400;
const uint32_t trait = 1000;
const uint8_t code [] = {1, 0, 0, 1};
simpleBouton bouton(7);
//Cablage : pin---BP---GND
bool identificationCode(uint8_t saisieBouton[]);
void setup()
{
Serial.begin(115200);
}
void loop()
{
//Lecture de la durée d'appui AVANT d'actualiser
uint32_t duree = bouton.dureeEnfonce();
static uint8_t y = 0;
static uint8_t saisieBouton[4];
bouton.actualiser();
if (bouton.vientDEtreRelache()) {
(duree <= point) ? saisieBouton[y] = 1 : saisieBouton[y] = 0 ;
(duree <= point) ? Serial.println("point") : Serial.println("trait") ;
y++;
Serial.println(y);
}
if ((y == 4) && identificationCode(saisieBouton)) {
Serial.println ("le code est bon !");
for (uint8_t z = 0 ; z < 4; z++) saisieBouton[z] = 3;
// action sur relais ....
}
if (y == 4) y = 0;
}
bool identificationCode(uint8_t saisieBouton[]) {
for (uint8_t x = 0 ; x < 4 ; x++) {
if (saisieBouton[x] != code [x]) return false;
}
return true;
}
Bonne journée.
PS : A vous de doser le temps d'appui pour déterminer si l'appui est long ou court. Dés que le code est trouvé vous n'avez plus qu'à actionner le relais ...
Avec les temps d'appui que j'ai déterminés tout fonctionne très bien sur 328p ou 1284p. Non testé sur ESP32 mais nul doute que ça fonctionnera bien.
edit : vous pouvez supprimer la réinitialisation du tableau saisieBouton qui est absolument inutile : for (uint8_t z = 0 ; z < 4; z++) saisieBouton[z] = 3;
1/ Je ne connais pas du tout la librairie JC_Button.h
Mais il semble qu'elle ne gère pas l'anti-rebond correctement : const uint8_t BUTTON_PIN = 10; // PIN10(pullup) -- poussoir + 100nF // -- GND
Vous ne devriez pas avoir de condensateur anti-rebond, de plus personnellement je mets plutôt une valeur proche de 10nF (100nF étant le maximum). C'est la librairie ou le condensateur pour l'anti-rebond. Si la librairie est ben faite le condensateur est totalement inutile. Bon après le fait d'utiliser les deux ne doit pas poser de problème ...
2/ Une librairie qui gère des boutons poussoirs ne devrait pas vous obliger à utiliser la fonction millis(), elle fait le job de manière transparente pour vous.
3/ la librairie de @bricoleau est particulièrement bien faite est extrêmement efficace. C'est celle-ci que j'utilise systématiquement. De plus là où @bricoleau est génial c'est qu'il l'a faite de sorte qu'elle soit simple et facilement compréhensible
Après si votre code vous convient, c'est votre choix et de surcroît si il fonctionne bien, il n'y a rien à y redire ...
Enfin pourquoi déclarez-vous les variables globales de code static ?
Je ne connaissais aucune des deux avant de commencer ce projet
Normalement si, par défaut et on peut ajuster en paramètre la durée de l'anti-rebond logiciel.
J'ai laissé le condensateur plus par habitude que par nécessité, et 100 nF parce que des expériences précédentes avec des boutons d'assez mauvaise qualité faisait que 10 nF laissait passer parfois quelques rebonds. C'est surdimensionné, je vais fouiller les fonds de tiroir pour diminuer.
Peut-être, mais je n'ai pas trouvé comment avec JC_button.h. Reste que par plaisir, je vais quand même regarder l'autre lib et si quelqu'un à mieux à proposer avec JC_button, je suis preneur de conseils et d'explications.
Je ne suis encore vraiment pas au point avec le C++ et je code en copie-collant des bouts trouvés de-ci de-là. Si j'ai bien compris (pas sûr du tout),staticest nécessaire pour les interruptions. Mais à y réfléchir, c'est pour les déclarations locales, ici pour les globales c'est moins clair. Là aussi, je suis preneur d'une explication.
Franchement je ne vois pas trop quoi dire, c'est bien.
Pour pinailler ou pourrait se dire que sur exemple aussi simple, n'est-il pas possible de simplifier et si toutes les variables sont vraiment nécessaire et si l'ajout d'une variable ne peut pas simplifier le code?
Par exemple remplacer tous les calcules de temps de pression par une variable pour aérer la lecture du code ?
Pourquoi ne pas utiliser la propriété lastChange, plutôt que millis pour msLache
Du coup cela peut simplifier le test d'inactivité?
je ne suis pas persuadé que la variable isTyping soit absolument nécessaire ?
j'ai fait un wokwi pour voir ce que cela pourrait donner certains changements qui sont fort discutable .
C'est le fait que @ProfesseurMephisto utilise de manière préventive un condensateur qui te fait dire ça ?
Pourquoi cela est-il absolument nécessaire, de ne pas avoir de condensateur dans ce cas?
Moi je crois de mémoire que je mets systématiquement un 100nF, je n'ai pas calculé le temps, tu pense que c'est trop ?