Counter und Schrittmotor

Du meinst die Spannung am Punkt zwischen Emitter und 50K Widerstand? Ich glaub das war um 0.5V, aber ich werde es morgen nochmal nachmessen und auch versuchen wie weit ich den Widerstand senken kann. Es muss einfach über 3V sein oder?

...

agmue:
artikel=2143 sieht so aus wie meine.

Prima, davon habe ich jetzt vor 30 Minuten gerade 2 bestellt :wink:

Draht:
Du meinst die Spannung am Punkt zwischen Emitter und 50K Widerstand? Ich glaub das war um 0.5V, aber ich werde es morgen nochmal nachmessen und auch versuchen wie weit ich den Widerstand senken kann. Es muss einfach über 3V sein oder?

Ich meine die Spannung, die am Eingangspin anliegt, wenn die Lichtschranke unterbrochen ist, also der Transitor hochohmig. Dann sollte am Eingang eine Spannung < 1,5V anliegen. Je kleiner desto besser.

Also hier?

IMG_5165.jpg

IMG_5165.jpg

Hat es einen besonderen Grund, dass der Transistor des Optokopplers unüblicherweise als Emitterfolger geschaltet ist?

Gruß Tommy

Tommy56:
Hat es einen besonderen Grund, dass der Transistor des Optokopplers unüblicherweise als Emitterfolger geschaltet ist?

Gruß Tommy

Ich brauch einfach ein logic LOW, bei LS-unterbruch.

Aha, das hätte man nicht im Code abfangen können? Jeder baut sich die Probleme selbst.

Gruß Tommy

Tommy56:
Aha, das hätte man nicht im Code abfangen können? Jeder baut sich die Probleme selbst.

Gruß Tommy

Doch, aber ich hatte erst andere Lichtschranken.

Bitte mache es einfach so:

IMG_5165.png

IMG_5165.png

Das ist definitv die bessere Variante 8) . Anpassungen im Code sind ja nun auch nicht so schwierig ...
In der Klasse bei den LS-Abfragen 'pressed' durch 'released' ersetzen ( und umgekehrt ). Und bei 'state' muss invertiert werden. Dürfte überschaubar sein. Wenn ich das richtig sehe, sind das 6 Stellen, die geändert werden müssen.

Ok, ich hab die 'ringClass' jetzt mal so abgeändert. Ich habe nur 5 Stellen gefund. habe ich was vergessen?

class Ring {
    enum Schritt : byte {REF_CHK_KELLE, REF_FREI_KELLE, REF_KELLE, REF_GEFUNDEN, REF_M, REF_SUCHEN, WARTEN, KELLE_RUNTER, M_ZEIT, KELLE_RAUF};
    enum  : byte { MIN, STD }; // 1. Instanz: Minuten, 2. Instanz Stunden
    static byte ringIx;
    static char *ringTxt[2] ;
  private:
    MoToStepper StepRing = { FULLROT };
    MoToStepper StepKelle = { FULLROT };

    byte _disPin;   // Output um Stepper abzuschalten
    byte _refLsRing;
    byte _refLsKelle;
    byte _stellTaster;
    int  _nullposKelle;
    int  _nullposRing;
    byte _ringNr;
    byte minute, hour;
    byte ringPosAlt = 12, ringPosNeu = 0;
    Ring::Schritt schritt = Schritt::REF_CHK_KELLE, altSchritt = Schritt::REF_M;

    void printSchritt( byte schritt ) {
      static const char *schrittTexte[] = {"REF_CHK_KELLE", "REF_FREI_KELLE", "REF_KELLE", "REF_GEFUNDEN", "REF_M", "REF_SUCHEN", "WARTEN", "KELLE_RUNTER", "M_ZEIT", "KELLE_RAUF" };
      debug(ringTxt[_ringNr]); debugln( schrittTexte[schritt] );
    }


