impulsion relais

Bonjour

... sympa cette Lib pour la gestion de l'anti-rebond ... et plus si affinité :slight_smile:

une question
possible de détourné la librairie pour une utilisation de sortie Impulsionnelle, du On/Off pour un relais.

explication avec l'exemple 05 de la Librairie

//Exemple librairie simpleBouton.h
//Appel d'une fonction à chaque appui bouton
#include "simpleBouton.h"

simpleBouton bouton(7);  // apl d'une variable, pas une entrée Physique ????

...
..
.

void loop()
{
  bouton.actualiser();
  if (bouton.vientDEtreEnfonce())
  {
    actionAssociee(); // mis a ON et OFF d'un relais (une seul impulsion )
  }
}

void actionAssociee()
{
  Serial.println("Action");
}

pour pas utiliser Delay ou Millis dans un scktech

merci

JeeLet:
possible de détourner la librairie pour une utilisation de sortie Impulsionnelle, du On/Off pour un relais ?

Pas compris la question...

Bonsoir J-M-L

oui la question est mal formuler, je vais essayer différemment.

je commande un Télérupteur a travers un p'ti Relais, relais commande par une impulsion

impulsion égale dans la durée a l'action d'un bouton poussoir d'une habitation
(on est dans le domaine de la gestion d’éclairage )

les fonctions dispo avec Arduino sont Delay ou millis pour activer une sortie impulsionnelle, du On-Off.

les Biblio anti-rebond comme Bounce2 ou simpleBouton.h utilise déjà millis

pourquoi pas utilisé simpleBouton.h qui a l'air pas mal modulable .

du code avec une fonction bloquante, pas très kleen

digitalWrite(RELAY_PIN, RELAY_ON);
        wait(200);                          //delai On-Off Impuls
        digitalWrite(RELAY_PIN, RELAY_OFF);

le croquis en question utilise déjà Bounce2 pour la gestion des contact en entrée,

alors c'est une bonne idée ????
histoire de faire une pierre 2 coups

voili voila

le projet question Mysensors - Forum Domoticz en français

vous pourriez faire

#include <simpleBouton.h>

simpleBouton bouton(2); //Cablage : pin---BP---GND
const byte RELAY_PIN = 3; // commande du relai

#define RELAY_ON LOW
#define RELAY_OFF HIGH

void setup()
{
  pinMode(RELAY_PIN, OUTPUT);
}

void loop()
{
  bouton.actualiser();
  if (bouton.vientDEtreEnfonce()) digitalWrite(RELAY_PIN, RELAY_ON);
  if (bouton.vientDEtreRelache()) digitalWrite(RELAY_PIN, RELAY_OFF);
}

De mémoire je crois avoir lu quelque part que les télérupteurs (peut-être mécaniques ?) ont besoin d'une impulsion minimum de 100ms pour coller donc si vous lâchez le bouton momentané trop vite le relais s'activera bien mais le télérupteur ne s'activera / désactivera pas

Hello

En déclarant le bouton légèrement différemment :

simpleBouton bouton(2, 200);

Le délai de debounce passera à 200 ms, ce qui garantira que le relais reste activé au minimum 200 ms.

Par contre la détection d'appui sera assez molle : il faudra maintenir le bouton enfoncé pendant 200 ms avant détection de l'appui.

Peut-être qu'une valeur intermédiaire à 120 ms donnerait satisfaction dans les deux sens.

Le délai de debounce a une valeur unique utilisée aussi bien à l'appui qu'au relâchement.
Il faudrait bidouiller la lib pour gérer deux délais distincts et là plus de problème.

Sinon une petite machine à états qui inclut le debounce et le délai d'impulsion.
Et si l'arduino doit piloter plusieurs boutons et plusieurs relais, une machine à états sous forme de classe avec plusieurs instances.

Bonjour

Messieurs merci pour le fil conducteur, un retour de mes test.

le relais est remplacer par une Led pour visu (rapide :slight_smile: )

@bricoleau le bouton poussoir est la seulement pour simuler une variable interne, dans la finaliter c'est pas pour utiliser des BP, non seulement une tempo de basculement, une seul impulsion sur un relais.

.. "Sinon une petite machine à états " oui j'ai déjà essayé par le passé pour autre truc, mais pas tout comprit, mais pourquoi pas encore une fois :slight_smile:

