Counter und Schrittmotor

step1.detach()

Hab ich noch ausgewechselt mit digitalWrite(LOW);

Ich dache eigentlich, dass es dir darum geht, dass der Sketch während der Bewegung der Motore nicht blockiert. Jetzt blockierst Du ihn selbst mit delay(). Das macht doch keinen Sinn.

Vielleicht erklärst Du mal genauer, was das ganze überhaupt werden soll.

Also das Projekt ist eine Farb-Uhr. (Farbkellen welche sich im Kreis drehen - alle 5 Minuten um 30 Grad (Stepper1) und dann nach oben geklappt werden mit (Stepper2) von einer externen Quarz-Uhr wird der Counter getaktet.
Wichtig war mir, dass der Counter nicht gestopt wird, solange die Schrittmotoren arbeiten. Das war eben so mit Stepper.h.
Die Delays hab ich nur eingebaut, damit der Schrittmotor zeit hat die Bewegung auszuführen. Vielleicht gibt es da auch eine bessere Möglichkeit, wichtig ist nur, dass der Counter dabei nicht unterbrochen wird.

Ich hab noch ein Bild angefügt auf dem ist (im Bild unten) die Apparatur zu sehen - zum besseren Verständnis.

Draht:
Also das Projekt ist eine Farb-Uhr. (Farbkellen welche sich im Kreis drehen - alle 5 Minuten um 30 Grad
Wichtig war mir, dass der Counter nicht gestopt wird, solange die Schrittmotoren arbeiten. Das war eben so mit Stepper.h.

Mit deinen delays ist das doch wieder genau so.

In welchem Takt kommen denn später die Pulse?
Du wirst eine kleinen ‘endlichen Automaten’ bzw. eine Schrittkette brauchen, der die Bewegung der beiden Stepper kontrolliert ohne den Sketchablauf zu unterbrechen.
Der hat dann z.B. die Zustände:
‘Warten’ - da passiert nichts, bis die 5 Minuten rum sind,
→ wenn 5 Minuten um, Stepper 1 starten und Zustand = Drehen
‘Drehen’
→ wenn Stepper 1 nicht mehr dreht Stepper 2 starten und Zustand = ‘Hochklappen’
‘Hochklappen’
→ wenn Stepper 2 nicht mehr dreht Stepper 2 zurück starten und Zustand = ‘Runterklappen’
‘Runterklappen’
→ wenn Stepper 2 nicht mehr dreht dann Zustand = ‘Warten’

Während der jeweiligen Zustände wird nur die Bedingung abgefragt, und wenn sie nicht erfüllt ist geht’s einfach weiter. Damit blockiert der loop nicht, und Du kannst ständig deinen Pulseingang abfragen.

Die Pulse werden dann im Sekunden Takt kommen. Also nach 300 Sekunden soll das ganze jeweils anlaufen.
Du hast recht. Da war ich gestern Nacht zu müde und hab das nicht mehr bemerkt, nach dem ich die Delays 'eingebaut habe'
Ich muss dein Vorschlag erst noch studieren.

Ich brauche die Delays eigentlich gar nicht, denn der Ablauf ist so: (so meinst du es auch oder MicroBahner ?)

  1. warten bis 5 Min. verstrichen sind.
  2. Stepper1 klappt die Kelle runter.
  3. Stepper2 dreht das Rad um 30 Grad
    4.Stepper1 klappt die neue Kelle wieder hoch.
  4. Wieder warten 5 Minuten. (Minus die Zeit welche ab Punkt 2 verstrichen ist)
    Ich kann den Sketch im Moment nicht korrigieren, da ich nicht am Computer bin, aber wenn ich keine Fehlüberlegung mache sollte es so gehen.

Habs nun doch versucht vom iphone aus.

/******************************************************************
   Demo zum Anschluß eines unipolaren Stepmotors 28BYJ-48 ( über SPI )
  und eines Standard bipolaren Steppers über 4 Pins und eine H-Brücke.
  Dieses Beispiel läuft nicht auf ESP8266!

  Der Schrittmotor kann wahlweise direkt über 4 frei wählbare Pins, oder über die SPI-
  Schnittstelle und Schieberegister angeschlossen werden.
  SPI belegt beim UNO oder nano die Pins 10(SS),11(MOSI) und 13(SCK)
  Pin 12 (MISO) wird zwar nicht genutzt, aber von der HW belegt
*/
/*******************************************************************
  Demo for connecting a unipolar stepper motor 28BYJ-48 ( via SPI ) and a standard bipolar stepper
  via 4 pins and a H-bridge.  This example does not run on ESP8266!

  The stepper motor can be connected either directly via 4 freely selectable pins, or via the SPI
  interface and shift register (see circuit diagram in documentation).
  SPI occupies the pins 10(SS), 11(MOSI) and 13(SCK) of the UNO or nano.
  Pin 12 (MISO) is not used, but is occupied by the hardware
  In this example Step1 is connected directly while Step2 is connected via SPI.

  Translated with www.DeepL.com/Translator (free version)
*/
#include <MobaTools.h>


int button1 = 4; //button pin, connect to ground to move servo

int switchPin = 4;              // switch is connected to pin 4
int val;                        // variable for reading the pin status
int buttonState;                // variable to hold the button state
int buttonPresses = 0;          // how many times the button has been pressed

int stepCount = 0;

const int FULLROT1 = 4096;
MoToStepper Step1(FULLROT1); 
MoToStepper Step2(FULLROT1);   // HALFSTEP ist default



void setup() {

  pinMode(button1, INPUT_PULLUP);

   
  Step1.attach( 5, 6, 7, 8 );
  Step1.setSpeed(50);

  Step2.attach( 9, 10, 11, 12 );
  Step2.setSpeed(50);

  pinMode(button1, INPUT_PULLUP);
  pinMode(switchPin, INPUT);    // Set the switch pin as input
  Serial.begin(9600);           // Set up serial communication at 9600bps
  buttonState = digitalRead(switchPin);   // read the initial state

  digitalWrite(4, HIGH); //enable pullups to make pin high
  pinMode(LED_BUILTIN, OUTPUT);


}

void loop() {

  val = digitalRead(switchPin);      // read input value and store it in val
  if (val != buttonState) {          // the button state has changed!
    if (val == LOW) {                // check if the button is pressed
      buttonPresses++;               // increment the buttonPresses variable
      Serial.print("Button has been pressed ");
      Serial.print(buttonPresses);
      Serial.println(" times");
      delay(500);

      if (buttonPresses >= 60)
      {

        Step1.doSteps(800);   // Kelle runter
        Step2.doSteps(512);   // Rad dreht 30*
        Step1.doSteps(-800);  // Kelle hoch
        
        buttonPresses = 0;
      
          }
        
      }
    }

  buttonState = val;

Schicke Deinen Sketch doch wenigstens vor der Veröffentlichung durch den Compiler.
Der compiliert garantiert nicht.

Gruß Tommy

Draht:
Ich brauche die Delays eigentlich gar nicht, denn der Ablauf ist so: (so meinst du es auch oder MicroBahner ?)

  1. warten bis 5 Min. verstrichen sind.
  2. Stepper1 klappt die Kelle runter.
  3. Stepper2 dreht das Rad um 30 Grad
    4.Stepper1 klappt die neue Kelle wieder hoch.
  4. Wieder warten 5 Minuten. (Minus die Zeit welche ab Punkt 2 verstrichen ist)

Im Prinzip meine ich das schon auch so ( ok, die Zuordnung und Reihenfolge Klappen/Drehen hatte ich nicht richtig verstanden ), aber dein Sketch wird nicht funktionieren, weil Du die Bewegungen der Stepper nicht abwartest.
Dein 'Problem' bei der Umsetzung ist, dass die Punkt 2,3 und 4 ja auch Zeit brauchen, Du aber an der Stelle nicht einfach warten kannst, weil dir sonst die Impulse verloren gehen. Das erfordert dann eben eine entsprechende Umsetzung im Programm in Form der Schrittkette. Der Gedanke dahinter ist, während der einzelnen Zustände der Schrittkette ( Deine Punkte 1..4 ) immer nur exakt die Abfragen und Aktionen auszuführen, die für den aktuellen Schritt relevant sind. Alles andere wird während dieser Zeit übersprungen.
Dafür eignet sich sehr gut die switch-Anweisung
Als Pseudocode:

 switch ( schritt ) {
    case 1: //warten bis 5 Min. verstrichen sind.
      if ( >= 300 Pulse empfangen ) {
        pulszähler auf 0
        Stepper1 starten
        schritt = 2
      }
      break;
    case 2: //Stepper1 klappt die Kelle runter.
      if ( not Stepper1.moving() ) {
        // Kelle ist unten
        Stepper2 starten
        schritt = 3
      }
      break;
    case 3: // Stepper2 dreht das Rad um 30 Grad
      if ( not Stepper2.moving() ) {
        // Drehung abgeschlossen
        Stepper1 starten
        schritt = 4
      }
      break;
    case 4: // Stepper1 klappt die neue Kelle wieder hoch.
      if ( not Stepper1.moving() ) {
        // Kelle ist oben
        schritt = 1
      }
      break;
  }

Dabei wird der loop nie angehalten und trotzdem wird die jeweilige Stepperbewegung abgewartet bis der nächste Punkt dran ist. Dadurch können auch deine Sekundenpulse problemlos weitegerzählt werden. Du musst dann auch keine Zeit abziehen, da die Zählung beim Erreichen von 300 gleich wieder neu startet ( während der ganzen Stepperbewegungen )

Mach ich, sobald ich wieder zhause bin.

Vielen Dank MicroBahner. Einmal mehr hast du natürlich recht! Ich muss dem Stepper Ja trotzdem Zeit geben für die Bewegung!
Ich werde deinen Sketch studieren und testen, sobald ich wieder zuhause bin.

Nada

???

Gruß Tommy

MicroBahner:
Als Pseudocode:

Wir müssen mal einen Pseudocode nach C++ - Converter schreiben :slight_smile:

Draht:
Also das Projekt ist eine Farb-Uhr. (Farbkellen welche sich im Kreis drehen - alle 5 Minuten um 30 Grad (Stepper1) und dann nach oben geklappt werden mit (Stepper2) von einer externen Quarz-Uhr wird der Counter getaktet.

Ich hab noch ein Bild angefügt auf dem ist (im Bild unten) die Apparatur zu sehen - zum besseren Verständnis.

Ja, danke für die nützliche Anschauung, wobei Stepper2 fehlt, oder?

wno158:
Wir müssen mal einen Pseudocode nach C++ - Converter schreiben :slight_smile:

Kein Problem, Takt durch millis ersetzt:

#include <MobaTools.h>
const uint16_t FULLROT = 4096;
MoToStepper StepMinuten(FULLROT);
MoToStepper StepMinKelle(FULLROT);
uint32_t jetzt, vorhin;
enum {WARTEN, KELLE_RUNTER, ZEIT, KELLE_RAUF};
byte schritt = WARTEN;
byte posMinuten = 0;

void setup() {
  Serial.begin(115200);
  Serial.println("\nStart");
  StepMinuten.attach( 5, 6, 7, 8 );
  StepMinuten.setSpeed(50);

  StepMinKelle.attach( 9, 10, 11, 12 );
  StepMinKelle.setSpeed(50);
}

void loop() {
  jetzt = millis();
  switch(schritt) {
  case WARTEN:
    if (jetzt - vorhin >= 10000) {
      vorhin = jetzt;
      Serial.print(jetzt); Serial.print('\t'); 
      schritt = KELLE_RUNTER;
    }
    break;
  case KELLE_RUNTER:
      StepMinKelle.doSteps(512);
      schritt = ZEIT;
    break;
  case ZEIT:
    if (!StepMinKelle.moving()) {
      if (posMinuten < 11) {
        if (posMinuten == 0) StepMinuten.setZero();
        posMinuten++;
        StepMinuten.write(30 * posMinuten);
        Serial.println(30 * posMinuten);
      } else {
        posMinuten = 0;
        StepMinuten.write(360);
        Serial.println(360);
      }
      schritt = KELLE_RAUF;
    }
    break;
  case KELLE_RAUF:
    if (!StepMinuten.moving()) {
      StepMinKelle.doSteps(-512);
      schritt = WARTEN;
    }
    break;
  }
}

@MicroBahner: Die 4096 Schritte können nicht ganzzahlig auf 30 Grad aufgeteilt werden, ist meine Vorgehensweise mit write(winkel) dann zulässig? Oder wären absolute Schritte (4096UL * posMinuten / 12) besser?

wno158:
Wir müssen mal einen Pseudocode nach C++ - Converter schreiben :slight_smile:

Ich dachte, dass das eine schöne Übung für Draht wäre :wink:

agmue:
Kein Problem, Takt durch millis ersetzt:

Ist hier wohl nicht der richtige Ansatz, da die Zeit über einen externen Sekundentakt vorgegeben wird.

Wenn etwas mit millis() in absolut regelmässigen Abständen ablaufen soll ist dies

    if (jetzt - vorhin >= 10000) {
      vorhin = jetzt;

auch nicht optimal, da Fehler durch die Laufzeit von loop() sich akkumulieren. Dann sollte man

   if (jetzt - vorhin >= 10000) {
      vorhin += 10000;

schreiben. Auch dafür gäbe es eine passende Klasse in den MobaTools: die MoToTimebase.
Aber, wie gesagt, hier eh nicht relevant.

agmue:
Die 4096 Schritte können nicht ganzzahlig auf 30 Grad aufgeteilt werden, ist meine Vorgehensweise mit write(winkel) dann zulässig? Oder wären absolute Schritte (4096UL * posMinuten / 12) besser?

Stimmt. ist mir noch garnicht aufgefallen. Auf jeden Fall sollte man dann innerhalb einer Umdrehung mit absoluten Positionen arbeiten, und jeweils nach einer Umdrehung neu Nullen (Referenzpunkt setzen). Durch die Absolutpositionen mittelt sich das aus. Da kann man dann auch mit den Winkeln arbeiten ( 'write' arbeitet eh immer mit Absolutwinkeln, gerechnet ab Nullpunkt ).

MicroBahner:
Auf jeden Fall sollte man dann innerhalb einer Umdrehung mit absoluten Positionen arbeiten, und jeweils nach einer Umdrehung neu Nullen …

Dann habe ich es wohl richtig :slight_smile:

Danke für die Antwort!

MicroBahner:
Aber, wie gesagt, hier eh nicht relevant.

Richtig, ich würde anstelle des Taktes sowieso lieber ein Uhrenmodul wie DS3231 nutzen.

MicroBahner:
Ist hier wohl nicht der richtige Ansatz, da die Zeit über einen externen Sekundentakt vorgegeben wird.

Na gut, dann eben mit Takt (korrigierte Fassung mit Takterkennung außerhalb der Schrittkette):

#include <MobaTools.h>
const uint16_t FULLROT = 4096;
MoToStepper StepMinuten(FULLROT);
MoToStepper StepMinKelle(FULLROT);
MoToStepper StepStunden(FULLROT);
const byte taktPin = 4;
bool aktTakt, altTakt;
const uint16_t MAXTAKTE = 10;  // zum Testen; später 60 * 5 = 300 Takte für 5 Minuten
uint16_t takte = 65535;        // keine automatische Bewegung
enum {WARTEN, KELLE_RUNTER, ZEIT, KELLE_RAUF};
byte schritt = WARTEN;
byte posMinuten = 0, posStunden = 0;

void setup() {
  Serial.begin(115200);
  Serial.println("\nStart");
  pinMode(taktPin, INPUT_PULLUP);
  pinMode( 13, OUTPUT );
  aktTakt = digitalRead(taktPin);
  altTakt = aktTakt;
  StepMinuten.attach( 5, 6, 7, 8 );
  StepMinuten.setSpeed(50);

  StepMinKelle.attach( 9, 10, 11, 12 );
  StepMinKelle.setSpeed(50);

  StepStunden.attach( A0, A1, A2, A3 );
  StepStunden.setSpeed(50);
}

void loop() {
  aktTakt = digitalRead(taktPin);
  digitalWrite(13, aktTakt);
  if (altTakt != aktTakt) {
    altTakt = aktTakt;
    if (!aktTakt) {
      takte++;
      if (takte >= MAXTAKTE) {
        takte = 0;
      }
      Serial.print("Takte: "); Serial.println(takte);
    }
  }
  switch (schritt) {
    case WARTEN:
      if (takte == 0) {
        schritt = KELLE_RUNTER;
      }
      break;
    case KELLE_RUNTER:
      StepMinKelle.doSteps(512);
      schritt = ZEIT;
      break;
    case ZEIT:
      if (!StepMinKelle.moving()) {
        if (posMinuten < 11) {
          if (posMinuten == 0) StepMinuten.setZero();
          posMinuten++;
          StepMinuten.write(30 * posMinuten);
          Serial.print("Minuten-Winkel: "); Serial.print(30 * posMinuten); Serial.print('\t');
        } else {
          posMinuten = 0;
          StepMinuten.write(360);
          Serial.print("Minuten-Winkel: "); Serial.print(360); Serial.print('\t');
          if (posStunden < 11) {
            if (posStunden == 0) StepStunden.setZero();
            posStunden++;
            StepStunden.write(30 * posStunden);
            Serial.print("Stunden-Winkel: "); Serial.print(30 * posStunden);
          } else {
            posStunden = 0;
            StepStunden.write(360);
            Serial.print("Stunden-Winkel: "); Serial.print(360);
          }
        }
        Serial.print('\n');
        schritt = KELLE_RAUF;
      }
      break;
    case KELLE_RAUF:
      if (!StepMinuten.moving()) {
        StepMinKelle.doSteps(-512);
        schritt = WARTEN;
      }
      break;
  }
}

EDIT: Neuer Anfangswert für takte.

MoToStepper StepStunden(FULLROT);

Gibt's da einen Stunden-Stepper? Davon habe ich bisher gar nichts gelesen. Und wenn, bräuchte man da doch auch einen Stepper für die Kelle, oder ist das da anders? Bei so vielen Steppern würde sich dann auch die Ansteuerung über SPI und Schieberegister anbieten.
Und wie ist eingentlich die Grundstellung geplant? Irgendwie müssen die beim Starten doch in die richtige Startstellung gebracht werden, die können ja irgendwo stehen.
Draht muss da wohl noch ein paar drahtige Fragen beantworten ;).

Was aber auf jeden Fall gilt: Die Auswertung der Taktflanken und das Zählen der Pulse muss außerhalb der Schrittkette gemacht werden. Sonst gehen während der Stepperbewegungen Pulse verloren.

MicroBahner:

MoToStepper StepStunden(FULLROT);

Gibt's da einen Stunden-Stepper?

Auf dem Foto habe ich zwei Räder mit zwölf Scheiben gesehen, könnte also für Stunden und fünf-Minuten sein.

MicroBahner:
Was aber auf jeden Fall gilt: Die Auswertung der Taktflanken und das Zählen der Pulse muss außerhalb der Schrittkette gemacht werden. Sonst gehen während der Stepperbewegungen Pulse verloren.

Autsch, mit den Kellen zusammen braucht der Durchlauf tatsächlich länger als eine Sekunde, da ist unbedingt Nacharbeit notwendig :-[

Meld mich morgen. Mit dem iphone ist das alles etwas mühsam. Quoten funktioniert nicht usw.