Motorlaufzeit und Programmlaufzeit stimmt nicht überein

Hallo Forum!
Bin absoluter Anfänger; Frage ist daher möglicherweise komisch.
Betreibe einen Steppermotor mit Pololu a4988. Ziel ist maximal genau eine Umdrehung pro Minute in Richtung1 in max kleinen Schritten und das über mehrere Minuten (einstellbar) und dann schnell zurück in Richtung 2.

Mit der Delay Variante und mit der Stoppuhr war das halbwegs genau. In der Folge - weil Delay ja böse - hab ich ein Programm geschrieben,

  • mit dem im Vorlauf auf Delays verzichtet wird
  • und bei dem eine Zeitkontrolle die einzelnen Umdrehungen und die gesamte Vorlaufzeit überwacht (Monitorausgabe).
    Damit kann ich eine sehr hohe Genauigkeit - wenige Hundertstel Sekunden nach 10 Minuten - erreichen (zumindest zeigt das die Zeitkontrolle so an). Kontrolliert man den Vorlauf mit der Stoppuhr gibts Abweichungen im Sekundenbereich (2-3 Sekunden nach 10 Minuten.
    Ist das normal…oder hab ich da was falsch gemacht?
    Programm hier:
/* +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Steppersteuerung --- mit Uno und Polulu Driver --- sketch_feb26g

Einzustellen: Anzahl der ganzen Umdrehungen, Steps pro Umdrehung,
Step high und Step low  mit 2 Stellmöglichkeiten
Automatischer Ausgleich der Abweichung mit manuellem Programmlaufzeitausgleich
Kontrolle über Monitor, Rücklauf schnell mit Delays, W.Röder Feb2021
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
*/
               //Variable
int steps;            // Schritte pro Umdrehung (3200)
int Um;               // Anzahl der Umdrehungen = Minuten Laufzeit
               // Zeiten
long time_0;         // - Beginn Vorlauf
long time_00;        // - Beginn Umdrehung
long time_a;         // - Start High
long time_b;         // - Start Low
long time_c;         // - Ende für eine Umdrehung
long time_d;         // - Ende für gesamten Vorlauf
long LZ_U;           // Laufzeit ab Vorlauf
long LZ_UU;          // Laufzeit Umdrehung
              // Impulse
long Hi;             // Impuls High
long Lo;             // Impuls Low
              // Auto Korrektur
long Korr0;          // Auto-Korrekturen bei Low
long Korr1;          // Diff pro Step als Ganzzahl teilbar durch 4
long KorrLo;         // Korrigierter Low Wert
int KorrKonst;       // Variable Korrektur - Ausgleich Programmablaufzeit

void setup() {
                                //Polulu Pins
  pinMode(6, OUTPUT); // Enable
  pinMode(5, OUTPUT); // Step
  pinMode(4, OUTPUT); // Richtung
  digitalWrite(6, LOW);
  digitalWrite(5, LOW);
  digitalWrite(4, HIGH);
                                // Schritteinstellung MS 1 - 3
  pinMode(8, OUTPUT); // MS 1     
  pinMode(9, OUTPUT); // MS 2
  pinMode(10, OUTPUT); // MS 3
  digitalWrite(8, HIGH);        // Schritteinstellung 1 - 3 lt. Polulu Tabell
  digitalWrite(9, HIGH);
  digitalWrite(10, HIGH);
                              /*MS1     MS2     MS3     Microstep Auflösung     
                                L     L     L     Full Step     
                                H     L     L     Half Step     
                                L     H     L     Quarter Step     
                                H     H     L     Eighth Step     
                                H     H     H     Sixteenth Step
                              */
  Serial.begin(9600);
                                // Variable Einstellungen
  Um = 10;                      // Anzahl ganzer Umdrehungen
  steps = 3200;                 // 1 U/min mit 1/8 Stepeinstellung
  Hi = 9340;                    // Impuls High in Microsekunden ~9340
  Lo = 9396;                    // Impuls Low in Microsekunden  ~9396
  KorrKonst = 56;               // Variable Korrektur - Ausgleich Programmablaufzeit ~44
  KorrLo = Lo;                  // Reset auf den Low Wert
                      // Ausgabe Grundeinstellungen
  Serial.print("Ganze Umdrehungen ");
  Serial.print(Um);
  Serial.println();
  Serial.print("Steps pro Umdrehung ");
  Serial.print(steps);
  Serial.println();
                     // es geht los in Richtung 1 - mit HIGH / LOW somit mit 2 Stellmöglichkeiten - Auflösung 4 micros
}                           
void loop() {
  digitalWrite(4, LOW);                      // Richtung
    time_0 = micros();                       // Startzeit vor allen Umdrehungen
  for (int u = 0; u < Um; u++) {             // int u = Umdrehungszähler
    Serial.println(" ");                     //Ausgaben am Monitor
    Serial.print("Umdrehung Nr. ");
    Serial.print(u+1);
    Serial.println();
    time_00 = micros();                       // Startzeit vor einer Umdrehung
  for (int s = 0; s < steps; s++) {           // int s = Stepzähler
      time_a = micros();                      //Startzeit high
      digitalWrite(5, HIGH);
      while (micros() - time_a < Hi) {        //Step high   (~5000 oder 9340)
        // do nothing
      }
      time_b = micros();                      //Startzeit low
      digitalWrite(5, LOW);
      while (micros() - time_b < KorrLo) {      //Step low = korregierter Low Wert
        // do nothing                           //Gesamtlaufzeit unter 60 sec/U Wert erhöhen  ... 
       }                                        //über 60sec/U Wert verringern                               
     }               // ->> Ende Stepschleife 
    time_c = micros();                        // Endzeit nach einer Umdrehung
    LZ_U = (time_c - time_0);                 // Laufzeit ab Beginn
    LZ_UU = (time_c - time_00);               // Laufzeit nach aktueller Umdrehung
    Korr0 = (LZ_U - (60000000 * (u + 1))) / steps;    // Korrekturwert je Step
    Korr1 = ((Korr0 / 4) * 4);                        // als Ganzzahl teilbar durch 4
    KorrLo = (Lo - ((Korr0 / 4) * 4) - KorrKonst);    // Korrigierter Low Wert
    
                     // Infos nach jeder Umdrehung
    Serial.println();
    Serial.print("Zeit in 1/1000 sec pro Umdrehung ");
    Serial.print(LZ_UU / 1000);
    Serial.println();
    Serial.print("Soll in Sekunden ");
    Serial.print(60 * (u + 1));
    Serial.println();Serial.print("Gesamtlaufzeit in 1/100 sec ");
    Serial.print(LZ_U / 10000);
    Serial.println();
    Serial.print("Korrekturbasis = Gesamtlaufzeit: ");
    Serial.print(time_c);
    Serial.print("-");
    Serial.print(time_0);
    Serial.print("=");
    Serial.print(LZ_U);
    Serial.println();  
    Serial.print("LZ Differenz zum Soll in Microsec. ");
    Serial.print(LZ_U - (60000000 * (u + 1)));
    Serial.println();
    Serial.print("Differenz pro Step ");
    Serial.print(Korr0);
    Serial.print(" = gerundet auf 4 Microsec Aufloesung ");
    Serial.print(Korr1);
    Serial.println();
    Serial.print("Low Impuls fuer naechste Umdrehung inc. KorrKonst. ");
    Serial.print(KorrLo);
    Serial.println();
    }                       // ->> Ende Umdrehungsschleife
    
    time_d = micros();                 // Laufzeitkontrolle vor dem Rücklauf
    Serial.println();
    Serial.print("Programmlaufzeit in 1/1000 sec ");
    Serial.print((time_d - time_0) / 1000);
    Serial.println();
                                      //Übergang zum Rücklauf mit delays
  delay(3000);
    for (int u = 0; u < Um; u++) {    // int u = Umdrehungszähler
    for (int s = 0; s < steps; s++)
  {
    digitalWrite(5, HIGH);
    delayMicroseconds(1000);
    digitalWrite(5, LOW);
    delayMicroseconds(500);
  }
  }
  delay(1000);
}

Danke für eure Hilfe
Werner

Zum einen ist der Taktgeber auf den Arduinos keine Präzisionsuhr. Je nachdem was da eingesetzt ist (Resonator/Quarz) kann das recht unterschiedlich große Abweichungen geben.
Zum zweiten ist deine Art die micros() einzusetzen auch nichts anderes als delay(). ( Du schreibst es ja auch noch hin 'do nothing' ). Eigentlich hast Du nur delay nachprogrammiert.
Da kommen dann zu den Delayzeiten auch noch die Programmlaufzeiten dazu - wobei die hier bei deinen Delay-Zeiten nicht allzusehr ins Gewicht fallen dürften.

Hallo Franz-Peter!

Danke für die Hinweise…
Soweit ich das aus den diversen Ratgebern herausgelesen habe, stoppt Delay den ganzen Programmablauf.
Die von mir verwendete Variante wurde als Ersatz für Delay - ohne das Programm zu stoppen - angepriesen.

for (int s = 0; s < steps; s++) { // int s = Stepzähler
time_a = micros(); //Startzeit high
digitalWrite(5, HIGH);
while (micros() - time_a < Hi) { //Step high (~5000 oder 9340)
// do nothing
}
time_b = micros(); //Startzeit low
digitalWrite(5, LOW);
while (micros() - time_b < KorrLo) { //Step low = korregierter Low Wert
// do nothing //Gesamtlaufzeit unter 60 sec/U Wert erhöhen …
} //über 60sec/U Wert verringern
}

Ich hätte das so verstanden, daß die “for Schleife” bei jedem Step

  • time a mit der aktuellen Zeit speichert
  • den Step Impuls ausgibt
  • die while Schleife solange durchläuft, bis die vergangene Zeit der HIGH Zeit entspricht (also nix tut)
  • und dann in der nächsten while Schleife das Spiel mit der LOW Zeit fortsetzt.

Was mich ratlos macht, ist der Umstand, daß (time_d - time_0) = Zeit zwischen Beginn der Umdrehungen und Ende des Vorlaufes - die ich am Monitor ausgebe - mit der gestoppten Realität so gar nicht übereinstimmt (3 Sekunden bei 10 min Laufzeit kommt mir viel vor. Auch wenn die einzelnen Programmschritte und Schleifen Durchläufe Zeit kosten, muß das doch in der Differenz enthalten sein.

Gruß
Werner

werner51:
Soweit ich das aus den diversen Ratgebern herausgelesen habe, stoppt Delay den ganzen Programmablauf.

Das ist richtig.

Die von mir verwendete Variante wurde als Ersatz für Delay - ohne das Programm zu stoppen - angepriesen.

      while (micros() - time_a < Hi) {        //Step high   (~5000 oder 9340)

// do nothing
      }

Das ist beim ersten Durchlauf knapp 10ms Für time_b auch.
Macht hier

for (int s = 0; s < steps; s++) {

für jeden Step 20ms.

Wenn Du für die Zeit nicht die Schleife bedienen willst, musst Du die Schleife in das “do nothing” einpacken…

Hallo Werner,

werner51:

  • die while Schleife solange durchläuft, bis die vergangene Zeit der HIGH Zeit entspricht (also nix tut)

Naja, und das ist doch das gleiche wie delay - da wird der gesamte Programmablauf angehalten und bleibt in der while-Schleife stehen, bis die Zeit abgelaufen ist. Das ist exakt das Gleiche, was delay() macht - in einer while-Schleife warten, bis die Zeit abgelaufen ist.

Wenn Du das ohne Anhalten des Programms machen willst, musst Du den ganzen Ablauf umbauen und darfst den loop nicht anhalten.

Was hast Du denn überhaupt für ein Board? Ist da ein Quarz, oder nur ein Resonator drauf. Die Resonatoren sind schon recht ungenau, was die Taktfrequenz angehtl

Ich habe das jetzt mal auf eine blockadefreie Variante umgeschrieben. Bei mir liegenden die Abweichungen - in Zeiten des seriellen Monitors gemessen (‘Zeitstempel anzeigen’) nach 10 Umdrehungen noch im Bereich. weiniger ms. Die Zeiten im micros() sind prinzipbedingt exakt. Die Korrekturwerte habe ich deshalb rausgeschmissen.
Die Anschlußpins habe ich ganz am Anfang festgelegt. Die musst Du wieder auf deine Pins zurückstellen. Man sollte den Pinnummern grundsätzlich am Anfang einem Namen zuordnen und die Nummern nicht im Programm selbst verwenden. So ist die Umstellung auf andere Pinnummern an einer zentralen Stelle schnell geschehen. Und wenn man vernünftige Namen wählt, sieht man im Sketch auch gleich was da umgestellt wird.

/* +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  Steppersteuerung --- mit Uno und Polulu Driver --- sketch_feb26g

  Einzustellen: Anzahl der ganzen Umdrehungen, Steps pro Umdrehung,
  Step high und Step low  mit 2 Stellmöglichkeiten
  Automatischer Ausgleich der Abweichung mit manuellem Programmlaufzeitausgleich
  Kontrolle über Monitor, Rücklauf schnell mit Delays, W.Röder Feb2021
  ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
*/
// Definition der Pinzuordnungen
const byte stepPin = 6;
const byte dirPin  = 5;
const byte enaPin  = 7;
const byte MS1Pin  = 8;
const byte MS2Pin = 9;
const byte MS3Pin = 10;
const byte zyklPin = 11;   // toggelt bei jeder Steptime ( nur für Test mit LA )

//Variable
int steps;            // Schritte pro Umdrehung (3200)
int stepCounter;
unsigned long lastStepTime;

int umZahl;          // Anzahl der Umdrehungen = Minuten Laufzeit
int umCount;          // Zähler für vollständige Umdrehungen
// Zeiten
long time_0;         // - Beginn Vorlauf
long time_00;        // - Beginn Umdrehung
long time_c;         // - Ende für eine Umdrehung
long time_d;         // - Ende für gesamten Vorlauf
long LZ_U;           // Laufzeit ab Vorlauf
long LZ_UU;          // Laufzeit Umdrehung
// Impulse
unsigned long stepTime = 18750;             // Zeit für einen Step

void setup() {
  //Polulu Pins
  pinMode(enaPin, OUTPUT); // Enable
  pinMode(stepPin, OUTPUT); // Step
  pinMode(dirPin, OUTPUT); // Richtung
  pinMode(zyklPin, OUTPUT);
  digitalWrite(enaPin, LOW);
  digitalWrite(stepPin, LOW);
  digitalWrite(dirPin, HIGH);

  // Schritteinstellung MS 1 - 3
  pinMode(MS1Pin, OUTPUT); // MS 1
  pinMode(MS2Pin, OUTPUT); // MS 2
  pinMode(MS3Pin, OUTPUT); // MS 3
  digitalWrite(MS1Pin, HIGH);        // Schritteinstellung 1 - 3 lt. Polulu Tabell
  digitalWrite(MS2Pin, HIGH);
  digitalWrite(MS3Pin, HIGH);
  /*MS1     MS2     MS3     Microstep Auflösung
    L     L     L     Full Step
    H     L     L     Half Step
    L     H     L     Quarter Step
    H     H     L     Eighth Step
    H     H     H     Sixteenth Step
  */

  Serial.begin(115200);
  while (!Serial);  // benötigt bei Leonardo/Micro
  // Variable Einstellungen
  umZahl = 10;                      // Anzahl ganzer Umdrehungen
  steps = 3200;                 // 1 U/min mit 1/16 Stepeinstellung
  //KorrKonst = 56;               // Variable Korrektur - Ausgleich Programmablaufzeit ~44
  //KorrLo = Lo;                  // Reset auf den Low Wert
  // Ausgabe Grundeinstellungen
  Serial.print("Ganze Umdrehungen ");
  Serial.print(umZahl);
  Serial.println();
  Serial.print("Steps pro Umdrehung ");
  Serial.print(steps);
  Serial.println();
  Serial.print("Soll in Sekunden ");
  Serial.print(60 * (umZahl));
  Serial.println();   // es geht los in Richtung 1 - mit HIGH / LOW somit mit 2 Stellmöglichkeiten - Auflösung 4 micros
  digitalWrite(dirPin, LOW);    // Richtung
  umCount = 0;                  // Umdrehungszähler auf Startwert
  stepCounter = 0;
  lastStepTime = micros();
  time_0 = micros(); // Startzeit
}
void loop() {
  // Prüfen, ob die Zeit für einen Step abgelaufen ist
  if ( micros() - lastStepTime > stepTime ) {
    digitalWrite( zyklPin, !digitalRead(zyklPin) );    // nur zur Messung mit LA
    if ( stepCounter > 0 ) {
      // Steppulse ist fällig
      digitalWrite( stepPin, HIGH );
      stepCounter -= 1;
      digitalWrite( stepPin, LOW ); // etwa ein 5µs Impuls, reicht für A4988
    }
    lastStepTime += stepTime;       // nächsten Zeitslot einstellen
  }

  if ( digitalRead( dirPin ) == LOW ) {
    // wir drehen vorwärts  >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
    if ( stepCounter == 0 ) {
      // der Motor steht
      time_00 = time_c;
      time_c = micros();                        // Endzeit nach einer Umdrehung
      LZ_U = (time_c - time_0);                 // Laufzeit ab Beginn
      LZ_UU = (time_c - time_00);               // Laufzeit nach aktueller Umdrehung
      // Infos nach jeder Umdrehung (  erst nach einer Umdrehung sinnvoll )
      if ( umCount > 0 ) {
        Serial.println();
        Serial.print("Zeit in 1/1000 sec pro Umdrehung ");
        Serial.print(LZ_UU / 1000);
        Serial.println();
        Serial.print("Gesamtlaufzeit in 1/100 sec ");
        Serial.print(LZ_U / 10000);
        Serial.println();
        Serial.println();
      }
      if ( umCount++ < umZahl ) {
        // die gewünschte Zahl der Umdrehungen ist noch nicht erreicht
        Serial.println(" ");                     //Ausgaben am Monitor
        Serial.print("Umdrehung Nr. ");
        Serial.print(umCount);
        Serial.println();
        stepCounter = steps;    // steps = Steps/Umdrehung
        time_00 = micros();                       // Startzeit vor einer Umdrehung
      } else {
        // gewünschte Umdrehungszahl erreicht, zurückdrehen
        time_d = micros();                 // Laufzeitkontrolle vor dem Rücklauf
        Serial.println();
        Serial.print("Programmlaufzeit in 1/1000 sec ");
        Serial.print((time_d - time_0) / 1000);
        Serial.println();
        //Übergang zum Rücklauf
        digitalWrite( dirPin, HIGH );
        stepCounter = steps * umZahl;
        stepTime = 1875;    // zurück mit 10-facher Geschwindigkeit
      }
    }
  } else {
    // wir drehen Rückwärts <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
    if ( stepCounter == 0 ) {
      // Stepper ist wieder vorn angekommen, wieder von vorn
      umCount = 0;
      delay(3000);     // hier ist noch ein delay() ... ;-)
      digitalWrite( dirPin, LOW );
      stepTime = 18750;

    }

  }

}

Du wirst allerdings ein wenig ‘umdenken’ müssen, um den Sketch zu verstehen :wink: . Der loop läuft ständig durch und bleibt nie irgendwo stehen. Die meiste Zeit dreht er nur im Kreis und macht gar nichts … ausser ein paar Abfragen, ob nicht doch endlich mal was zu tun ist :wink:

P.S. Da die MS1…MS3 bei mir fest verdrahtet sind, habe ich den entsprechenden Abschnitt auskommentiert. Das musst Du auch wieder zurückändern.

Edit: hab’ den Code nochmal etwas optimiert, und auch die MS1…M3 Pins am Amfang festgelegt und jetzt wieder im Code aktiviert.

MicroBahner:
Die Zeiten im micros() sind prinzipbedingt exakt.

Aber auch nur in den Grenzen der Genauigkeit des Resonators/Quartzes und bei den kleinen Arduinos nur in 4er Schritten.

Gruß Tommy

Ok, war vielleicht etwas knapp und missverständlich ausgedrückt. Gemeint sind die Zeiten für eine Umdrehung, die im seriellen Monitor ausgegeben werden, und auf Basis micros() ermittelt werden. Da auch die Steps auf Basis micros() generiert werden, müssen diese Zeiten prinzipiell ‘korrekt’ sein ( wenn kein grundsätzlicher Programmfehler drin ist ), denn letztendlich bedeutet dass, dass die Resonatorfrequenz auf Basis der Resonatorfrequenz gemessen wird.

Deshalb der Hinweis die Zeiten über den Zeitstempel im seriellen Monitor zu kontrollieren. Denn da ist die Zeitbasis der Takt im PC. Inwieweit der genauer ist, sei jetzt mal dahingestellt, aber es ist jedenfalls eine vom Arduino unabhängige Zeitbasis.

Hallo Franz Peter!
Danke für den neuen Sketch...werd das genau studieren.

Der Hinweis auf die Art des Boards war hilfreich bei der Fehlersuche...weil

ich 2 verschiedene Unos verwendet habe...Nr. 1 - ein böses China Teil - war fix verkabelt mit Treiber und Motor
Nr. 2 Made in Italy.....offensichtlich ein Original... hab ich zum Programmtesten verwendet.
Läuft des auf Nr. 2 entwickelte Programm auf Nr. 1 gibts bereits nach 3 Minuten eine Differenz von mehr als 3 Sekunden...(mit solchen Unterschieden hätt ich nie gerechnet)
Hab dann Treiber und Motor mit Nr. 2 verkabelt...und das funktioniert einwandfrei...noch Beep am Anfang und Ende eingebaut....(wegen der Stoppuhrauslösung) Zeitdifferenz bei Handstoppung war
im Bereich der Reaktionszeit.
Gruß
Werner

Hallo Franz-Peter!

..."Du wirst allerdings ein wenig 'umdenken' müssen, um den Sketch zu verstehen ;) . Der loop läuft ständig durch und bleibt nie irgendwo stehen. Die meiste Zeit dreht er nur im Kreis und macht gar nichts ... ausser ein paar Abfragen, ob nicht doch endlich mal was zu tun ist ;)...

Denk schon einige Zeit um.....aber ich durchblick das System noch nicht......kannst du bitte den logischen Ablauf verbal formulieren?
Gruß
Werner

Suche mal nach der Nachtwächtererklärung.

Gruß Tommy

'Nachtwächtererklärung' ist schonmal ein gutes Stichwort.

Versuch mal, dich gedanklich in den Prozessor reinzuversetzen, und durch das Programm zu navigieren. Letztlich läuft Du im loop immer im Kreis herum und prüfst an veschiedenen Stellen nur, ob Du jetzt im Moment etwas tun musst. Wenn nicht, wird nicht gewartet, sondern es geht einfach weiter zur nächsten 'Prüfstelle'. Und wenn Du unten beim letzten 'Prüfpunkt' angekommen bist, geht es oben wieder weiter.

Starten wir am Anfang von loop:

  • Prüfen, ob die Zeit für einen Step abgelaufen ist.
    wenn ja, weitere Prüfungen:

  • muss überhaupt ein Step ausgeführt werden ( stepCounter ist > 0 )

  • Step ausführen, und einen Step vom stepCounter abziehen
    Auf jeden Fall den Zeitmerker für den nächsten Step vorschieben

  • Als nächstes schaust Du - je nach aktueller Drehrichtung - nur in den jeweiligen Block. Die andere Drehrichtug interessiert nicht - da schaust Du garnicht rein. Und solange der Motor noch dreht ( also noch Steps auszuführen sind, stepCounter nicht 0 ) machst Du da auch nichts, sondern springst einfach weiter ans Ende vom loop - und wieder von vorn

  • Wenn der Motor steht, wurde eine Umdrehung ausgeführt. Jetzt werden die Messzeiten verwaltet.

  • wenn die gewünschte Zahl an Umdrehungen noch nicht erreicht wird, wird die nächste Umdrehung eingeleitet Dazu wird jetzt einfach stepCounter wieder auf die Steps/Umdrehung gestellt. Steps werden dann wiede in 1) erzeugt.

  • Wenn die gwünschte Umdrehungszahl erreicht ist, wird der Rücklauf eingeleitet ('Übergang zum Rücklauf')

  • Bist Du am Ende vom loop angekommen, gehts wieder bei 1 weiter. Da kann es durchaus sein, dass Du bei 1+2 festgestellt hast, dass nichts zu tun ist, und Du sozusagen 'leer' durch den loop kreist.

Hallo Franz-Peter!
Danke für deine Geduld!
....das erste if wird wohl FALSE sein

  • weil zwischen der aktuellen Zeit und der last Step Time wird weniger als 18750 vergangen sein ????
    ....somit hat das 2. if Pause (inclusive lastStepTime)
    das 3.if ist TRUE, das 4. auch TRUE...umCount wird 1
    nächsten 2 else nicht relevant
    ich bin wieder am Start und nix ist weitergegangen.

Tatsächlich dreht sich der Motor aber....daher hab ich was entscheidendes übersehen.
Gruß
Werner

Hallo Werner,
mach dich mit dem Gedanken vertraut, dass die meisten loop-Durchläufe ‘leer’ sind - also da nichts passiert. Der Prozessor ist so schnell, da ist das der Normalfall bei so langsamen Vorgängen. Aber irgendwann ist die Zeit dann doch abgelaufen und es passiert was :wink:

Hallo Arduinauten!

Habe - wie ich glaube…oder zumindest hoffe - Franz Peters Ratschläge umgesetzt… und versucht, das Nachtwächtergschichtl zu verinnerlichen.

Ergebnis ist ein universell veränderbarer Steuerungssketch. Da für mein Projekt nur der genaue Vorlauf relevant ist, hab ich im Rücklauf die Delays belassen.
Mit der Autokorrektur pendelt die Zeit zwischen den Umdrehungen schön hin und her…nach 10 Min ist das sehr genau.
…obs reicht, wird die Praxis zeigen.

Die vielen Kontrollausgaben sind eh nur für die Testerei relevant…werden im Endzustand verschwinden

/* +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Steppersteuerung --- mit Uno R3 und Polulu A 4988 Driver --- sketch_Stepper 1U Min mar16b
Polulu A 4988 ist mit allen Pins verkabelt und einstellbar.
Stepperanschluß: sw,gr,bl,rt (damit die Richtung stimmt)
Display zur Kontrolle.
Ziel: 1U/Min über mehrere Minuten, Vorlauf ohne Delay...und so genau wie möglich!
Schneller Rücklauf; einstellbar mit Delay.
Grundeinstellungen: Anzahl der ganzen Umdrehungen, Steps pro Umdrehung,
Steptime (Auflösung 4 Microsec) + auto Korrektur
Kontrolle über Display und Monitor.   W.Röder März 2021
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
*/
                                      // LCD einrichten
#include <Wire.h>                     // Wire Bibliothek einbinden
#include <LiquidCrystal_I2C.h>        // I2C Bibliothek (v. Brabander)einbinden
LiquidCrystal_I2C lcd(0x27, 16, 2);   // Displaytyp - HEX-Adresse 0x27
                                      // LCD Pins: GND, +,SDA auf A4,SCL auf A5
// Definition der Pinzuordnungen
const byte dirPin  = 4;     // Richtung
const byte stepPin = 5;     // Step
const byte enaPin  = 6;     // Enable
const byte MS1Pin  = 8;     // MS1
const byte MS2Pin  = 9;     // MS2
const byte MS3Pin  = 10;    // MS3

//Variable
int steps;                    // Schritte pro Umdrehung 
int stepCounter;              // Stepzähler
unsigned long stepTime;       // Stepzeit
int umZahl;                   // Anzahl der Umdrehungen = Minuten Laufzeit
int umCount;                  // Zähler für vollständige Umdrehungen

// Zeiten
unsigned long lastStepTime;   // Stepteilzeit
long time_0;                  // Beginn Vorlauf
long time_00;                 // Ende für gesamten Vorlauf
long LZ_U;                    // Laufzeit ab Vorlauf
long time_01;                 // Zwischenzeiten für Ausgabe
long time_02;
long time_03;

void setup() {

 pinMode(12, OUTPUT);         // LCD Sromversorgung
 digitalWrite(12, HIGH);
 lcd.init();                  // LCD gestartet 
 lcd.clear();
 lcd.backlight();             // Hintergrundbeleuchtung einschalten 
                                                                   
                              // Polulu Pins
  pinMode(enaPin, OUTPUT);    // Enable
  pinMode(stepPin, OUTPUT);   // Step
  pinMode(dirPin, OUTPUT);    // Richtung
  
                              // Polulu Grundeinstellung
  digitalWrite(enaPin, LOW);
  digitalWrite(stepPin, LOW);
  digitalWrite(dirPin, LOW);   

                               // Schritteinstellung MS 1 - 3
  pinMode(MS1Pin, OUTPUT);     // MS 1
  pinMode(MS2Pin, OUTPUT);     // MS 2
  pinMode(MS3Pin, OUTPUT);     // MS 3
  
  digitalWrite(MS1Pin, HIGH);   // Schritteinstellung 1 - 3 lt. Polulu Tabelle
  digitalWrite(MS2Pin, HIGH);
  digitalWrite(MS3Pin, HIGH);
                              /*MS1     MS2     MS3     Microstep Auflösung     STEPS
                                L       L       L       Full Step             200     
                                H       L       L       Half Step               400
                                L       H       L       Quarter Step             800
                                H       H       L       Eighth Step             1600
                                H       H       H       Sixteenth Step        3200      */
 Serial.begin(9600);                        
                                   // Variable Einstellungen
  umZahl = 10;                      // Anzahl ganzer Umdrehungen
  steps = 3200;                    // Steps für 1 U 
  stepTime = 18728;                // Lt. Tabelle - ca.Werte für 1 U/min) 
                                      //~ 299760 bei 200
                                      //~ 149980 bei 400
                                      //~  77940 bei 800
                                      //~  37460 bei 1600
                                      //~  18728 bei 3200
  
  umCount = 0;                     // Umdrehungszähler auf Startwert
  stepCounter = 0;                 // Stepzähler auf Startwert
  lastStepTime = micros();         // Startwert
  time_0 = micros();               // Startwert
  time_01 = micros();
  time_02 = micros();    
  }
void loop() {                      // ...los gehts in die Schleife
   if(umCount < umZahl){           // Der Kern der Sache...die Schrittgeber ifs
  digitalWrite(dirPin, LOW);   
  if(stepCounter < steps){
  digitalWrite(stepPin, HIGH);
  } 
    if(micros() - lastStepTime >= stepTime) {             
    digitalWrite(stepPin, LOW);
    lastStepTime = micros();
    stepCounter++;  
    }
}
  if(stepCounter == steps){      // Steps abgearbeitet = eine Umdrehung
  umCount++;                     // Umdrehungszähler +1
  
  time_01 = micros();            // Zwischenzeiten speichern
  time_03 = time_01-time_02;
  time_02 = micros();
                                 // Infos nach jeder Umdrehung  
  lcd.clear();
  lcd.setCursor(0, 0);          //Position des ersten Zeichens 1.Zeile 
  lcd.print("Ende Um.Nr. ");
  lcd.print(umCount);
  lcd.setCursor(0, 1);          //Position des ersten Zeichens 2.Zeile 
  lcd.print(time_03 / 1000);
  lcd.print(" MilliSec");
  Serial.println();
  Serial.print("Ende Umdrehung Nr. ");
  Serial.print(umCount);
  Serial.println();
  Serial.print("LZ dieser Umdrehung ");
  Serial.print(time_03);
  Serial.println();

if(time_03 < 60000000){           //optional...LZ Korrektur
  stepTime = (stepTime + 4);              //  |
}                                         //  |
if(time_03 > 60000000){                   //  |
  stepTime = (stepTime - 4);              //  v
}

   
  stepCounter = 0;                // Step Zähler zurücksetzen...Schleife 
                                  // nächste Umdrtehung
  }
//++++++++++++++++++++++++++++
  if(umCount == umZahl){        // Umdrehungszahl erreicht....dann Rücklaufsequenz
  time_00 = micros();           // prüfe Laufzeit
  LZ_U = time_00 - time_0;      // prüfe Laufzeit
  
                                // Daten am Display
  lcd.clear();
  lcd.setCursor(0, 0);          // Position des ersten Zeichens 1.Zeile 
  lcd.print("LZt: ");
  lcd.print(LZ_U);                               
  lcd.setCursor(0, 1);          // Position des ersten Zeichens 2.Zeile 
  lcd.print("Um&Stp: ");
  lcd.print(umCount);                                    
  lcd.print(" ");            
  lcd.print(steps);                                                            
                                // Daten am Monitor
  Serial.println();  
  Serial.print("<<<<<< Ende nach Umdrehungen >>>>>>  ");
  Serial.print(umZahl);
  Serial.println();
  Serial.println();
  Serial.print("Steps pro Umdrehung ");
  Serial.print(steps);
  Serial.println();
  Serial.print("Steptime ");
  Serial.print(stepTime);
  Serial.println();
  Serial.print("Gesamtlaufzeit in Microsec ");
  Serial.print(LZ_U);
  Serial.println();  
  Serial.print("Diff in Microsec ");
  Serial.print(-((60000000 * umZahl) - LZ_U));
  Serial.println();  
 
  delay(600);                   // Pause
                                // Schneller Rücklauf mit delays 
  digitalWrite(dirPin, HIGH);             
    for (int s = 0; s < steps * umZahl; s++){
    digitalWrite(stepPin, HIGH);
    delayMicroseconds(500);
    digitalWrite(stepPin, LOW);
    delayMicroseconds(500);
    }
  umCount = 0;                  // damit wird es endlos
  lastStepTime = micros();
  time_0 = micros();
  time_02 = micros();
  }
}
//Ende loop

…insgesamt eine spannende Sache
Gruß
Werner