@J-M-L ... tu en pense quoi !!?? .. tu a un p'ti peux de temps pour un p'ti exemple "formateur" ?

merci a vous et bonne Ap

ah oui mon code foireux

#include "simpleBouton.h"

 const byte  buttonPin = 4; // BP pour simulation l'etat d'une variable
 const byte RELAY_PIN = 3;  // commande du relai (test avec LED)
 
 int buttonState = 0; 
 int lastButtonState = 0; 
 
 simpleBouton bouton(lastButtonState, 200); //lastButtonState pour simul variable

 #define RELAY_ON LOW
 #define RELAY_OFF HIGH

 void setup()  {
   Serial.begin(115200);

   pinMode(buttonPin, INPUT); 
   pinMode(RELAY_PIN, OUTPUT);

   buttonState = LOW;
 }

 void loop() {
    buttonState = digitalRead(buttonPin); 
    if(buttonState == HIGH) {
        (lastButtonState = LOW); 
     }
    else  {
        (lastButtonState = HIGH); 
     }
      //Serial.println(lastButtonState); // pour visu test
      
  bouton.actualiser();
  if (bouton.vientDEtreEnfonce()) digitalWrite(RELAY_PIN, RELAY_ON);
  if (bouton.vientDEtreRelache()) digitalWrite(RELAY_PIN, RELAY_OFF);
  
 }
 // ---------------- * ----------

faut pas faire   pinMode(buttonPin, INPUT); sinon vous cassez la classe de @bricoleau.. la pin du bouton est mise en INPUT_PULLUP lors de l'instanciation.

@bricoleau le bouton poussoir est la seulement pour simuler une variable interne, dans la finaliter c'est pas pour utiliser des BP, non seulement une tempo de basculement, une seul impulsion sur un relais.

si vous n'avez pas de vrai bouton que quelqu'un appui, ça ne va pas marcher avec la classe de @bricoleau...

ce dont vous avez besoin éventuellement si vous ne voulez pas gérer millis() vous même c'est une approche par gestion d'évènements.

J'avais posté pour @iznobe une classe AsyncTask qu'il utilise dans la gestion des ses volets

En gros quand vous voulez envoyer une impulsion au relais vous appelez une fonction qui active le relais et enregistre pour plus tard un callback (appel de fonction) qui se chargera d'éteindre le relais ce qui fabriquera donc la bonne impulsion. la classe AsyncTask permet de gérer tout cela, il suffit d'avoir dans la loop() un appel à updateQueue() assez fréquent

le callback prend un paramètre (un type particulier appelé t_commandID qui est un nombre) et donc vous pouvez enregistrer le N° de pin dans la tâche comme cela le callback pourrait gérer plusieurs relais.

voici un code d'exemple, dans le setup() je demande une impulsion au relais et cette fonction enregistre le callback pour 2 secondes plus tard (en pratique vous mettriez 100ms pour un télérupteur). La console à 115200 bauds affichera aussi un petit message. Vous devriez voir la LED de la carte s'allumer, puis par magie s'éteindre 2 secondes plus tard.

le .ino

#include "AsyncTask.h"
AsyncTask<10> gestionnaireDeTache; // max 10 tâches en cours

const byte ledPin = LED_BUILTIN;  // commande du relai (test avec LED de la carte)

void finImpulsion(t_commandID identifier)
{
  Serial.print(F("FIN IMPULSION SUR PIN"));
  Serial.println(identifier);
  digitalWrite(ledPin, LOW);
}

void impulsionRelais(byte numPin)
{
  Serial.print(F("IMPULSION SUR PIN #"));
  Serial.println(numPin);
  digitalWrite(numPin, HIGH);
  // on enregistre de se faire notifier 2000ms plus tard pour éteindre le relais
  // en pratique mettre 100ms
  gestionnaireDeTache.registerAsyncCommand(numPin, 2000UL, finImpulsion);
}


void setup()
{
  Serial.begin(115200);
  pinMode(ledPin, OUTPUT);
  // on balance une impulsion
  impulsionRelais(ledPin);
}

void loop()
{
  gestionnaireDeTache.updateQueue(); // va  gérer automatiquement le callback

  // ici on peut faire autre chose si pas bloquant
}

le fichier AsyncTask.h à mettre dans le même répertoire que le .ino

#ifndef ASYNCTASK_H
#define ASYNCTASK_H

#include <Arduino.h>

typedef uint16_t t_commandID; // command idendifier is on 2 bytes (0x00 to 0xFFFF).
typedef void (*t_callback)(t_commandID); // same as "using t_callback = void (*)(t_commandID);"

template <uint16_t queueLength>
class AsyncTask
{
  private:
    struct t_queueCommand
    {
      t_callback    callback;    // a pointer to the function you want to execute after the delay is expired
      t_commandID   commandID;   // An ID for this command, used in callBack
      uint32_t      maxWait;     // how long to wait before the callback
      uint32_t      startTime;
      bool          active;
    };

    uint16_t _count;
    t_queueCommand _queueCommandList[queueLength];
    static const uint16_t _maxCommands = queueLength;

  public:
    // constructor
    AsyncTask()
    {
      _count = 0;
      for (uint16_t i = 0; i < _maxCommands; i++)
        _queueCommandList[i].active = false;
    }

    bool registerAsyncCommand(t_commandID id, uint32_t deltaT, t_callback cb) {

      // find the next empty slot
      int32_t nextSlot = -1;

      for (int32_t i = 0; i < _maxCommands; i++) {
        if (! _queueCommandList[i].active) {
          nextSlot = i; // found a position
          break;
        }
      }

      // register the command in that slot
      if (nextSlot != -1) {
        _queueCommandList[nextSlot].startTime = millis();
        _queueCommandList[nextSlot].commandID = id;
        _queueCommandList[nextSlot].callback = cb;
        _queueCommandList[nextSlot].maxWait = deltaT;
        _queueCommandList[nextSlot].active = true;
        _count++;
      } // else  // error no room left

      return (nextSlot != -1);
    }

    bool unregisterAsyncCommand(t_commandID id) {
      bool commandRemoved = false;
      for (int32_t i = 0; i < _maxCommands; i++) {
        if ((_queueCommandList[i].active) && (_queueCommandList[i].commandID == id)) {
          // on l'a trouvée
          _queueCommandList[i].active = false;
          _count--;
          commandRemoved = true;
          break;
        }
      }
      return commandRemoved;
    }

    bool forceAsyncCommand(t_commandID id) {
      bool commandExecuted = false;
      for (int32_t i = 0; i < _maxCommands; i++) {
        if ((_queueCommandList[i].active) && (_queueCommandList[i].commandID == id)) {
          // trigger the callback
          _queueCommandList[i].callback(_queueCommandList[i].commandID);
          // mark it as done
          _queueCommandList[i].active = false;
          _count--;
          commandExecuted = true;
          break;
        }
      }
      return commandExecuted;
    }

    bool findAsyncCommand(t_commandID id) {
      bool commandFound = false;
      for (int32_t i = 0; i < _maxCommands; i++) {
        if ((_queueCommandList[i].active) && (_queueCommandList[i].commandID == id)) {
          commandFound = true; // we found it !
          break;
        }
      }
      return commandFound;
    }

    uint16_t updateQueue()
    {
      uint16_t taskExpired = 0;
      if (_count == 0) return false; // no command to execute
      for (uint16_t i = 0; i < _maxCommands; i++) {
        if (_queueCommandList[i].active) {
          if (millis() - _queueCommandList[i].startTime >= _queueCommandList[i].maxWait) {
            // trigger the callback
            _queueCommandList[i].callback(_queueCommandList[i].commandID);
            // mark it as done
            _queueCommandList[i].active = false;
            _count--;
            taskExpired++; // count number of completed tasks
          }
        }
      } // end for each possible task
      return taskExpired;
    }


    // utilities
    uint16_t maxCommands() const {
      return _maxCommands;
    }

    uint16_t queueCount() const  {
      return _count;
    }
};

#endif

PS/ on s'éloigne bcp de la classe SimpleBouton ce qui "pollue" le partage de @bricoleau, le mieux serait de demander au modérateur de déplacer toute cette discussion dans le forum principal et continuer la discussion là bas

J-M-L merci

... oui la demander est en cours pour le déplacement de post

bon j'ai de la lecture :slight_smile:

Topic déplacé....

... un retour avec utilisation de AsyncTask.h

c du lourd pour un débutent, j'aimais bien le coter Light de bricoleau.

donc le code avec un ajout pour activer l'impulsion
, l'envoie d'une valeur au programme avec le terminal série.

je sais pas ou placer la valeur ??? ( avec un BP connecter le code s’allonge encore :slight_smile: )

