Exemple: Enchainements

QuickStep permet d'enchaîner des rotations sans ralentir. Ici est expliqué pourquoi si on envoie les ordres de rotation d'un pas à la fois, que cela fonctionne encore avec une base de temps de 80µs.

Liens

Pour faire fonctionner cet exemple, il faut soit télécharger QuickStepExemples.zip contenant tous les fichiers d'exemples, soit télécharger Enchainements.zip contenant cet exemple, soit créer un répertoire du nom de l'exemple et mettre dedans:
- le fichier Enchainements.ino de l'exemple
- le fichier de configuration QuickStepConf.h propre à cet exemple
- les trois fichiers (QuickStep.h, QuickStep.cpp et digitalWriteFast.h) pour avoir la bibliothèque (identiques pour toutes les applications)

QuickStepConf.h (extrait)

//  Hybride 200pas/tr en mode 16 micro-pas
#define UN_TOUR (200L*16) pas_ou_micro_pas
#define VITESSE_MAXI 80 micro_secondes_par_pas
#define STEP 2
#define DIR 5
#define ENABLE 8
#define NOMBRE_DE_PAS_MAXIMUM_SUR_16_BITS
#define NB_ORDRES_DANS_LA_PILE 3

Enchainements.ino (extrait)

#
  $menu = ":QS";
  include "QuickStep.h"

void setup()
{
  quickStepInit(); // Obligatoire pour utiliser QuickStep
  Serial.begin(115200);
  quickStepInfo();
}

void loop()
{ 
  // Un tour dans un sens, une seconde d'arrêt
  for (word i = 0; i < UN_TOUR; i++)
    quickStepRotation(1 pas_ou_micro_pas, VITESSE_MAXI); // Demande pour aller dans un sens
  quickStepWait(); // Attente de la fin du mouvement
  delay(1000); // Rotation 1s + attente 1s = 2s
  
  // Un tour dans l'autre sens, une seconde d'arrêt
  quickStepRotation(-UN_TOUR, VITESSE_MAXI); // Demande pour aller en sens inverse
  quickStepWait(); // Attente de la fin du mouvement
  delay(1000); // Rotation 1s + attente 1s = 2s
}

Dans cet exemple, on montre que l'on peut enchaîner les ordres sans rajouter de temps intermédiaire. C'est toujours un programme un tour dans un sens un tour dans l'autre, mais l'aller est décomposé en 3200 mouvements d'un micro-pas. Pour pouvoir enchaîner les ordres, il faut que la pile contienne au moins deux places. Comme on n'a comme choix que 1 ou 3, c'est une pile de 3 ordres qui est choisie par #define NB_ORDRES_DANS_LA_PILE 3.

Pour que cela puisse se faire à la bonne vitesse, il faut que les ordres arrivent assez rapidement. Entre deux pas, il faut avoir le temps de traiter quickStepRotation (65µs environ) et une interruption qui fait avancer d'un pas (9µs) ainsi que le temps de la boucle. Il faut donc compter sur plus de 80µs. C'est le temps qui est mis dans la configuration. La vitesse est de 234 tr/mn (c'est quickStepInfo() qui l'affiche).

Si on tourne plus vite, comme quelques ordres sont mémorisés, pendant que le moteur démarre, on va remplir la pile des ordres (3 places donc 3 ordres). Pendant les premiers pas, on va continuer à envoyer des ordres d'avancer, mais pas assez vite. Peu de temps après, il n'y aura plus d'ordre dans la pile, le moteur s'arrête. Du coup de nouveaux ordres continuent d'arriver et le moteur redémarre. Cela se traduit avec un temps mort supplémentaire de 2 périodes d'horloge (une pour s'arrêter et une pour démarrer). On va donc avoir de temps en temps 2 impulsions qui manquent. Avec un temps entre impulsions de 75µs, on a 18 impulsions suivi de 2 temps d'arrêt. Il y a donc un ralentissement. A 77µs, ce sera 40 impulsions avent d'avoir les deux impulsions qui manquent. La différence de vitesse n'est pas brusque, mais la musique du moteur change légèrement. Voici le chronogramme que l'on peut observer pour un temps de 75µs:

En haut les impulsions STEP pour le moteur. En bas, c'est l'activité de quickStepRotation: ce signal monte quand on entre dans la fonction et redescend quand on en sort. En rouge des traits qui donnent pour chaque ordre donné par quickStepRotation l'impulsion STEP générée.
(1) L'ordre de mouvement est arrivé un peu juste et pour la fonction d'interruption la pile est vide. Le programme arrête le moteur, et l'interruption prend un peu plus de temps. Du coup quickStepRotation est obligé d'attendre et elle dure plus longtemps.
(2) quickStepRotation remet un ordre d'avancer dans la pile (impulsion 4), durée 65µs
(3) quickStepRotation met un deuxième ordre d'avancer dans la pile. Comme on est en phase de démarrage, la fonction est interrompue. Le temps est supérieur à 65µs.
(4) la fonction d'interruption envoie ou pas les impulsions sur des moments réguliers, espacés de 75µs. C'est la base de temps. Les impulsions ne peuvent pas être ailleurs.
(5) la fonction quickStepRotation débute un peu avant l'impulsion (4). Il y a à ce moment deux ordres dans la pile, on a la place d'en mettre un de plus, d'autant que le temps que cela se fasse, une impulsion aura fait disparaître un ordre. On en mettra jamais 3!
A partir de là, quickStepRotation + la boucle + l'interruption prennent plus de 75µs et le temps entre l'écriture d'un ordre et l'impulsion STEP correspondante diminue. En gros en 18 impulsions on n' appellé que 17 fois quickStepRotation. Il va manquer une impulsion et tout va recommencer.

Ce cas limite n'existe normalement pas. Avancer plusieurs fois d'un pas se fait si on veut aller sur un capteur de fin de course. Mais avec cette bibliothèque, on peut utiliser:

quickStepRotation(MIN_PAS, VITESSE_MAXI); // Demande pour aller vers le fin de course
while (digilalRead(finDeCourse) == NON_ACTIVE); // Attend d'être en fin de course
quickStepStopMoteur(); // Arrête le moteur
quickStepOrigine(); // Initialise le compteur des pas absolu