Vitesse progressive d'un moteur à courant continu en un temps déterminé

Bonsoir
Je souhaiterai construire un montage et un programme qui, lorsque l'on appuie sur un bouton, démarre un moteur à courant continu en passant progressivement de 0 à sa vitesse maximum en 5 secondes. Le moteur doit continuer à tourner tant que l'on a pas appuyé une deuxième fois sur le bouton. Sachant que l'instruction delay() exige un temps en milliseconde, j'ai calculer 5000/255 qui donne environ 20.

#include "MTcheckButton.h"// V1.0.0 Voir http://arduino.dansetrad.fr/MTobjects

const byte boutonCommande = 3;
int VitesseMCC = 0;
byte pinMoteur = 6;
boolean lecture = LOW;


void enclenchement(void){
  for(int i=1; i<255; i++){
    VitesseMCC ++;
    analogWrite(pinMoteur,VitesseMCC);
    //delay(20);
  }
  analogWrite(pinMoteur,255);   
}

void arret(void){
  VitesseMCC = 0;
  analogWrite(pinMoteur,VitesseMCC);
}

MTcheckButton BoutonMarcheAvant(boutonCommande, enclenchement, arret);

void setup(){
}
void loop(){
}

Le problème est que la progression ne se voit pas lorsqu'il n'y a pas de delay() et que lorsque j'ajoute un delay(), mon moteur ne démarre pas. Comment pourrait-je solutionner ce problème ?

Cordialement

Bonjour,

Le problème avec la bibliothèque MTobjects c'est que les fonctions sont appelées en interruption, ce qui limite fortement les actions qu'elles peuvent faire. En particulier delay() ne fonctionne pas en interruption.
Trouve une autre bibliothèque pour gérer ton bouton ou passe toi de bibliotheque (c'est un très bon exercice).

Bonjour
Voici un programme que j'ai écrit sans aucune bibliothèque:

const byte boutonCommande = 3;
int VitesseMCC = 0;
byte pinMoteur = 6;

void setup() {
  // put your setup code here, to run once:
  pinMode(boutonCommande, INPUT_PULLUP);
  pinMode(pinMoteur,OUTPUT);
}

void loop() {
  // put your main code here, to run repeatedly:
  boolean etatBoutonCommande=digitalRead(boutonCommande);
  if(etatBoutonCommande == LOW){
    boolean lecture = LOW;
    if(lecture == LOW){
      lecture == HIGH;
      for(int i=1; i<255; i++){
      VitesseMCC ++;
      analogWrite(pinMoteur,VitesseMCC);
      delay(20);
      }
      while(lecture == HIGH){
        analogWrite(pinMoteur,255);
      }
    }
   
    if(lecture == HIGH){
      lecture == LOW;
      while(lecture == LOW){
        analogWrite(pinMoteur,0);
      }
    } 
  }
}

Le soucis que je rencontre est que lorsque j'appuie une deuxième fois sur le bouton poussoir le moteur s'arrête un moment puis recommence à tourner, alors que je voudrais qu'il reste à l'arrêt tant que je n'ai pas appuyé une troisième fois sur le bouton. Quelle astuce pourrait-je utiliser pour arriver à ce que je veux ?

Cordialement

Utiliser un "drapeau".
Un "drapeau" c'est le petit nom que l'on donne à une variable booléenne dont tu testes l'état vrai ou faux (true or false).

A chaque appui sur le bouton, tu inverses sa valeur.
Si je ne me trompe pas (je n'ai pas vérifié et moi, il faut que je vérifie) ce doit être une instruction comme :
Si le "drapeau" se nomme controle
controle = !controle ;

Si controle = false, tu ne fais rien.
Si controle = true :
tu inverses sa valeur puis tu lances le moteur.

Parfaitement, pourquoi chercher des complications alors qu'un simple condensateur de 100 nF placé en parallèle sur le contact fait la même chose en mieux sans avoir à écrire la moindre ligne de code :grinning:.

J'ai essayé le code suivant:

const byte boutonCommande = 3;
int VitesseMCC = 0;
const byte pinMoteur = 6;
bool drapeau = 0;
void setup() {
  // put your setup code here, to run once:
  pinMode(boutonCommande, INPUT_PULLUP);
  pinMode(pinMoteur,OUTPUT);
}

void loop() {
  // put your main code here, to run repeatedly:
  boolean etatBoutonCommande=digitalRead(boutonCommande);
  if((!digitalRead(boutonCommande))){
    if(drapeau == 0 && etatBoutonCommande == LOW){
      drapeau = 1;
      for(int i=1; i<255; i++){
        VitesseMCC ++;
        analogWrite(pinMoteur,VitesseMCC);
        delay(20); 
        analogWrite(pinMoteur,255);
      }
    }
    if(drapeau == 1 && etatBoutonCommande == LOW){
       analogWrite(pinMoteur,0);
    }
  }
}

Le moteur tourne jusqu'à la vitesse maximum puis s'arrête définitivement même si l'on rappuie sur le bouton. J'ai très probablement écrit quelque chose incorrectement. Serait il possible d'avoir une proposition de modification ?

Cordialement

Avant de coder, il faut faire une description fidèle de ce que l'on veut obtenir.
Ton besoin tombe parfaitement dans l'utilisation d'une machine à état.

1 Like

Au lieu de tester l'état du bouton, il faudrait tester son changement d'état et en particulier s'il vient d'être enfoncé. Pour cela il faut comparer l'état du bouton à son état que tu auras mémorisé au cycle précédent.
Ce qui donne ceci (par exemple)

const byte boutonCommande = 3;
int VitesseMCC = 0;
const byte pinMoteur = 6;
bool drapeau = false;

void setup() {
  // put your setup code here, to run once:
  pinMode(boutonCommande, INPUT_PULLUP);
  pinMode(pinMoteur, OUTPUT);
}

void loop() {
  static bool etatBoutonPrecedent = false;
  
  bool etatBoutonCommande = !digitalRead(boutonCommande); // on travaille en logique positive
  if (etatBoutonCommande != etatBoutonPrecedent)
  {
    if (etatBoutonCommande)
    {
      // on a appuyé sur le bouton
      if (drapeau==false)
      {
        // on lance le moteur
        VitesseMCC = 0;
        for (int i = 1; i < 255; i++) {
          VitesseMCC ++;
          analogWrite(pinMoteur, VitesseMCC);
          delay(20);
        }
        drapeau = true; // le moteur est en marche
      }
      else
      {
        // on arrete le moteur
        analogWrite(pinMoteur, 0);
        drapeau = false;
      }
    }
    etatBoutonPrecedent = etatBoutonCommande;
    delay(20);  // pour anti rebond
  }
}

@fdufnews Je ne manquerai pas d'y jeter un oeil.

@kamill Merci infiniment. Le moteur fonctionne bien comme voulu.

  1. En quoi avoir mis static devant bool pour la variable "etatBoutonPrecedent" est-il important ?
  2. Qu'est-ce que le rebond ?

Cordialement

static permet de conserver la valeur de la variable à chaque appel de la fonction. On peut aussi utiliser une variable globale qui est statique par définition.

Les rebonds se produisent quand tu appuies sur (ou relâches) un bouton. Au lieu d'avoir une transition bien franche tu as des rebonds mécaniques qui provoquent une série d'états haut et bas parasites. Ca dépend en grande partie de la qualité du bouton, mais aucun bouton n'en est totalement exempt.
On peut les traiter soit par hard (voir le post de @68tjs) soit par soft, soit les deux.

1 Like

C'est comme une balle qui rebondi sur le sol.
Rebond, rebondir, il y a des origines communes :grinning:

Le contact mobile vient frapper le contact fixe et fait comme la balle : elle quitte le sol par rebond. Au début, elle monte haut, puis petit à petit, en perdant de l'énergie, elle monte de moins en moins haut et fini par rester au sol.
Ce qui veut dire :

  1. que les rebonds sont multiples, il n'y en a jamais qu'un seul
  2. que chaque rebond est plus court que son précédent.

Je prends le schéma classique de câblage d'un bouton :

  • Le contact est placé entre la masse et une entrée du micro.
  • On active la résistance "pull-up" interne du micro qui fait autour de 50 kilos ohms.
  • Au repos, le contact du bouton est ouvert et l'entrée du micro est à Vcc par l'intermédiaire de la pull-up.
  • Quand les lames du contact se touchent, l'entrée du micro reçoit un 0 V.

Les rebonds vont se traduire par la détection d'une suite de niveaux LOW et HIGH.

Le traitement soft ou logiciel consiste (en gros) à introduire une temporisation et à tester que la fonction digitalRead() retourne toujours la même valeur.

Le traitement "Hard", je préfère le terme "matériel" consiste à placer un condensateur en parallèle sur le contact.

Avant l'appui sur le bouton, le condensateur est chargé à Vcc par l'intermédiaire de la pull-up.

Au premier appui, le condensateur est instantanément et complètement court-circuité par le contact.
Quand le contact s'ouvre par rebond, le condensateur commence à se charger à travers la pull-up.

Mais cela prend du temps avant que la tension aux bornes du condensateur soit suffisante pour que le micro la considère comme un niveau haut, Au fur et mesure des rebonds les lames se retouchent (la balle retouche le sol) et déchargent régulièrement le condensateur.
En conséquence, tant que le bouton reste enfoncé, le micro ne peut que détecter un niveau bas.

Avec un bouton contact habituel, une valeur de 100 nF associé à la pull-up convient dans 99 % des cas.
Avec un gros contacteur massif conçu pour plusieurs ampères, comme l'a écrit Kamil, il serait préférable d'associer les deux solutions.

Voilà l'état des lieux, tu choisis la solution qui te convient le mieux.

Étant un ancien électronicien, je ne peux imaginer d'autre solution que le condensateur. :grinning:

Mais bien naturellement, je comprends parfaitement qu'un non-électronicien n'a pas envie de câbler des composants alors qu'il peut s'en dispenser avec des lignes de code. :sleepy:

Désolé, mais delay fonctionne parfaitement dans les fonctions appelées par MTobjects. C'est d'ailleurs le principal intérêt. Je ferai un tuto pour monter qu'on peut même interrompre un delay par un autre.

Réponse tardive, j'ai éteint mon téléphone et j'avais oublié le code pin. C'est d'ailleurs un comble pour un utilisateur de microcontrôleur d'avoir un problème basique de pin. Sur ma uno j'ai 20 pins que je maitrise, sur mon téléphone je n'en ai qu'une que je ne maitrisais pas.

Bonjour @vileroi,

Mea Culpa.
Suite à ton message j'ai regardé de nouveau le programme de @enash et effectivement
ses problèmes ne semblent pas venir du delay() mais sans doute du fait qu'il utilise analogWrite() sur la pin 6, alors que dans ta doc tu as indiqué qu'il ne faut pas utiliser analogWrite() sur les pins 5 et 6.

Bonsoir,
Effectivement, j'ai remplacé "6" par "9" dans le programme et tout fonctionne aussi. Merci infiniment

Cordialement

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.