/*
 * sur une idée de J-M-L
 * 
 * pour envoie d'une seul Impulsion pour un Relais 
 *  du Filp-Flop logique ??
 * 
 */

 #include "AsyncTask.h"
 // objet nommé gestionnaireDeTache capable de contenir 10 tâches
   AsyncTask<10> gestionnaireDeTache; // max 10 tâches en cours
/*Une tâche se définie par un identifiant (un nombre)..*/
/*..un délai à attendre en ms et une fonction à appeler (un callback)*/

 const byte ledPin = 3;  // commande du relai (test avec une LED)
  int go = 0 ;
  
 void finImpulsion(t_commandID identifier)
 {
  Serial.print(F("FIN IMPULSION SUR PIN"));
  Serial.println(identifier);
  digitalWrite(ledPin, LOW);
 }

 void impulsionRelais(byte numPin)
 {
  Serial.print(F("IMPULSION SUR PIN #"));
  Serial.println(numPin);
  digitalWrite(numPin, HIGH);
 
  gestionnaireDeTache.registerAsyncCommand(numPin, 2000UL, finImpulsion);
 }
//on enregistre de se faire notifier 2000ms plus tard ...
//.. pour éteindre le relais, en pratique mettre 100ms


 void setup()
 {
  Serial.begin(115200);
  pinMode(ledPin, OUTPUT);
  
  impulsionRelais(ledPin);    //on balance une impulsion
 }

 void loop()
 {

  if (go > 0) {
      Serial.println("c bon");
 }
 
  gestionnaireDeTache.updateQueue(); // va  gérer automatiquement le callback
  

/*appeler à chaque tour de loop updateQueue()..*/
/*..pour déclencher les callbacks au bon moment*/

  // ici on peut faire autre chose si pas bloquant

  /* ajout de reception d'une valeur  par le terminal*/ 
  while (Serial.available()) { //lecture du port serie ...
  char  go = Serial.read();     // ... et on lit le charactère
  Serial.print(go);            // puis on l'écrit sur le moniteur
  //delay(10);                // test avec temps de pause
  }
  
 }
 // ---------------- Fin du Pgm  ----------
 
 /*    ---- INFO Tuto -----
*     
* une recopie de https://forum.arduino.cc/index.php?topic=674268.0

// ------ *** -------
//ce bout de code déclare dans le setup qu'on veut déclencher la fonction callback1
//dans 3secondes, puis 6 secondes et la fonction callback2 dans 9 secondes

Code exemple:
  // on amorce avec 3 tâches futures dans 3, 6 et 9 secondes
  gestionnaireDeTache.registerAsyncCommand(10, 3000UL, callback1);
  gestionnaireDeTache.registerAsyncCommand(20, 6000UL, callback1);
  gestionnaireDeTache.registerAsyncCommand(30, 9000UL, callback2);
// ------ *** -------
*/
  /[code]


merci J-M-L

Re-Edit
j'ai trouver des info https://forum.arduino.cc/index.php?topic=674268.0

bon affaire non aboutie, trop hermétique pour moi.

merci encore

Bonsoir

une version avec la biblio de bricoleau ... "simpleBouton.h"

/*
* Gestion d'une impulsion de sortie pour commande télérupteur
* 
* avec librairie simpleBouton.h de bricoleau pour le debounce et millis   
* version: V4.2 du 07/08/2020
* 
* un test avec commande start du cycle avec un inter (on/off)  "TC"
* activation du compteur par le retour d'etat du contact auxilaire "TS"
*
*
*/
//  ---   *** attention Prog en  test ***   ---

 #include "simpleBouton.h"

 boutonAction boutonTC(2); // Cmd Mar Arr du cycle impuls
 simpleBouton boutonTS(3 ); // TS= retour d'état du TL 
 const byte RELAY_PIN = 4;  // commande du Relai-->TL 

 #define RELAY_ON  HIGH
 #define RELAY_OFF LOW

 void cloc() 
  {
  Serial.println("clic cloc");
  digitalWrite(RELAY_PIN, RELAY_ON);
  Serial.println("  start impuls");
  }

 void setup()
  {
  Serial.begin(115200);
  
  boutonTC.attacher(cloc); // apl Fonction
  
  pinMode(RELAY_PIN, OUTPUT);
  digitalWrite(RELAY_PIN, RELAY_OFF);
  }
 
  void loop()
  {
//Lecture de la durée d'appui AVANT d'actualiser
  uint32_t duree1 = boutonTS.dureeEnfonce(); 
  
  boutonTS.actualiser();
  boutonTC.actualiser();
  
  if (boutonTS.vientDEtreEnfonce() ) 
  {
  Serial.println("Bouton enfonce");
  }

  if (duree1 > 1500 )
  {
  digitalWrite(RELAY_PIN, RELAY_OFF);
  }
  
  if (boutonTS.vientDEtreRelache() )
  {
  Serial.println("off impuls");  
  Serial.print(duree1);
  Serial.println(" ms");
  } 
   
}
//---- fin pgm ------

// ---- zone mémo et autre ---- 
/*
 * Detection_dun_front
 * 
 *     int new_bp = 0, old_bp = 0;
    void setup(){
       pinMode(5, INPUT);
       ...
    }
    void loop(){
       ...
       new_bp = digitalRead(5);
       if((new_bp != old_bp) && (new_bp == 1)){
          [ACTIONS A FAIRE SUR FRONT MONTANT]
       }
       old_bp = new_bp;
       
       ...
    }  
  * 
*/

bon me reste plus que comment remplacer mon inter 'le boutonTC" par une variable ON / OFF
... un "truc" avec verrouillage (connais pas le terme >:( )

une variable a HIGH enclenche un cycle d'impuls
et le passage a LOW re-cycle d'impuls ... un flip flop ???

Bonsoir

voila mon impulse est opérationnelle :slight_smile:

reste a le prendre en faute, faire des test plus fouillé.

/*
* Gestion d'une impulsion de sortie pour commande télérupteur
* 
* avec librairie simpleBouton.h de Mr bricoleau pour le debounce et millis   
* version: V4.2 du 07/08/2020
* 
* commande Marche ou Arret du TéLérupteur avec un inter (on/off) 
* activation du compteur par le retour d'etat du contact auxilaire du Tl
*
*
*/
//  ---   *** fonctionnelle??  ***   ---

 #include "simpleBouton.h"

 simpleBouton boutonTC(2); // Cmd Mar Arr du cycle impuls
 simpleBouton boutonTS(3); // TS= retour d'état du TL 
 const byte RELAY_PIN = 4;  // Relais qui Commande le TL 

 #define RELAY_ON  HIGH
 #define RELAY_OFF LOW

  void actionAssocieeON() {          //demande d'allumage lux
  Serial.println("Action on");
  digitalWrite(RELAY_PIN, RELAY_ON);  //début de l'impulsion
  }

  void actionAssocieeOFF() {        //demande d'extinction lux
  Serial.println("Action off");
  digitalWrite(RELAY_PIN, RELAY_ON);  //début de l'impulsion
  }
  
 void setup() {
  Serial.begin(115200);
  pinMode(RELAY_PIN, OUTPUT);
  digitalWrite(RELAY_PIN, RELAY_OFF);
  }
 
  void loop() { 
//Lecture de la durée d'appui AVANT d'actualiser
  uint32_t duree1 = boutonTS.dureeEnfonce(); 
  
  boutonTS.actualiser();
  boutonTC.actualiser();

// ----basculement demande -----
  if (boutonTC.vientDEtreEnfonce()) { // demande de marche du TL
    actionAssocieeON();
  }

  if (boutonTC.vientDEtreRelache()) { // demande d'arret du TL
    actionAssocieeOFF();
  }

// ---- gestion impulse relais ----  
  if (boutonTS.vientDEtreEnfonce() ) {
  Serial.println("Bouton enfonce");
  }

  if (duree1 > 1500 ) {
  digitalWrite(RELAY_PIN, RELAY_OFF);   //fin de l'impulsion
  }
  
  if (boutonTS.vientDEtreRelache() ) {
  Serial.println("off impuls");  
  Serial.print(duree1);   // affiche la durée de l'impulsion 
  Serial.println(" ms");
  } 
 
}
//---- fin pgm ------

// ---- zone mémo et autres ---- 
/*
 *
 * 
 * 
 * 
 * 
*/

retour d'info du terminal :

(mis en marche de l'inter)
Action on
Bouton enfonce
off impuls
1504 ms

(mis a l'arret)
Action off
Bouton enfonce
off impuls
1504 ms

merci Bricoleau pour la Lib ultra Light

sur un UNO c'est ".. 2762 octets (8%) de l'espace"

pour info, un peut de lecture