Minuterie pour femme de ménage
publication: 4 juillet 2022 / mis à jour 8 juillet 2022
Appel à collaboration
Vous développez des montages, simples ou complexes avec ESP32 et ESP32forth.
Partagez-les ici sur ce site.
ESP32forth ne pourra se développer qu'avec la collaboration active de toutes les bonnes volontés.
Vos montages peuvent aider d'autres développeurs.
Les montages des autres développeurs peuvent vous aider.
Pour proposer un article ou un montage, cliquez ici
Préambule
On est en 1990. C'est un programmeur informatique qui travaille beaucoup. Donc il lui arrive de quitter son bureau un peu tard.
Et c'est lors d'un d'une de ses sorties tardives de bureau qu'il s'engage dans le couloir, un de ces couloirs avec un bouton de minuterie à chaque extrémité. La lumière est déjà allumée. Mais par réflexe, notre ami programmeur appuie sur l'interrupteur et se pique le doigt: une pointe en bois est fichée dans l'interrupteur pour bloquer la minuterie.
C'est la femme de ménage qui est en train de nettoyer le sol qui lui explique:
- "oui. La minuterie ne tient qu'une minute. Et je me retrouve souvent dans l'obscurité. Comme j'en ai marre de rappuyer sans cesse sur l'interrupteur de la minuterie, je bloque le bouton avec cette petite pointe en bois"...
Une solution
Cette anecdote a fait germer dans la tête de notre programmeur une idée. Comme il avait quelques connaissances sur les microcontroleurs, il s'est mis en tête de trouver une solution pour la femme de ménage.
L'histoire ne dit pas dans quel langage il a programmé sa solution. Certainement en assembleur.
Il a dérivé la commande des lumières vers sont circuit:
- un appui ordinaire déclenche la minuterie pour une minute;
- si la lumière est allumée, tout appui bref sur un bouton ramène le délai d'allumage à une minute;
- le secret de notre programmeur est d'avoir prévu un appui long de 3 secondes ou plus. Cet appui long enclenche la minuterie pour 10 minutes d'allumage;
- si la minuterie est en circuit long, un nouvel appui long ramène le délai de la minuterie à une minute;
- un bip sonore bref acquite l'activation ou la désactivation d'un cycle long de minuterie.
La femme de ménage a fort apprécié cette amélioration de la minuterie. Elle n'a plus eu besoin de bloquer le bouton d'une quelconque manière.
Et les autres travailleurs? Comme personne n'était informé de cette fonctionnalité, ils ont continué à utiliser la minuterie en appuyant brièvement sur l'interrupteur d'activation.
Une minuterie en FORTH pour ESP32Forth
Vous l'avez compris, on va utiliser timers
pour gérer une minuterie
en y intégrant le scénario décrit précédemment.
\ myLIGHTS connceted on GPIO18 18 constant myLIGHTS \ define max time for normal or extended cycle, in seconds 60 constant MAX_LIGHT_TIME_NORMAL_CYCLE 600 constant MAX_LIGHT_TIME_EXXTENDED_CYCLE \ max time set for normal or extended cycle , in seconds 0 value MAX_LIGHT_TIME timers \ stop lights if MAX_LIGHT_TIME equal 0 : cycle.stop ( -- ) -1 +to MAX_LIGHT_TIME \ decrease max time for 1 second MAX_LIGHT_TIME 0 = if LOW myLIGHTS pin \ light off else 0 rerun then ; \ initialize timer 0 ' cycle.stop 1000000 0 interval \ start a light cycle, n is delay in seconds : cycle.start ( n -- ) 1+ to MAX_LIGHT_TIME \ set max time myLIGHTS output pinMode HIGH myLIGHTS pin \ light on 0 rerun ;
On peut déjà tester notre minuterie:
3 cycle.start \ turn on the light for 3 seconds 10 cycle.start \ turn on the light for 10 seconds
Si on relance cycle.start
pendant que la lumière est allumée, on repart pour un nouveau
cycle d'allumage de n secondes.
Il nous reste donc à gérer l'activation de ces cycles depuis un interrupteur.
Gestion du bouton d'allumage lumière
C'est pas sorcier. On va gérer un bouton poussoir. Comme nous avons une carte ESP32 sous la main, programmable avec ESP32Forth, on va en profiter pour gérer ce bouton par interruptions. Les interruptions gérant les bornes GPIO sur la carte ESP32 sont des interruptions matérielles.
Notre bouton est monté sur la borne GPIO17 (G17).
On définit au passage deux mots, intPosEdge
et intNegEdge
,
lesquels déterminent le type de déclenchement de l'interruption:
intPosEdge
pour déclencher l'interruption sur front montant;intNegEdge
pour déclencher l'interruption sur front descendant;
17 constant button \ mount button on GPIO17 interrupts \ select interrupts vocabulary \ interrupt activated for upraising signal : intPosEdge ( -- ) button #GPIO_INTR_POSEDGE gpio_set_intr_type drop ; \ interrupt activated for falldown signal : intNegEdge ( -- ) button #GPIO_INTR_NEGEDGE gpio_set_intr_type drop ;
Nous avons ensuite besoin de définir quelques variables en constantes:
- deux constantes,
CYCLE_SHORT
etCYCLE_LONG
qui serviront à définir la durée d'allumage des lumières. Ici on a choisi 3 et 10 secondes pour faire nos tests. - la variable
msTicksPositiveEdge
qui mémorise la position du compteur d'attente délivré parms-ticks
- la constante
DELAY_LIMIT
qui détermine le seuil de détermination d'un appui bref ou long sur le boutton poussoir. Ici, c'est 3000 millisecondes, soit 3 secondes. Un usager normal n'appuiera pour aisni dire JAMAIS 3 secondes sur le bouton d'allumage de la lumière. Seule la femme de ménage connait la manoeuvre pour avoir un allumage continu long...
03 constant CYCLE_SHORT \ light duration for short press button, in seconds 10 constant CYCLE_LONG \ light duration for long press button \ memorize ms-ticks value on positive edge variable msTicksPositiveEdge \ delay limit: if delay < DELAY_LIMIT, short cycle 3000 constant DELAY_LIMIT
Le mot getButton
est lancé à chaque interruption déclenchée par
appui sur le bouton poussoir connecté à GPIO17 (G17) sur notre carte ESP32.
Au début de l'exécution de getButton
, on désactive les inetrruptions
sur G17. Cette interruption sera réactivée en fin de définition. Cette désactivation
est nécessaire pour empêcher l'empilement des interruptions.
La désactivation est suivie de la boucle 70000 0 do loop
. Cette boucle
sert à gérer les rebonds de contact. Ici on gère l'anti-rebond par logiciel.
\ word executed by interruption : getButton ( -- ) button gpio_intr_disable drop 70000 0 do loop \ anti button bounce button digitalRead 1 = if ms-ticks msTicksPositiveEdge ! intNegEdge else intPosEdge ms-ticks msTicksPositiveEdge @ - DELAY_LIMIT > if CYCLE_LONG cr ." BEEP" else CYCLE_SHORT cr ." ----" then cycle.start button gpio_intr_enable drop ;
Au front montant, le mot getButton
enregistre l'état du compteur de délai
et positionne les interruptions sur front descendant. Puis on quitte ce mot en
réactivant les interruptions.
Au front descendant, le mot getButton
calcule le temps écoulé depuis
le front montant. Si ce délai est supérieur à DELAY_LIMIT
, on engage un
cycle d'allumage long. Sinon, on engage un cycle d'allumage court.
L'engagement d'un cycle d'allumage long est matérialisé par l'affichage sur le terminal de "BEEP".
Dans le scénario d'origine, c'est matérialisé par un bip sonore bref.
En pour finir, on initialise le bouton et l'interruption matérielle sur ce bouton:
\ initialise button and interruption vector button input pinMode \ set G17 in input mode button gpio_pulldown_en drop \ activate internal resistor on G17 ' getButton button pinchange intPosEdge forth
Conclusion
Ce cas d'école, très simple, montre comment gérer simultanément le timer et une interruption matérielle.
Ces deux mécanismes sont très peu préemptifs. Le timer laisse disponible l'accès à l'interpréteur FORTH. L'interruption matérielle est opérationnelle même si FORTH exécute un autre processus.
Nous ne somme pas en multi-tâche. Il est important de le dire!
Je souhaite seulement que ce cas d'école vous donne maintenant beucoup d'idées pour vos développements...
Legal: site web personnel sans commerce / personal site without seling