ISR und Schrittmotor-Lib

Servus zusammen,

ich bin zur Zeit an einem schulischen Projekt. Ich schicke über mein CANOe auf dem PC diverse CAN-Botschaften auf mein Arduino-CAN-Shield, mein Arduino liest die Botschaft aus (diese Besteht aus Geschwindigkeit, Schrittanzahl, Drehrichtung) und von da soll es auf einen Schrittmotor gehen der dann aus und ein fahrt.

Ich habe das jetzt so mit dem Arduino Mega programmiert das sich meine Schrittmotor befehle in einer ISR sich befinden, das ich auch während dem Aus und Einfahren des Motors weiterhin CAN-Botschaften empfangen kann. Nur leider funktioniert das ganze innerhalb der ISR, mit einem normalen DC Motor funktioniert das so wie gewollt.

Habt ihr Ideen wie ich das lösen kann? Weiteres Problem ist, das wenn ich das ganze in meinem loop mache, das ich dann keine Botschaften mehr über den Bus erhalte. Wie erwähnt funktioniert das ganze mit einem DC Motor recht gut, aber da werden halt keine extra Libs benötigt.

if (ID == 0xFF && buf[0] == 0xEE) {

digitalWrite(21, HIGH); //Interrupt "Drücken"
Serial.println("Druecken: ");
Serial.println();
}

void Druecken()
{

analogWrite(motorSpeedPin, Geschwindigkeit); //Drehzahl Motor
digitalWrite(controlPin1, HIGH); //Drehrichtung Motor
digitalWrite(controlPin2, LOW); //Drehrichtung Motor

}

Bei geeigneter Programmierung stören sich Interrupts gegenseitig kaum. Du brauchst also eine Stepper-Bibliothek, die auch mit Interrupts arbeitet, wie das alle guten Bibliotheken machen.

BTW die Code Tags sehen aus wie </> (ganz links).

Vielen Dank für deine Antwort.

Hatte vergessen zu Erwähnen das ich das Adafruit Motorshield v2.3 verwende.
Wo finde ich so eine Lib die auch in Interrupts funktioniert?

Was meinst du mit dem letzten Satz? :wink:
Das sind nur paar Kommentare verrutscht.

Welche Bibliothek hast Du denn schon probiert? Am professionellsten ist die AccelStepper Bibliothek.

Bei Code können eckige Klammern falsch dargestellt werden, wenn sie mit Quotes statt mit Code Tags geschützt sind.

DrDiettrich:
Du brauchst also eine Stepper-Bibliothek, die auch mit Interrupts arbeitet, wie das alle guten Bibliotheken machen.

DrDiettrich:
Am professionellsten ist die AccelStepper Bibliothek.

Die arbeitet aber auch nicht mit Interrupts, sondern vertraut darauf, dass ihre 'run' Methode im loop oft genug aufgerufen wird. Ich habe eine eigene Lib, die den Motor im Timerinterrupt ansteuert, d.h. der läuft z.B. auch noch während eines delay() weiter. Allerdings hat sie (noch) keine Anfahr- und Bremsrampe wie die AccelStepper.

Wenn Du eine Lib kennst, die den Stepper per Interrupt ansteuert, würde mich das auch sehr interessieren.

Was erwartest Du, wenn Du Stepper.step(1000); einmal in loop() aufrufst? Wie soll das ohne Interrupts weitergehen?

DrDiettrich:
Was erwartest Du, wenn Du Stepper.step(1000); einmal in loop() aufrufst? Wie soll das ohne Interrupts weitergehen?

Du bist gedanklich bei einer anderen Bibliothek, die Methode step gibt es bei AccelStepper nicht.

Stepper.run(); muß möglichst häufig aufgerufen werden, macht die Bewegung:

/// Poll the motor and step it if a step is due, implementing
/// accelerations and decelerations to achive the ratget position. You must call this as
/// fequently as possible, but at least once per minimum step interval,
/// preferably in your main loop.
/// \return true if the motor is at the target position.
boolean run();

Für neue Ziele gibt es dann beispielsweise sowas:

/// Set the target position. The run() function will try to move the motor
/// from the current position to the target position set by the most
/// recent call to this function.
/// \param[in] absolute The desired absolute position. Negative is
/// anticlockwise from the 0 position.
void moveTo(long absolute);

Sorry, da war ich wirklich wo anders :frowning:

Trotzdem bleibt die Frage: was stört Dich bei Stepper.run()? Auch wenn das ständig in loop() aufgerufen werden muß, dazu ist loop() ja schließlich da.

Du quotest immer noch, statt Code Tags </> zu benutzen.

DrDiettrich:
Trotzdem bleibt die Frage: was stört Dich bei Stepper.run()? Auch wenn das ständig in loop() aufgerufen werden muß, dazu ist loop() ja schließlich da.

Es war deine Aussage, dass eine Stepper Lib gebraucht wird, die mit Interrupts arbeitet ( und dass das alle guten Libs so machen ).

Die loop-Version kann problematisch werden, wenn ein komplexer Sketch mit entsprechenden loop-Laufzeiten und schnelle Schrittmotorbewegung mit evtl. noch Microstepping zusammenkommen. Die AccelStepper macht pro run()-Aufruf immer nur einen Schritt.