  public:
    Ring () {
       _ringNr = ringIx++;       // interner Index: 0: MinutenRIng ( erste Instanz ), 1 Stundenring ( 2.Instanz )
    }
    void init( byte stepperRing, int rampRing, int speedRing, int nullposRing, byte stepperKelle, int rampKelle, int speedKelle, int nullposKelle, byte disPin, byte refLsRing, byte refLsKelle, byte stellTaster ) {
      StepRing.attach(stepperRing);
      StepRing.setRampLen(rampRing);
      StepRing.setSpeed(speedRing);
      StepKelle.attach(stepperKelle);
      StepKelle.setRampLen(rampKelle);
      StepKelle.setSpeed(speedKelle);
      _disPin = disPin;
      pinMode( _disPin, OUTPUT );
      _refLsRing = refLsRing;
      _refLsKelle = refLsKelle;
      _stellTaster = stellTaster;
      _nullposKelle = nullposKelle;
      _nullposRing = nullposRing;
    }


    // Rückgabe wert ist die aktuelle Position ( wenn im Zustand WARTEN )
    // oder -1 wenn in Bewegung
    int process(boolean _stellenAktiv) {
#ifdef DEBUG
      if ( schritt != altSchritt ) {
        // Debugging; Ausgabe wenn Statuswechsel
        printSchritt((byte) schritt);
        altSchritt = schritt;
      }
#endif

      // Erkennen der Referenzpunkte ( unabhängig von der FSM )
      // Kellen-Referenz
      if (Taster.released(_refLsKelle)) {   // Wenn Referenzpunkt erreicht, Bewegung anhalten und Nullpunkt setzen.
        StepKelle.setZero(_nullposKelle);  // Nullpunkt etwas hinter den referenzpunkt setzen, um ihn auch bei Schrittverlusten sicher zu erreichen
        StepKelle.write(0);
        debug(ringTxt[_ringNr]); debugln("RefKelle erreicht");
      }
      // Ring-Referenz
      if (Taster.released(_refLsRing)) {
        StepRing.setZero(_nullposRing);
        StepRing.write(0);
        debug(ringTxt[_ringNr]); debugln("Ref-Ring erreicht");
      }

      switch (schritt) {
        case Schritt:: REF_CHK_KELLE:
          // Prüfen ob Kelle in der Lichtschranke steht
          digitalWrite(_disPin, LOW);                 // Stepperspulen anschalten
          if ( Taster.state(_refLsKelle ) ) {
            // Kelle aus LS ausfahren
            debug(ringTxt[_ringNr]); debugln(F("LS freifahren"));
            StepKelle.write( -159 );
            schritt = Schritt::REF_FREI_KELLE;
          } else {
            // Kelle Refpunkt suchen
            schritt = Schritt::REF_KELLE;
          }
          break;

        case Schritt::REF_FREI_KELLE:
          // LS freifahren
          // etwas über LS Grenze hinausfahren
          if ( Taster.pressed(_refLsKelle) ) StepKelle.doSteps( -100 );
          if ( !StepKelle.moving() ) schritt = Schritt::REF_KELLE;
          break;

        case Schritt::REF_KELLE:
          StepKelle.write(370);
          schritt = Schritt::REF_GEFUNDEN;
          debug(ringTxt[_ringNr]); debugln(F("Referenzpunkt Kelle suchen"));  // Bewegung Kelle starten.
          break;

        case Schritt::REF_GEFUNDEN:
          if (Taster.state(_refLsKelle!)) {   // Wenn Referenzpunkt erreicht, Bewegung anhalten und Nullpunkt setzen.
            debug(ringTxt[_ringNr]); debugln(F("Referenzpunkt Kelle gefunden"));
            schritt = Schritt::REF_M;
          }
          break;

        case Schritt::REF_M:

          debug(ringTxt[_ringNr]); debugln(F("Referenzpunkt Ring suche"));
          StepRing.write(400);
           debugln(F("am suchen"));
          schritt = Schritt::REF_SUCHEN;
          break;

        case Schritt::REF_SUCHEN:

          if (Taster.state(_refLsRing!) ) {
            debug(ringTxt[_ringNr]); debugln(F("Referenzpunkt Ring gefunden"));
            schritt = Schritt::WARTEN;

          }
          break;
        case Schritt::WARTEN:

          // Das Abschalten der Stepper wurde bereits in KELLE_RAUF gemacht
          if ( _stellenAktiv ) {
            // im Einstellmodus wird das vorrücken über den Stelltaster ausgelöst
            ringPosNeu = ringPosAlt + Taster.clicked(_stellTaster); // Bei einfach Klick wird eins, bei Doppelklick 2 addiert
            if ( ringPosNeu > 11 ) ringPosNeu = 0;
          } else {
            // im Normalbetrieb die Uhr abfragen
            readDS3231time(minute, hour);
            if ( _ringNr == MIN ) {
              ringPosNeu = minute / 5;
            } else {
              ringPosNeu = hour > 11 ? hour - 12 : hour;     //posStunden = minute > 11 ? minute - 12 : minute; // nur zum Testen
            }
          }
          if (ringPosAlt != ringPosNeu) {
            // Ereignis: Zeitpunkt für den Bewegungsablauf ist gekommen
            // Aktion: Ablauf starten mit der Kellenbewegung
            debug(ringTxt[_ringNr]);; displayTime(0, minute, hour);

            debug(ringTxt[_ringNr]); debug(F("alt: ")); debug(ringPosAlt); debug('\t'); debug("pos: "); debug(ringPosNeu); debug('\n');
            ringPosAlt = ringPosNeu;
            digitalWrite(_disPin, LOW);                 // Stepperspulen anschalten
            StepKelle.write(0);                // Minutenkelle runter
            schritt = Schritt::KELLE_RUNTER;
          }
          break;

        case Schritt::KELLE_RUNTER:

          if (!StepKelle.moving()) {
            // Ereignis: die Minutenkelle ist unten
            // Aktion: Beweegung des Minutenrings starten
            if (ringPosNeu == 0) {
              StepRing.write(360);
          
              schritt = Schritt::M_ZEIT;
            }
            else {
              StepRing.write(30 * ringPosNeu);
              debug(ringTxt[_ringNr]); debug("Winkel: "); debugln(30 * ringPosNeu);

              schritt = Schritt::M_ZEIT;
            }
          }

          break;
        case Schritt::M_ZEIT:

          if (!StepRing.moving() )
          { // Ereignis: Bewegung des Rings beendet
            // Aktion: Kelle hochfahren

            StepKelle.write(-59);           // Minutenkelle hoch

            // if (ringPosNeu == 0) StepRing.setZero();

            schritt = Schritt::KELLE_RAUF;
          }
          break;

        case Schritt::KELLE_RAUF:
          if (!StepKelle.moving())
          { // Ereignis: die Minutenkelle ist oben
            // Aktion: Stepper abschalten
            digitalWrite(_disPin, HIGH);
            schritt = Schritt::WARTEN;
          }
          break;
      }

      if ( schritt == Schritt::WARTEN ) return ringPosAlt;
      else return -1;
    }


};

// Klassenglobale Variable
byte Ring::ringIx = 0;
char *Ring::ringTxt[2] = {"Min: ", "Std: "};

Ich denke, Du hast einen Taster.state vergessen. Und zum Invertieren, musst Du da das '!' vor das 'Taster' schreiben. Also z.B. nicht

         if (Taster.state(_refLsKelle!)) {   // Wenn Referenzpunkt erreicht, Bewegung anhalten und Nullpunkt setzen.

sondern

         if (!Taster.state(_refLsKelle)) {   // Wenn Referenzpunkt erreicht, Bewegung anhalten und Nullpunkt setzen.

Ach ja, das mit dem "!" müsste ich ja eigentlich wissen.
Ok, hab noch ein Taster.state gefunden. von denen hab ich 3 invertiert und 2 pressen in released und ein released in pressen umgewandelt = 6 :slight_smile:

class Ring {
    enum Schritt : byte {REF_CHK_KELLE, REF_FREI_KELLE, REF_KELLE, REF_GEFUNDEN, REF_M, REF_SUCHEN, WARTEN, KELLE_RUNTER, M_ZEIT, KELLE_RAUF};
    enum  : byte { MIN, STD }; // 1. Instanz: Minuten, 2. Instanz Stunden
    static byte ringIx;
    static char *ringTxt[2] ;
  private:
    MoToStepper StepRing = { FULLROT };
    MoToStepper StepKelle = { FULLROT };

    byte _disPin;   // Output um Stepper abzuschalten
    byte _refLsRing;
    byte _refLsKelle;
    byte _stellTaster;
    int  _nullposKelle;
    int  _nullposRing;
    byte _ringNr;
    byte minute, hour;
    byte ringPosAlt = 12, ringPosNeu = 0;
    Ring::Schritt schritt = Schritt::REF_CHK_KELLE, altSchritt = Schritt::REF_M;

    void printSchritt( byte schritt ) {
      static const char *schrittTexte[] = {"REF_CHK_KELLE", "REF_FREI_KELLE", "REF_KELLE", "REF_GEFUNDEN", "REF_M", "REF_SUCHEN", "WARTEN", "KELLE_RUNTER", "M_ZEIT", "KELLE_RAUF" };
      debug(ringTxt[_ringNr]); debugln( schrittTexte[schritt] );
    }


  public:
    Ring () {
       _ringNr = ringIx++;       // interner Index: 0: MinutenRIng ( erste Instanz ), 1 Stundenring ( 2.Instanz )
    }
    void init( byte stepperRing, int rampRing, int speedRing, int nullposRing, byte stepperKelle, int rampKelle, int speedKelle, int nullposKelle, byte disPin, byte refLsRing, byte refLsKelle, byte stellTaster ) {
      StepRing.attach(stepperRing);
      StepRing.setRampLen(rampRing);
      StepRing.setSpeed(speedRing);
      StepKelle.attach(stepperKelle);
      StepKelle.setRampLen(rampKelle);
      StepKelle.setSpeed(speedKelle);
      _disPin = disPin;
      pinMode( _disPin, OUTPUT );
      _refLsRing = refLsRing;
      _refLsKelle = refLsKelle;
      _stellTaster = stellTaster;
      _nullposKelle = nullposKelle;
      _nullposRing = nullposRing;
    }


    // Rückgabe wert ist die aktuelle Position ( wenn im Zustand WARTEN )
    // oder -1 wenn in Bewegung
    int process(boolean _stellenAktiv) {
#ifdef DEBUG
      if ( schritt != altSchritt ) {
        // Debugging; Ausgabe wenn Statuswechsel
        printSchritt((byte) schritt);
        altSchritt = schritt;
      }
#endif

      // Erkennen der Referenzpunkte ( unabhängig von der FSM )
      // Kellen-Referenz
      if (Taster.released(_refLsKelle)) {   // Wenn Referenzpunkt erreicht, Bewegung anhalten und Nullpunkt setzen.
        StepKelle.setZero(_nullposKelle);  // Nullpunkt etwas hinter den referenzpunkt setzen, um ihn auch bei Schrittverlusten sicher zu erreichen
        StepKelle.write(0);
        debug(ringTxt[_ringNr]); debugln("RefKelle erreicht");
      }
      // Ring-Referenz
      if (Taster.released(_refLsRing)) {
        StepRing.setZero(_nullposRing);
        StepRing.write(0);
        debug(ringTxt[_ringNr]); debugln("Ref-Ring erreicht");
      }

      switch (schritt) {
        case Schritt:: REF_CHK_KELLE:
          // Prüfen ob Kelle in der Lichtschranke steht
          digitalWrite(_disPin, LOW);                 // Stepperspulen anschalten
          if ( !Taster.state(_refLsKelle ) ) {
            // Kelle aus LS ausfahren
            debug(ringTxt[_ringNr]); debugln(F("LS freifahren"));
            StepKelle.write( -159 );
            schritt = Schritt::REF_FREI_KELLE;
          } else {
            // Kelle Refpunkt suchen
            schritt = Schritt::REF_KELLE;
          }
          break;

        case Schritt::REF_FREI_KELLE:
          // LS freifahren
          // etwas über LS Grenze hinausfahren
          if ( Taster.pressed(_refLsKelle) ) StepKelle.doSteps( -100 );
          if ( !StepKelle.moving() ) schritt = Schritt::REF_KELLE;
          break;

        case Schritt::REF_KELLE:
          StepKelle.write(370);
          schritt = Schritt::REF_GEFUNDEN;
          debug(ringTxt[_ringNr]); debugln(F("Referenzpunkt Kelle suchen"));  // Bewegung Kelle starten.
          break;

        case Schritt::REF_GEFUNDEN:
          if (!Taster.state(_refLsKelle)) {   // Wenn Referenzpunkt erreicht, Bewegung anhalten und Nullpunkt setzen.
            debug(ringTxt[_ringNr]); debugln(F("Referenzpunkt Kelle gefunden"));
            schritt = Schritt::REF_M;
          }
          break;

        case Schritt::REF_M:

          debug(ringTxt[_ringNr]); debugln(F("Referenzpunkt Ring suche"));
          StepRing.write(400);
           debugln(F("am suchen"));
          schritt = Schritt::REF_SUCHEN;
          break;

        case Schritt::REF_SUCHEN:

          if (!Taster.state(_refLsRing) ) {
            debug(ringTxt[_ringNr]); debugln(F("Referenzpunkt Ring gefunden"));
            schritt = Schritt::WARTEN;

          }
          break;
        case Schritt::WARTEN:

          // Das Abschalten der Stepper wurde bereits in KELLE_RAUF gemacht
          if ( _stellenAktiv ) {
            // im Einstellmodus wird das vorrücken über den Stelltaster ausgelöst
            ringPosNeu = ringPosAlt + Taster.clicked(_stellTaster); // Bei einfach Klick wird eins, bei Doppelklick 2 addiert
            if ( ringPosNeu > 11 ) ringPosNeu = 0;
          } else {
            // im Normalbetrieb die Uhr abfragen
            readDS3231time(minute, hour);
            if ( _ringNr == MIN ) {
              ringPosNeu = minute / 5;
            } else {
              ringPosNeu = hour > 11 ? hour - 12 : hour;     //posStunden = minute > 11 ? minute - 12 : minute; // nur zum Testen
            }
          }
          if (ringPosAlt != ringPosNeu) {
            // Ereignis: Zeitpunkt für den Bewegungsablauf ist gekommen
            // Aktion: Ablauf starten mit der Kellenbewegung
            debug(ringTxt[_ringNr]);; displayTime(0, minute, hour);

            debug(ringTxt[_ringNr]); debug(F("alt: ")); debug(ringPosAlt); debug('\t'); debug("pos: "); debug(ringPosNeu); debug('\n');
            ringPosAlt = ringPosNeu;
            digitalWrite(_disPin, LOW);                 // Stepperspulen anschalten
            StepKelle.write(0);                // Minutenkelle runter
            schritt = Schritt::KELLE_RUNTER;
          }
          break;

        case Schritt::KELLE_RUNTER:

          if (!StepKelle.moving()) {
            // Ereignis: die Minutenkelle ist unten
            // Aktion: Beweegung des Minutenrings starten
            if (ringPosNeu == 0) {
              StepRing.write(360);
          
              schritt = Schritt::M_ZEIT;
            }
            else {
              StepRing.write(30 * ringPosNeu);
              debug(ringTxt[_ringNr]); debug("Winkel: "); debugln(30 * ringPosNeu);

              schritt = Schritt::M_ZEIT;
            }
          }

          break;
        case Schritt::M_ZEIT:

          if (!StepRing.moving() )
          { // Ereignis: Bewegung des Rings beendet
            // Aktion: Kelle hochfahren

            StepKelle.write(-59);           // Minutenkelle hoch

            // if (ringPosNeu == 0) StepRing.setZero();

            schritt = Schritt::KELLE_RAUF;
          }
          break;

        case Schritt::KELLE_RAUF:
          if (!StepKelle.moving())
          { // Ereignis: die Minutenkelle ist oben
            // Aktion: Stepper abschalten
            digitalWrite(_disPin, HIGH);
            schritt = Schritt::WARTEN;
          }
          break;
      }

      if ( schritt == Schritt::WARTEN ) return ringPosAlt;
      else return -1;
    }


};

// Klassenglobale Variable
byte Ring::ringIx = 0;
char *Ring::ringTxt[2] = {"Min: ", "Std: "};

So ich melde mich zurück vom Tatort. Mittlerweile ist nun alles wieder zusammen gestöpselt mit einem Steckplatz für den Nano für den Fall der Fälle.
Hatte 2 Neue Nanos bestellt, bei einem ist mir der USB- Stecker abgebrochen, praktisch von alleine (ohne meine Schuld :wink: und der 2. ist durch meine Schuld hinüber, nochmal neue Nanos bestellt und jetzt bin ich wieder am Testen der Anlage. Sie läuft noch nicht so wie sie sollte.

  1. mal werden die Stepper nicht vom Strom genommen nach den jeweiligen Bewegungen. Dies sollte doch durch LOW und HIGH der PIn 9 und 8 am Nano geschehen oder?

  2. Wahrscheinlich muss ich mir nochmal Gedanken machen über die Stromversorgung der ganzen Anlage.
    Im Moment betreibe ich das Ganze mit einem 12v Trafo (2250mA) siehe Abb. Da die Ring-Stepper 12V brauchen.
    Über einen DC/DC Wandler erhalte ich dann 5V diese betreiben Die 2 anderen Steppermotoren, die Lichtschranken und die 2 Schieberegister.
    Dem Nano (5V) Ausgang mute ich nur den Betrieb des DS3231 zu.

Der Nano selbst wird im Moment noch vom Laptop gespiesen. Was haltet ihr davon? Irgendwie läuft eben noch nicht alles so wie es sollte. Die Motoren ruckeln zum Teil, haben Schrittverluste, LS geben ungewollte Signale uä.

Dies ist mein DC/ Wandler: https://www.conrad.ch/de/p/wuerth-elektronik-173010578-dc-dc-wandler-smd-5-v-dc-1-a-anzahl-ausgaenge-1-x-1486753.html. und dies mein Trafo:

Ich habe den Übeltäter für die fehlende Motorenabstellung gefunden. Es war ein Schieberegister, welchen offensichtlich hinüber war. Hätte nicht gedacht, dass die so sensibel sind.

Draht:
Hätte nicht gedacht, dass die so sensibel sind.

Die Erfahrung habe ich eigentlich bisher nicht gemacht. Mir ist noch keiner kaputtgegangen :wink: .

Draht:
Der Nano selbst wird im Moment noch vom Laptop gespiesen. Was haltet ihr davon? Irgendwie läuft eben noch nicht alles so wie es sollte. Die Motoren ruckeln zum Teil, haben Schrittverluste, LS geben ungewollte Signale uä.

War das im Testaufbau auch so? Laufen die Schrittmotore mit dem ausgetauschten Schieberegister besser?
Und den Nano über einen Laptop zu versorgen ist wohl auch eher nicht die Endlösung oder?

MicroBahner:
War das im Testaufbau auch so? Laufen die Schrittmotore mit dem ausgetauschten Schieberegister besser?

Nein, das war beim Testaufbau nicht so! Und nein, sie laufen nicht besser, aber das Ausschalten der Motoren geht nun wieder.

MicroBahner:
Und den Nano über einen Laptop zu versorgen ist wohl auch eher nicht die Endlösung oder?

Nein das mit dem Laptop ist nur solange ich noch den Monitor brauche.

Jetzt, bin ich wiedermal am Fehler suchen :confused: