IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Arduino Discussion :

millis() ne change pas


Sujet :

Arduino

  1. #1
    Futur Membre du Club
    Homme Profil pro
    retraité
    Inscrit en
    octobre 2013
    Messages
    11
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Haute Saône (Franche Comté)

    Informations professionnelles :
    Activité : retraité

    Informations forums :
    Inscription : octobre 2013
    Messages : 11
    Points : 7
    Points
    7
    Par défaut millis() ne change pas
    Bonjour
    Je veux étalonner la vitesse d'un moteur en fonction de la largeur d'impulsion d'un port Arduino. J'ai écrit un script qui compte le temps entre 10 tours du moteur (il y a un capteur ). J'utilise 2 variables, 'départ' et 'arrivee', qui lisent millis(). Or, bien qu'il s'écoule plusieurs secondes à vitesse lente pour ces 10 tours, depart et arrivee contiennent la même valeur. Voyez-vous où je me suis trompé ?

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    int pinVitesse = 6;   
    int pinHall = 2;// le capteur de tours
    int alpha;
    unsigned long arrivee; 
    int n;
     
    unsigned long depart;
     byte compte=0;
    byte valid;
    unsigned long delai;
     
    void setup() {
      pinMode(pinVitesse,OUTPUT);
      pinMode(pinHall, INPUT_PULLUP);
      analogWrite(pinVitesse, 0); 
      Serial.begin(9600);
      Serial.println("depart");
      delay(5000);
    }
     
    void loop() {
      for (n=2;n<16;n++){ 
        if(n<15){alpha=n*16;} else {alpha=255;}// alpha prendra les valeurs 32, 48,...255 
        analogWrite(pinVitesse, alpha); //lance le moteur
        Serial.print("alpha : ");
        Serial.println(alpha);   
        delay(5000); //délai de stabilisationde la vitesse
        valid=1; //autorisela lecture des impulsions Hall
     
        while(compte<=10){
          while(digitalRead(pinHall)!=HIGH){// attente d'une impulsion signalant un tour effectué
            //delay(1);
          } 
           if (valid==1){//première impulsion Hall : démarrage du décompte des tours
              depart=millis();
              Serial.println(depart,DEC);
              compte=0;
              valid=0;
           }
           else{
              compte++; // impulsions suivantes
           }  
        }
       arrivee=millis();// on a effectué 10 tours, on relève millis()
       Serial.println(compte);
       Serial.println(arrivee,DEC);
       analogWrite(pinVitesse, 0); 
        delai=arrivee - depart;// le temps passé pour 10 tours
       Serial.print(", 10 tours en  ");
       Serial.print(delai, DEC);
       Serial.println(" ms");
       delay(5000);
       valid=1;  // nouveau cycle avec le alpha suivant  
       compte=0;
      }
    }
    Extrait du moniteur :
    19:51:29.372 -> alpha : 80
    19:51:34.372 -> 40002
    19:51:34.372 -> 11
    19:51:34.372 -> 40003
    19:51:34.425 -> , 10 tours en 1 ms

  2. #2
    Membre chevronné
    Avatar de jpbbricole
    Homme Profil pro
    Retraité des réseaux informatiques
    Inscrit en
    février 2013
    Messages
    969
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Suisse

    Informations professionnelles :
    Activité : Retraité des réseaux informatiques
    Secteur : High Tech - Électronique et micro-électronique

    Informations forums :
    Inscription : février 2013
    Messages : 969
    Points : 2 171
    Points
    2 171
    Par défaut
    Bonsoir aschepens

    Pourquoi n'avoir pas persisté dans l'usage de l'interruption, ça simplifie nettement le comptage des impulsions et, de par là, leur chronométrage.

    Cordialement
    jpbbricole
    L'expérience est la seule chose qu'il ne faut acheter que d'occasion!

  3. #3
    Futur Membre du Club
    Homme Profil pro
    retraité
    Inscrit en
    octobre 2013
    Messages
    11
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Haute Saône (Franche Comté)

    Informations professionnelles :
    Activité : retraité

    Informations forums :
    Inscription : octobre 2013
    Messages : 11
    Points : 7
    Points
    7
    Par défaut
    Bonsoir Jpbbricole
    Merci pour votre réponse. En fait, en utilisant une interruption sur le pinHall, j'obtenais le même problème et j'ai pensé essayer autre chose.
    Je ne comprends vraiment pas ce comportement : c'est une façon de faire très classique et il me semble que mon script consulte millis() à des moment très différents.

  4. #4
    Membre chevronné

    Homme Profil pro
    Directeur de projet
    Inscrit en
    mai 2013
    Messages
    706
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Yvelines (Île de France)

    Informations professionnelles :
    Activité : Directeur de projet
    Secteur : Service public

    Informations forums :
    Inscription : mai 2013
    Messages : 706
    Points : 2 055
    Points
    2 055
    Par défaut Trop vite
    Bonjour,

    Il y a 2 setup et 2 loop.

    Il faut attendre que Hall soit retombé avant de relancer la boucle. Sinon le délai mesuré est celui de la durée de l'état 1 du Hall (arrondi à la ms).
    Par ailleurs on peut se passer de valide en utilisant compte = -1 avant le comptage effectif.

    Par exemple (non testé) :
    Code C++ : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
       compte = -1;
       while(compte <= 10){
          while(!digitalRead(pinHall));              // attendre impulsion signalant tour effectué
          if(compte < 0) {                           // 1e impulsion : démarrage du décompte des tours
             depart = millis();
             Serial.println(depart,DEC);
          }
          compte++;
          while(digitalRead(pinHall));               // Attendre fin de l'impulsion
       }
    Salutations
    Ever tried. Ever failed. No matter. Try Again. Fail again. Fail better. (Samuel Beckett)

  5. #5
    Membre chevronné
    Avatar de jpbbricole
    Homme Profil pro
    Retraité des réseaux informatiques
    Inscrit en
    février 2013
    Messages
    969
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Suisse

    Informations professionnelles :
    Activité : Retraité des réseaux informatiques
    Secteur : High Tech - Électronique et micro-électronique

    Informations forums :
    Inscription : février 2013
    Messages : 969
    Points : 2 171
    Points
    2 171
    Par défaut
    Bonjour aschepens
    Citation Envoyé par aschepens Voir le message
    Bonsoir Jpbbricole
    Merci pour votre réponse. En fait, en utilisant une interruption sur le pinHall, j'obtenais le même problème et j'ai pensé essayer autre chose.
    Je pense que l'usage de l'interruption rend les choses plus faciles, voici ma façon de voire la chose:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    const int pinHall = 2;
     
     
    int toursNombre = 10;
    volatile int toursComptage = 0;
     
    unsigned long toursNombreMillis = 0;
    unsigned long toursNombreDuree = 0;
     
     
    void setup() 
    {
    	pinMode(pinHall, INPUT_PULLUP);
     
    	Serial.begin(9600);
    	attachInterrupt(digitalPinToInterrupt(pinHall), interruptToursComptage, RISING);
     
    	Serial.println("depart");
    }
     
    void loop() 
    {
    	if (toursComptage == 1 && toursNombreMillis == 0)     // Si chrono à l'arrêt redémarrage d'une nouvelle séquence.
    	{
    		toursNombreMillis = millis();
    	}
     
    	if (toursComptage >= toursNombre)     // Si nombre de tours de mesure faits
    	{
    		toursNombreDuree = millis()-toursNombreMillis;
    		Serial.print("Duree pour " + String(toursNombre) + " tours = ");
    		Serial.println(String(toursNombre) + " = " + String(toursNombreDuree) + " millisecondes");
     
    		toursComptage = 0;
    		toursNombreMillis = 0;
    	}
     
    }
     
    void interruptToursComptage()
    {
    	toursComptage ++;
    }
    Cordialement
    jpbbricole
    L'expérience est la seule chose qu'il ne faut acheter que d'occasion!

  6. #6
    Membre expert

    Homme Profil pro
    mad scientist :)
    Inscrit en
    septembre 2019
    Messages
    2 006
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : mad scientist :)

    Informations forums :
    Inscription : septembre 2019
    Messages : 2 006
    Points : 3 745
    Points
    3 745
    Par défaut
    Salut

    il faut toujours mettre une section critique (bloquer les interruptions, faire une copie des variables sur lesquelles on fait un calcul par exemple puis réactiver les interruptions) quand on travaille sur des variables partagées avec une ISR (sauf si on est capable de garantir l'atomicité d'une opération ce qui est rarement le cas).


    Attention aussi aux test par égalité
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
     if (toursComptage == toursNombre)
    si vous n'avez pas de bol il y aura eu deux interruptions pendant que la boucle faisait autre chose et vous aurez dépassé toursNombre, l'égalité ne sera donc plus jamais vérifiée (enfin il faudra attendre que le int revienne à zéro et recommence)
    ==> il vaut mieux tester une inégalité

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
     if (toursComptage >= toursNombre)

  7. #7
    Membre chevronné
    Avatar de jpbbricole
    Homme Profil pro
    Retraité des réseaux informatiques
    Inscrit en
    février 2013
    Messages
    969
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Suisse

    Informations professionnelles :
    Activité : Retraité des réseaux informatiques
    Secteur : High Tech - Électronique et micro-électronique

    Informations forums :
    Inscription : février 2013
    Messages : 969
    Points : 2 171
    Points
    2 171
    Par défaut
    Bonjour Jay M
    Citation Envoyé par Jay M Voir le message
    Salut

    ==> il vaut mieux tester une inégalité
    J'y avais pensé mais oublié! c'est corrigé.

    Cordialement
    jpbbricole
    L'expérience est la seule chose qu'il ne faut acheter que d'occasion!

  8. #8
    Futur Membre du Club
    Homme Profil pro
    retraité
    Inscrit en
    octobre 2013
    Messages
    11
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Haute Saône (Franche Comté)

    Informations professionnelles :
    Activité : retraité

    Informations forums :
    Inscription : octobre 2013
    Messages : 11
    Points : 7
    Points
    7
    Par défaut
    Bonjour et merci pour toutes ces réponses.
    Guessey, oui, les 2 loop et les 2 setup sont dûs à un mauvais copier-coller lorsque j'ai remplacé mon script initial par un script commenté. C'est réparé... la variable valid(ation) m'est nécessaire puisque la vitesse doit se stabiliser et il faut que je repère une impulsion Hall pour démarrer le comptage au début d'un tour et non pas de façon aléatoire. Merci pour l'idée d'attendre que l'impulsion Hall retombe : je n'avais pas vu que ça pouvait être source de problème.

    Jay, oui, bon raisonnement pour préférer le test d'inégalité à l'égalité. Je vais aussi piocher l'aspect section critique.

    Jpbbricole, je pense que vous avez raison pour l'utilisation des interruptions et j'avais commencé par là.

    Mon souci était que millis() semblait ne pas (ou presque) changer de valeur. J'ai branché un oscillo pour voir les impulsions Hall et j'ai vu l'origine du problème : mes implsions font 10 volts, donc trop pour Arduino et j'ai fait un pont divisuer avec deux résistances de 100 kohms : j'ai bien 5v au point milieur. Mais quand je connecte ce point au pin 2, la valeur tombe à 2.5 volts et ça ne suffit pas pour définir l'état haut, je pense. J'ai mis un pont de deux resistances de 10kohms et ça marche.
    Je suis quand même étonné que l'impédance d'entrée d'une broche d'Arduino soit très inférieure à 50Kohms... la réistance de pull-up ?

  9. #9
    Membre chevronné

    Homme Profil pro
    Directeur de projet
    Inscrit en
    mai 2013
    Messages
    706
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Yvelines (Île de France)

    Informations professionnelles :
    Activité : Directeur de projet
    Secteur : Service public

    Informations forums :
    Inscription : mai 2013
    Messages : 706
    Points : 2 055
    Points
    2 055
    Par défaut O temps suspend ton vol
    Bonjour,

    Citation Envoyé par aschepens Voir le message
    ...la variable valid(ation) m'est nécessaire puisque la vitesse doit se stabiliser...
    L'utilisation de compte initialisée à -1 fait le même travail et banalise la boucle. De plus cela peut être une variable locale.

    Je ne suis pas sûr que l'interruption soit utile ici car elle n'épargne pas l'obligation que loop() tourne au moins deux fois plus vite que le temps le plus court pour faire un tour puisque c'est elle qui manipule le chrono. Il n'y a donc aucun avantage (si ce n'est pédagogique) à utiliser une interruption car les contraintes ne tombent pas et aucun gain de précision n'en résulte..

    Cela serait différent si loop() se donnait un temps de mesure par exemple 1 s (2, 4, 8... au hasard) et relevait alors le compteur. Dans ce cas la section critique serait la bienvenue.

    Autre approche, en utilisant 2 pulsein(), un sur le haut et un sur le bas, on peut obtenir assez facilement une valeur de temps de rotation en microsecondes mais il faut guetter l'impulsion.

    Salutations
    Ever tried. Ever failed. No matter. Try Again. Fail again. Fail better. (Samuel Beckett)

Discussions similaires

  1. Réponses: 13
    Dernier message: 27/06/2006, 11h20
  2. Réponses: 4
    Dernier message: 04/06/2006, 14h35
  3. [WinCE/PDA] Pourquoi touche TAB ne change pas le focus ?
    Par zitoun dans le forum Windows Mobile
    Réponses: 7
    Dernier message: 24/04/2006, 09h26
  4. [POO] La valeur de l'attribut ne change pas...
    Par slydemusli dans le forum Langage
    Réponses: 3
    Dernier message: 26/03/2006, 12h10
  5. Frames : adresse ne change pas
    Par polo-j dans le forum Balisage (X)HTML et validation W3C
    Réponses: 6
    Dernier message: 14/02/2005, 16h56

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo