Autres articles / Other articles

Minuterie pour femme de ménage

publication: 4 juillet 2022 / mis à jour 8 juillet 2022

Read this page in english

 

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:

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:

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:

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