Activer un solénoïde via un interrupteur

Bonjour, j'essaie d'activer un solénoïde via un interrupteur.
A chaque pression sur le bouton je souhaite que le solénoïde s'active 60 millisecondes.

Je ne peux pas utiliser la fonction delay()

Mes connaissances en C sont très sommaire et assez inégales.

Pouvez vous me dire ce qui cloche dans le code svp ?

Il y a plusieurs fichiers dans le code.

------------------------solenoid.cpp----------------------

//
// Created by Eric Vantillard on 22/05/2022.
//

#include "Solenoid.h"

Solenoid::Solenoid(int pin, bool allowReactivation) : pin(pin), allowReactivation(allowReactivation) {
    activated = false;
    activatedUntilMs = -1;
    lastActivationMs = -1;
}

void Solenoid::setup() const {
    pinMode(pin, OUTPUT);          //Sets that pin as an output
    digitalWrite(pin, LOW);
}

void Solenoid::update() {
    if (activated) {
        auto now = millis();
        if (now >= activatedUntilMs) {
            desactivate();
        }
    }
}

void Solenoid::activate(unsigned long durationMs) {
    if (!activated || allowReactivation) {
        activated = true;
        const auto now = millis();
        lastActivationMs = now;
        activatedUntilMs = now + durationMs;
        digitalWrite(pin, HIGH);
    }
}

void Solenoid::desactivate() {
    activated = false;
    activatedUntilMs = -1;
    digitalWrite(pin, LOW);
}

unsigned long Solenoid::lastActivation() const {
    return lastActivationMs;
}

bool Solenoid::isActive() const {
    return activated;
}





#include "Solenoid.h"
Solenoid solenoid(7, false);
void setup() {
 solenoid.setup();

}

void loop() {
  solenoid.update();
    if(digitalRead(A2)==LOW){
        solenoid.activate(60);//60 milli seconds
    } 

}

-------------------------------solenoid.h-----------------------------

//
// Created by Eric Vantillard on 22/05/2022.
//

#ifndef ARDUINO_SOLENOID_LIB_SOLENOID_H
#define ARDUINO_SOLENOID_LIB_SOLENOID_H

#include <Arduino.h>

class Solenoid {

public:

    explicit Solenoid(int pin, bool allowReactivation = true);

    void setup() const;

    void update();

    void activate(unsigned long durationMs);

    void desactivate();

    unsigned long lastActivation() const;

    bool isActive() const;


private:
    const int pin;
    const bool allowReactivation;
    bool activated;
    unsigned long activatedUntilMs;
    unsigned long lastActivationMs;
};

#endif //ARDUINO_SOLENOID_LIB_SOLENOID_H

------------------------------le code--------------------------

#include <Arduino.h>
#include "Solenoid.h"


Solenoid solenoid(7, false);

void setup() {
    solenoid.setup();
}

void loop() {
    solenoid.update();
    if(digitalRead(A2)==HIGH){
        solenoid.activate(60);//60 milli seconds
    } 
    
    auto now = millis();
    if(now%1000==0){
        solenoid.activate(60);//60 milli seconds
    }
}

Bonjour,

Quel est le problème?

Ca à l'air super compliqué pour faire une impulsion. Pourquoi tu ne peux pas utiliser delay()?
Si c'est pour la beauté du geste alors rien à dire.

Tu as bien mis un pullup externe sur A2? Sinon tu peux activer le pullup interne avec pinMode(A2, INPUT_PULLUP)
Tu devrais tester l'enfoncement du bouton plutôt que son état car autrement activate() est appelé tant que tu appuies sur le bouton et donc le solénoide est réactivé à la fin des 60ms (sauf si tu es super rapide et que tu appuies moind de 60ms sur le bouton).

Oui, ce serait bien de le décrire!

Je vois aussi qu'il n'y a pas de traitement anti rebonds.

Y a-t-il une raison de mettre activatedUntilMs à -1 si on ne l'utilise pas et pas à 0, cette variable étant déclarée positive? La mettre à -1 la met en fait au maximum (4 milliards). D'autant plus qu'il me semble que la valeur n'a pas d'importance (non utilisée si elle vaut 4 milliards).

Dans la gestion de la durée, le test est fait par
(now >= activatedUntilMs)
et pas par
(now - lastActivationMs > 60)
ce qui va provoquer une erreur au débordement. Mais tu as 70 jours pour y penser. Voir "blink without delay"

Merci de l'intérêt que vous portez a mon soucis, dsl j'avais fais une erreur dans la dernière parti du code, je viens d'éditer le message, alors voila ce que ca fait :