MicroBahner:
Ich habe eine eigene Lib, die den Motor im Timerinterrupt ansteuert, d.h. der läuft z.B. auch noch während eines delay() weiter.

Gibt es die irgendwo zum Ausprobieren?

Das ist Bestandteil meiner MobaTools. Einzeln gibt's das nicht, da sich dort verschiedene Klassen den Timer 1 teilen. Aber man muss natürlich nicht alle Klassen nutzen und instanziieren - man kann auch nur den Stepper nutzen. Dann liegt gegebenenfalls halt etwas Code brach :wink: . Einen Teil wird der Compiler wegoptimieren, aber überall klappt das nicht. Aber solange es in's Flash reinpasst...
Die Lib hat aber auch Grenzen, was die Motorgeschwindigkeit angeht. Derzeit ist das Timerraster auf 200µs festgelegt.

Ja, diese Aussage war falsch. Nach nochmaligem Wühlen in der Adafruit Dokumentation bin ich mir nicht sicher, was mit diesem Shield und Bibliothek überhaupt möglich ist. Eigentlich müßte ein Shield mit I2C Anschluß selbständig arbeiten können, die Beispiele sehen aber nicht danach aus.

MicroBahner:
Das ist Bestandteil meiner MobaTools.

Na die habe ich doch, gerade aktualisiert. Danke :slight_smile:

DrDiettrich:
Eigentlich müßte ein Shield mit I2C Anschluß ...

Ich fürchte, nur die Adafruit_Motor_Shield_V2_Library eventuell mit AccelStepper zusammen kann diese sehr spezielle Hardware ansteuern. Daher dürften alle gut gemeinten Ratschläge, andere Bibliotheken betreffend, in die Irre führen.

rosch92:
Wo finde ich so eine Lib die auch in Interrupts funktioniert?

Vermutlich nirgendwo.

Daten von CAN einlesen, auswerten und der Stepper-Bibliothek übergeben, dafür benötigst Du nach meiner Einschätzung keine ISR.

Anmerkung: Die CAN-Schnittstelle dürfte wie die serielle im Hintergrund mit Interrupts arbeiten.

Auszug der technischen Details des Shield, Quelle

This board/chip uses I2C 7-bit addresses between 0x60-0x80, selectable with jumpers.

Habe ich was verpasst, oder seit wann ist 0x80 7bit breit?

postmaster-ino:
... oder seit wann ist 0x80 7bit breit?

Frage doch mal Lady Ada, wenn Du die nicht kennst, hast Du tatsächlich was verpaßt :slight_smile:

PS.: Habe gerade eine Anmerkung geschrieben.

Danke euch allen für die Antworten.

Problem ist das wenn während der Bewegung des Motors eine erneute CAN-Message kommt, sich auf meinem Bus nichts mehr regt und der auch nichts mehr empfängt. Wenn das ganze in nem Interrupt wäre, könnte mein Bus auch während der Bewegung CAN Botschaften auswerten.
Oder gibts da einen Trick?

postmaster-ino:
Auszug der technischen Details des Shield, QuelleHabe ich was verpasst, oder seit wann ist 0x80 7bit breit?

This board/chip uses I2C 7-bit addresses between 0x60-0x80, selectable with jumpers.

"Between" heiß "zwischen"!

Tipp:
Wenn etwas dazwischen passt, passen soll, dann muss es schmaler sein, als das genannte, welches es aufnehmen soll.

Das kann man z.B. an jedem Spalt überprüfen.

Ich behaupte:
Du hast "between" gelesen, aber dein Hirn hat daraus "in range of" draus gemacht.

rosch92:
Danke euch allen für die Antworten.

Problem ist das wenn während der Bewegung des Motors eine erneute CAN-Message kommt, sich auf meinem Bus nichts mehr regt und der auch nichts mehr empfängt. Wenn das ganze in nem Interrupt wäre, könnte mein Bus auch während der Bewegung CAN Botschaften auswerten.
Oder gibts da einen Trick?

Trick?
Debuggen, den Fehler beheben.

In Nebenläufigkeiten denken.
Nicht blockierenden Code schreiben.

combie:
Ich behaupte:
Du hast "between" gelesen, aber dein Hirn hat daraus "in range of" draus gemacht.

Die 0x60 ist eine gültige Adresse, die 0x80 aber nicht. mein Gehirn ist leider nicht in der Lage, diesen Umstand aus dem Wörtchen "between" herauszuinterpretieren. Da wünschte ich mir eine eindeutigere Formulierung.

Auf Stacking Shields ist Lady Ada meinem von postmaster-ino übernommenem Vorschlag gefolgt:

"You can adjust the address of the shields to range from 0x60 to 0x7F for a total of 32 unique addresses."

Geht doch :smiley:

So lange ein Interrupt bearbeitet wird, sind andere Interrupts gesperrt. Es wäre also völlig falsch, lang laufenden Code in eine ISR zu legen.

Der Stepper-Treiber wartet die ganze Zeit nur darauf, wann der nächste Impuls ausgegeben werden soll. Dieses Warten sollte eigentlich blitzschnell abgehandelt werden, und der CAN Firmware ständig genügend Zeit übrig lassen. Einige Methoden können aber blockierend implementiert sein, es kommt also drauf an, welche Bibliothek und welche Methode(n) Du verwendest.

BTW: blockiert delayMicroseconds() Interrupts?