En plus de l'activation qui se fait toute seule chaque seconde que vous pouvez voir en vidéo, lorsque j'appuis sur le buton interrupteur rien ne se passe mais lorsque je le relâche ca active le solénoïde.
Bref on est bien loin de l'effet escompté.
Moi tout ce que je veux c'est qu'a chaque pression sur le bouton, le solénoïde s'active 60ms, quelque soit le temps ou le bouton reste enfoncé.

Si tu édites tes messages après qu'il y a eu des réponses, on ne va plus rien comprendre à la discussion.

a mince pardon :sweat_smile:

C'est normal qu'il s'active toutes les secondes, dans loop, il y a le code:

    auto now = millis();
    if(now%1000==0){
        solenoid.activate(60);//60 milli seconds

Note quand même qu'il ne faut pas comparer millis() avec une valeur mais utiliser un supérieur. Milli s'incrémente parfois de 1, parfois de 2. Il y a donc des valeurs que millis() ne prendra pas.

millis() s'incrémente que lors des coups de l'hologe qui bat 1,024ms. Normalement elle s'incrémente de 1, mais pour rattraper son retard, 24 fois par seconde, elle s'incrémente de 2.

[edit]
Si il ne se passe rien quand tu appuie sur le bouton, c'est peut être une erreur de câblage:

ou une pulldown!
Comment est câblé le bouton?


En fait quel est exactement ton but?

~ avoir un code qui fonctionne (quitte à utiliser une bibliothèque déjà faite)
~ faire une bibliothèque
~ comprendre pourquoi cela ne fonctionne pas
~ ... aute?

avoir un code qui fonctionne (quitte à utiliser une bibliothèque déjà faite) me conviens parfaitement :grin:
Pour le pull up, je pense pas qu'il faille un hardware, un pull up dans le code suffira amplement , mais pour le moment j'en suis pas la, même lorsque j'enlève
'''
auto now = millis();
if(now%1000==0){
solenoid.activate(60);//60 milli seconds
'''
le solénoïde s'active lorsque je relâche le bouton pendant 60ms, tandis que je souhaite qu'il s'active de 60ms quand j'appuis sur le bouton.
Lorsque je change LOW en HIGH je me retrouve avec le solénoïde actif de longue et lorsque je presse le bouton il ne se passe rien et lorsque je le relâche le solénoïde se désactive 60ms.

en gros je veux un code qui fait ca :

''' digitalWrite(solenoidPin, HIGH); //Switch Solenoid ON
delay(60); //attend 60 ms
digitalWrite(solenoidPin, LOW); //Switch Solenoid OFF
delay(60); //attend 60ms
'''
Mais je ne peux pas utiliser delay() .
J'ai mis 60 et 60 pour que le solénoïde puisse refroidir mais a l'usage je modifierais peut être un peu genre 60 on et 90 off

Vous pouvez oublier tout ce que j'ai poster avant, si vous avez un code a me proposer qui fait ce que je veux cad activer le solénoïde 60ms a chaque pression sur le bouton quelque soit le temps ou je le presse (sans utiliser delay()) je prend.

Si c'est sur Uno/Nano/Mega, j'écris simplement:

#include "MTsoftPWM.h" // Voir http://arduino.dansetrad.fr/MTobjects
#include "MTbutton.h" // Voir http://arduino.dansetrad.fr/MTobjects

MTsoftPWM solenoid(7, impulsion_de 60000 micro_seconde, periode_de 1000000 micro_secondes, on_commence_par HIGH, 2 niveaux_et_arret, MT_OFF);
// On se moque de la période, on n'ira pas au bout, on ne fait qu'une impulsion
// On ne fait que 2 changement avant arrêt: HIGH puis LOW

void solenoidActivate(void)
{
  solenoid.start();
}

MTbutton Bouton(A2, solenoidActivate);

void setup() {}

void loop() {}

Commerçons à lire par la fin car les conséquences en C doivent être définies avant (elles doivent être connues avant):

Le bouton, lors d'un appui appelle la fonction solenoidActivate qui fait partir un PWM pour une seule impulsion (2 niveaux).

Ce code fonctionne pour un bouton branché entre GND et A2 (une pullup interne est mise en place. Possibilité de mettre un bouton entre VCC et A2, si on écrit:
MTbutton Bouton(A2, solenoidActivate, PAS_D_ACTION, LOW si_non_appuye);
mais il faut mettre une pulldown externe

On trouve peut être l'équivalent pour d'autres cartes.


Ceci est dû à une inversion du bouton
if(digitalRead(A2)==HIGH){
est pour un bouton qui est bas (pulldown) et qui passe à HIGH quand on appuie dessus. Il suffit alors de mettre LOW à la place de HIGH

Avec un bouton, il faut absolument une pullup ou une pulldown. Si on veut une en interne, sur uno on ne peut mettrequ'une pullup, sur ESP32 on peut choisir

Pourquoi la seconde temporisation? Une fois le solénoïde éteint, on doit attendre un nouvel appui. Si on appuyait sur le bouton extrêmement rapidement, cela vaudrait peut être le coup, mais en principe on n'arrivera pas à appuyer de nouveau avant 200ms.

Il y a autre chose derrière ou en même temps. Plus on en saura, plus l'aide sera précise et utile.
Je vais monter l'association des défenseurs de delay. Je sis faire deux delay qui courent en même temps et n'empêchent pas un pas à pas d'avancer. C'est par philosophie? par religion? ou il; y aura autre chose à faire?

Pour encadrer le code c'est soit en utilisant le bouton </> de la barre d'outil soit avec 3 backsticks ``` pas des guillemets

Alors un grand merci , seul le code fonctionne parfaitement :ok_hand: :muscle:
Par contre j'ai besoin de comprendre pour pouvoir l'intégrer un un autre code.
Je suis habitué a une architecture de code differente, en 3 partie:
declaration
setup
loop

et la je suis un peu perdu et je n'arrive pas a intergrer ce code a un autre.
j'ai besoin d'explication et/ou d'une version avec le loop svp
la carte est une pro micro

Le code que je t'ai donné n'utilise que la partie déclaration. Setup et loop sont vides. Il suffit alors de supprimer la ligne setup et loop et de mettre ton code à la place:

#include "MTsoftPWM.h" // Voir http://arduino.dansetrad.fr/MTobjects
#include "MTbutton.h" // Voir http://arduino.dansetrad.fr/MTobjects

MTsoftPWM solenoid(7, impulsion_de 60000 micro_seconde, periode_de 1000000 micro_secondes, on_commence_par HIGH, 2 niveaux_et_arret, MT_OFF);
// On se moque de la période, on n'ira pas au bout, on ne fait qu'une impulsion
// On ne fait que 2 changement avant arrêt: HIGH puis LOW

void solenoidActivate(void)
{
  solenoid.start();
}

MTbutton Bouton(A2, solenoidActivate);


<tes déclarations>

void setup()
{
  <ton setup>
}

void loop() 
{
   <ton loop>
}

En général, on aime bien dans les déclaration mettre ensemble les includes, puis les variables et les fonctions, mais ce n'est pas indispensable. Il faut que les includes soit avant leur utilisation, que MTsoftPWM solenoid soit avant la fonction solenoidActivate car elle fait appel à solenoid,
et que Bouuton soit après solenoidActivate

Bonjour deathstalker

Moi, aussi :wink:
Voici une autre vision de la chose, avec la bibliothèque JC_Button pour gérer le bouton et millis() pour l'impulsion.

#include <JC_Button.h>     // https://github.com/JChristensen/JC_Button

const int selenoidPin = 7;
const int boutonPin = A2;

unsigned long selenoidOnTime = 60;     // Temps d'attraction en millisecondes
unsigned long selenoidOnMillis = 0;     // Temps d'attraction chronomètre

//                     Anti R  PULL_UP   Inversion
Button bouton(boutonPin, 20,    true,      true);       // Bouton actif à LOW

void setup() 
{
	pinMode(selenoidPin, OUTPUT);
	bouton.begin();
}
void loop() 
{
	bouton.read();
	
	if (bouton.wasPressed())     // Si bouton a été pressé
	{
		digitalWrite(selenoidPin, HIGH);
		selenoidOnMillis = millis();     // Début chronométrage impulsion
		
	}
	
	if (selenoidOnMillis != 0 && (millis()-selenoidOnMillis >= selenoidOnTime))     // Si durée d'impulsion
	{
		digitalWrite(selenoidPin, LOW);
		selenoidOnMillis = 0;
	}
}

Cordialement
jpbbricole

Alors lorsque je met ton code en début du mien j'obtiens un code erreur il me demande si par "bytes" je veux pas dire "bits", ca rentre en conflit avec un fichier de la librairie je crois.

Par contre en le mettant juste a la fin des includes juste avant le setup ca veux bien compiler mais il me dit que le sketch est trop gros (décidément c'est un problème reçurent dans ma vie :rofl:).

Donc faut que je regarde si j'ai pas une carte avec plus de mémoire.

Le code que j'ai donné ne fonctionne que sur Uno/nano/minipro/mega.

Pour la taille du code, aura-tu à rajouter encore quelque chose ou pas? Si tu ne rajoutes rien, on devrait reprendre un code plus light.

oui je n'ai plus reussi a compiller et a avoir cette erreur de sketch trop grand, j'ai cette erreur a la place
Arduino : 1.8.16 (Windows 10), Carte : "Arduino Leonardo"

MThardPWM.cpp:158:8: error: #error Cette bibliothèque ne fonctionne que sur Uno, Nano ou Mega

   #error Cette bibliothèque ne fonctionne que sur Uno, Nano ou Mega

    ^~~~~

exit status 1

#error Cette bibliothèque ne fonctionne que sur Uno, Nano ou Mega

Ce rapport pourrait être plus détaillé avec
l'option "Afficher les résultats détaillés de la compilation"
activée dans Fichier -> Préférences.

et oui j'ai une pro micro c'est l'équivalent d'une Leonardo mais plus petit avec moins de pin

Je n'ai pas testé sur une leonardo, car je n'en ai pas, mais effectivement, c'est le même processeur, et cela devrait fonctionner. Va dans le répertoire MTobjects et supprime les fichiers MThardPWM.h et .cpp ainsi que MTservo.h .cpp MTservo4fils.h et .cpp; ils ne te servent à rien pour ce projet.

Ce n'est pas une erreur de taille trop grande, mon test du processeur n'est pas complet.

Merci alors je teste ton code en parallèle et la librairie JC rentre en confli avec une autre
Arduino : 1.8.16 (Windows 10), Carte : "Arduino Leonardo"

libraries\JC_Button-master\JC_Button.cpp.o (symbol from plugin): In function `Button::begin()':

(.text+0x0): multiple definition of `Button::begin()'

sketch\JC_Button.cpp.o (symbol from plugin):(.text+0x0): first defined here

libraries\JC_Button-master\JC_Button.cpp.o (symbol from plugin): In function `Button::begin()':

(.text+0x0): multiple definition of `Button::read()'

sketch\JC_Button.cpp.o (symbol from plugin):(.text+0x0): first defined here

libraries\JC_Button-master\JC_Button.cpp.o (symbol from plugin): In function `Button::begin()':

(.text+0x0): multiple definition of `Button::isPressed()'

sketch\JC_Button.cpp.o (symbol from plugin):(.text+0x0): first defined here

libraries\JC_Button-master\JC_Button.cpp.o (symbol from plugin): In function `Button::begin()':

(.text+0x0): multiple definition of `Button::isReleased()'

sketch\JC_Button.cpp.o (symbol from plugin):(.text+0x0): first defined here

libraries\JC_Button-master\JC_Button.cpp.o (symbol from plugin): In function `Button::begin()':

(.text+0x0): multiple definition of `Button::wasPressed()'

sketch\JC_Button.cpp.o (symbol from plugin):(.text+0x0): first defined here

libraries\JC_Button-master\JC_Button.cpp.o (symbol from plugin): In function `Button::begin()':

(.text+0x0): multiple definition of `Button::wasReleased()'

sketch\JC_Button.cpp.o (symbol from plugin):(.text+0x0): first defined here

libraries\JC_Button-master\JC_Button.cpp.o (symbol from plugin): In function `Button::begin()':

(.text+0x0): multiple definition of `Button::pressedFor(unsigned long)'

sketch\JC_Button.cpp.o (symbol from plugin):(.text+0x0): first defined here

libraries\JC_Button-master\JC_Button.cpp.o (symbol from plugin): In function `Button::begin()':

(.text+0x0): multiple definition of `Button::releasedFor(unsigned long)'

sketch\JC_Button.cpp.o (symbol from plugin):(.text+0x0): first defined here

libraries\JC_Button-master\JC_Button.cpp.o (symbol from plugin): In function `Button::begin()':

(.text+0x0): multiple definition of `Button::lastChange()'

sketch\JC_Button.cpp.o (symbol from plugin):(.text+0x0): first defined here

collect2.exe: error: ld returned 1 exit status

exit status 1

Erreur de compilation pour la carte Arduino Leonardo

Ce rapport pourrait être plus détaillé avec
l'option "Afficher les résultats détaillés de la compilation"
activée dans Fichier -> Préférences.

j'ai fais ce que tu ma dis et j'obtiens cette erreur

Arduino : 1.8.16 (Windows 10), Carte : "Arduino Leonardo"

text section exceeds available space in boardLe croquis utilise 29186 octets (101%) de l'espace de stockage de programmes. Le maximum est de 28672 octets.

Les variables globales utilisent 1761 octets (68%) de mémoire dynamique, ce qui laisse 799 octets pour les variables locales. Le maximum est de 2560 octets.

Sketch too big; see https://support.arduino.cc/hc/en-us/articles/360013825179 for tips on reducing it.

Erreur de compilation pour la carte Arduino Leonardo

Ce rapport pourrait être plus détaillé avec
l'option "Afficher les résultats détaillés de la compilation"
activée dans Fichier -> Préférences.