Forum: Mikrocontroller und Digitale Elektronik AVR: zwei Schrittmotoren mit einem Timer


von Michael R. (Firma: Brainit GmbH) (fisa)


Lesenswert?

Hallo zusammen,

ich möchte an einbem ATmega328 zwei Schrittmotoren per Step/Direction 
ansteuern. Die beiden Stepper laufen vollkommen unabhängig 
(unterschiedliche Richtungen, unterschiedliche Drehzahlen, sie müssen 
auch nicht synchron laufen). Da ich einen recht breiten Drehzahlbereich 
abdecken will, scheiden die 8Bit-Timer eher aus (es sei denn ich fange 
an dynamisch am Prescaler herumzudrehen, aber das halte ich für keine 
gute Idee)

Nehm ich halt einfach zwei 16bit-Timer (Haha, wenn es denn zwei gäbe)

Deshalb hab ich mal versucht etwas zu brainstormen.

Mein Plan ist folgender: Ich lass den 16bit-Timer1 stur von 0x0000 bis 
0xffff durchlaufen. Die eigentlichen Step-Signale steuere ich mit den 
beiden Output-Compare-Werten, auf den dazugehörigen Interrupts hängt 
jeweils eine ISR. In der ISR erhöhe ich den OCR-Wert um den 
ensprechenden Timer-Wert der Geschwindigkeit.  So habe ich in einem 
Timer zwei (einigermaßen) unabhängige Frequenzen. Gleichzeitig schalte 
ich den jweiligen Step-Pin auf high.

Der eigentliche Step-Impuls darf recht kurz sein (wenn ich das 
Datenblatt richtig in Erinnerung habe, >1usec). Da könnte ich fast 
busy-mäßig in der ISR drauf warten, aber das wäre ja schade um die 16 
Takte :-)

Deshalb nehme ich dafür einen freien 8bit-Timer, der auch wieder stur 
von 0..255 durchläuft, und gar keine ISR hat. Dafür zwei hardwaremäßige 
Output-Compare, die stur das jeweilige bit-Signal auf Low schalten (Der 
Timer setzt den pin nie high, cleart ihn nur. Lt. Datenblatt sollte das 
gehen)

In der ISR des Timer1 muss ich jetzt etwas vorsichtig vorgehen: zuerst 
OCR2-Register auf TCNT2+2usec setzen, danach erst den Step-Pin auf high 
(sonst könnte ein ungünstiger Interrupt den Pin gleich wieder auf low 
ziehen)

Danach hab ich recht viel Zeit, die neue Schrittweite zu berechnen und 
den neuen OCR1-Wert zu laden.

ist der Plan einigermaßen gut?

von spess53 (Gast)


Lesenswert?

Hi

>Nehm ich halt einfach zwei 16bit-Timer (Haha, wenn es denn zwei gäbe)

In DIL: ATMega1284P.

MfG Spess

von Michael R. (Firma: Brainit GmbH) (fisa)


Lesenswert?

spess53 schrieb:
> In DIL: ATMega1284P.
Vielleicht hab ich ein altes Datenblatt, aber: dort steht:
1
– Two 8-bit Timer/Counters with Separate Prescalers and Compare Modes
2
– One 16-bit Timer/Counter with Separate Prescaler, Compare Mode, and Capture Mode

ist aber unwichtig: Der passt nicht in mein Ökosystem :-) Controller mit 
ATmega328 ist nämlich schon vorhanden...

: Bearbeitet durch User
von Kein Name (Gast)


Lesenswert?

GRBL hat da eine einfache Methode. Die rufen die ISR sehr oft auf, und 
überprüben in der ISR, ob es mal wieder Zeit für einen Schritt wird.

http://dank.bengler.no/-/page/show/5470_grbl

von Grünberg (Gast)


Lesenswert?

Michael Reinelt schrieb:
> Deshalb nehme ich dafür einen freien 8bit-Timer, der auch wieder stur
> von 0..255 durchläuft, und gar keine ISR hat. Dafür zwei hardwaremäßige
> Output-Compare, die stur das jeweilige bit-Signal auf Low schalten

Wenn der Comparematch seinen Pin (OC0A) nach low schalten kann, kann die 
Timer1 ISR den nicht nach high schalten. Über das PORT Register geht das 
dann nicht. Oder wie hast du dir das gedacht?

> (Der
> Timer setzt den pin nie high, cleart ihn nur. Lt. Datenblatt sollte das
> gehen)

Welcher Modus soll das sein?


> In der ISR des Timer1 muss ich jetzt etwas vorsichtig vorgehen: zuerst
> OCR2-Register auf TCNT2+2usec setzen, danach erst den Step-Pin auf high
> (sonst könnte ein ungünstiger Interrupt den Pin gleich wieder auf low
> ziehen)
>
> Danach hab ich recht viel Zeit, die neue Schrittweite zu berechnen und
> den neuen OCR1-Wert zu laden.
>
> ist der Plan einigermaßen gut?

Nochmal überdenken.

von Falk B. (falk)


Lesenswert?

@ Michael Reinelt (fisa)

>ich möchte an einbem ATmega328 zwei Schrittmotoren per Step/Direction
>ansteuern. Die beiden Stepper laufen vollkommen unabhängig
>(unterschiedliche Richtungen, unterschiedliche Drehzahlen, sie müssen
>auch nicht synchron laufen).

Und wozu braucht man da ZWEI Timer? Das kann EINER spielend, das 
richtige Konzept vorausgesetzt.

>>0xffff durchlaufen. Die eigentlichen Step-Signale steuere ich mit den
>beiden Output-Compare-Werten, auf den dazugehörigen Interrupts hängt
>jeweils eine ISR. In der ISR erhöhe ich den OCR-Wert um den
>ensprechenden Timer-Wert der Geschwindigkeit.  So habe ich in einem
>Timer zwei (einigermaßen) unabhängige Frequenzen. Gleichzeitig schalte
>ich den jweiligen Step-Pin auf high.

Naja, über welche Frequenzen reden wir denn? Ein 0815 Schrittmotor kommt 
doch eher nicht über 10 kHz. Die kann man auch ohne Output Compare 
direkt per CPU und Timerinterrupt erzeugen.

von Michael R. (Firma: Brainit GmbH) (fisa)


Lesenswert?

Grünberg schrieb:
> Wenn der Comparematch seinen Pin (OC0A) nach low schalten kann, kann die
> Timer1 ISR den nicht nach high schalten. Über das PORT Register geht das
> dann nicht. Oder wie hast du dir das gedacht?
Naja, genau so :-(

>> (Der
>> Timer setzt den pin nie high, cleart ihn nur. Lt. Datenblatt sollte das
>> gehen)
>
> Welcher Modus soll das sein?
ich dachte an "Compare Output Mode, non-PWM Mode"
Da gibts zwar "Clear OC0A on Compare Match", aber da steht leider recht 
klar: "If one or both of the COM0A1:0 bits are set, the
OC0A output overrides the normal port functionality of the I/O pin it is 
connected to."

Ok, Plan B :-)

Danke jedenfalls für den Hinweis...

von Michael R. (Firma: Brainit GmbH) (fisa)


Lesenswert?

Falk Brunner schrieb:
> Und wozu braucht man da ZWEI Timer? Das kann EINER spielend, das
> richtige Konzept vorausgesetzt.
Davon bin ich überzeugt. Und genau das Konzept versuche ich gerade 
zusammenzutragen.

> Naja, über welche Frequenzen reden wir denn? Ein 0815 Schrittmotor kommt
> doch eher nicht über 10 kHz. Die kann man auch ohne Output Compare
> direkt per CPU und Timerinterrupt erzeugen.

Maximal 20kHz, aber eher 10kHz oder niedriger. Und die 10kHz auch nur 
wegen recht feinem Microstepping.

von Michael R. (Firma: Brainit GmbH) (fisa)


Lesenswert?

Kein Name schrieb:
> GRBL hat da eine einfache Methode. Die rufen die ISR sehr oft auf, und
> überprüben in der ISR, ob es mal wieder Zeit für einen Schritt wird.

Ja, kenn ich. Aber wie gesagt, ich hab andere Anforderugnen. bei denen 
gehts um 2- oder 3D-Bresenham, Bahnsynchronität etc. Das brauch ich 
alles nicht. Dafür brauch ich recht freie geschwindigkeiten (und freie 
Geschwindigkeitsänderungen)

von m.n. (Gast)


Lesenswert?

http://www.mino-elektronik.de/Generator/takte_impulse.htm#bsp3
In diesem Beispiel wird nur OC1B benutzt; OC1A ist noch frei und kann 
für einen 2. Schrittmotor genommen werden. Lediglich die Ausgänge 
(insbesondere PB1) müssen angepaßt werden.

von blue man (Gast)


Lesenswert?

Ich habe jetzt zwar nur das Datenblatt meines ATmega32 im Kopf, aber da 
steht bei seinem (einzigen) 16bit Timer, daß seine 
Phase-And-Frequency-Correct-PWM genau für die Ansteuerung von Motoren 
ist und der 16Bit-Timer mit seinen beiden Kanälen A und B gleichzeitig 
zwei Motoren ansteuern kann.
Lies Dir Dein Datenblatt nochmal genau durch, wenn der 16Bit-Zähler zwei 
Kanäle hat, ist er prädestiniert für den Job und kann die Aufgabe mit 
wenig Rechenlast leisten.

von Falk B. (falk)


Lesenswert?

@ Michael Reinelt (fisa)

>> GRBL hat da eine einfache Methode. Die rufen die ISR sehr oft auf, und
>> überprüben in der ISR, ob es mal wieder Zeit für einen Schritt wird.

>Ja, kenn ich. Aber wie gesagt, ich hab andere Anforderugnen. bei denen
>gehts um 2- oder 3D-Bresenham, Bahnsynchronität etc. Das brauch ich
>alles nicht. Dafür brauch ich recht freie geschwindigkeiten (und freie
>Geschwindigkeitsänderungen)

Irrtum, deine Ziele sind nahezu identisch. Denn eben die feinganulare 
Erzeugung von Frequenzen ala DDS IST eine ander Form des 
Bresenhamalgorithmus.

Ach dein Ansatz mit 2x 16 Bit Timer und OCR Funktion geht auch mit EINEM 
Timer. Wie ? Ganz einfach. Ersten stellt man auf "Toggle on Compare" und 
zeitens schaltet man die Zeitdiffernz in der zugehörigen ISR weiter. 
Damit kann EIN 16 Bit Timer frei durchlaufen. Etwa so.
1
ISR(TIMER1_COMPA_vect) {
2
   OCR1A += delta_A;
3
}


delta_A ist die Schrittweite, welche von einer statemachine in der 
Hauptschleife entsprechend berechnet wird.

von Grünberg (Gast)


Lesenswert?

Idee, falls die Motorsteuerung nur auf eine Flanke reagiert?

Timer2 läuft im normalen mode immer durch. Die Comparematchausgangespins 
sind mit der Motorsteuerung verbunden.
COM2xy auf Toggeln bei Comparematch

Timer1 macht über seine Comparematches das Timing für die Schritte.
In den Timer1 ISR wird:
das FOC2x bit gesetzt (erzeugt ein Toggle vom Timer2 zum Motor)
OCR2xy 2µs, oder wie lange auch immer der Puls dauern soll, höher als 
TCNT2 setzen. Motorpin wird dann zurückgetoggelt
seinen eigenes OCR1xy für nächsten Puls setzen.

Wird interessant, ob man die Timings, die richtigen Pegel beim Toggeln, 
das Ein/Ausschalten des Motors über die COM2xy Bits und keine extra 
Schritte bekommt grins

von Michael R. (Firma: Brainit GmbH) (fisa)


Lesenswert?

blue man schrieb:
> Phase-And-Frequency-Correct-PWM genau für die Ansteuerung von Motoren
> ist und der 16Bit-Timer mit seinen beiden Kanälen A und B gleichzeitig
> zwei Motoren ansteuern kann.

Ja, aber nicht so einfach mit komplett unterschiedlichen Frequenzen

Falk Brunner schrieb:
> Ach dein Ansatz mit 2x 16 Bit Timer und OCR Funktion geht auch mit EINEM
> Timer. Wie ? Ganz einfach. Ersten stellt man auf "Toggle on Compare" und
> zeitens schaltet man die Zeitdiffernz in der zugehörigen ISR weiter.
> Damit kann EIN 16 Bit Timer frei durchlaufen. Etwa so.
> ISR(TIMER1_COMPA_vect) {
>    OCR1A += delta_A;
> }
>
> delta_A ist die Schrittweite, welche von einer statemachine in der
> Hauptschleife entsprechend berechnet wird.

Es wird wohl eh darauf hinauslaufen. Ich würde das gerne nur insofern 
optimieren, dass eine der beiden Flanken "in Hardware" geschaltet wird, 
und ich dafür keine ISR brauche. Nach der anderen Flanke muss ich eine 
neue Schrittweite berechnen. Das würde ich gerne in der ISR machen. also 
etwa in der Art:
1
ISR(TIMER1_COMPA_vect) {
2
if (steigende Flanke)
3
   OCR1A += Impulsbreite;
4
else
5
   OCR1A += Schrittweite() - Impulsbreite ;
6
}

von m.n. (Gast)


Lesenswert?

Michael Reinelt schrieb:
> Ich würde das gerne nur insofern
> optimieren, dass eine der beiden Flanken "in Hardware" geschaltet wird,
> und ich dafür keine ISR brauche. Nach der anderen Flanke muss ich eine
> neue Schrittweite berechnen. Das würde ich gerne in der ISR machen.

Ich hatte Dir ja Beispielcode verlinkt, wo die Schritte per 
Timer-Hardware ausgegeben werden. Lesen bildet!

von Michael R. (Firma: Brainit GmbH) (fisa)


Lesenswert?

m.n. schrieb:
> Ich hatte Dir ja Beispielcode verlinkt, wo die Schritte per
> Timer-Hardware ausgegeben werden. Lesen bildet!

jetzt wo du's sagst... ich hab mir gestern abend noch den Code 
angeschaut, aber leider nicht verstanden :-) und dann vergessen 
nachzufragen...

Soweit ich das durchblicke, wird per Output Compare der Pin gesetzt, 
gleichzeitig ein interrupt ausgelöst, und als erstes in der ISR der Pin 
wieder gelöscht, und das auch noch ((zitat) "per Force Output Compare 
erzwingen"

Der geht also (recht trickreich) davon aus, dass zwischen setzen des 
Pins und löschen des Pins in der ISR genug Zeit vergeht, damit der 
Step-Impuls lange genug ist?

ist das nicht eher "mutig" ?

wäre aber eine schöne Lösung!

von m.n. (Gast)


Lesenswert?

Michael Reinelt schrieb:
> Der geht also (recht trickreich) davon aus, dass zwischen setzen des
> Pins und löschen des Pins in der ISR genug Zeit vergeht, damit der
> Step-Impuls lange genug ist?

Der A8982 braucht Schrittimpulse >= 1µs; bevor das Programm zum Löschen 
des OC1x-Pins kommt, muß die Interruptroutine jede Menge Register 
retten, was hinreichend Zeit braucht.

> ist das nicht eher "mutig" ?

Wenn man es braucht, kann man ein Monoflop nachschalten (1), ein 
'delay_ms(100);' einfügen (2), oder das Bit weiter hinten im 
Programmablauf löschen (3).

Die richtige Lösung ist (3) ;-)

von Michael R. (Firma: Brainit GmbH) (fisa)


Lesenswert?

m.n. schrieb:
> Michael Reinelt schrieb:
>> Der geht also (recht trickreich) davon aus, dass zwischen setzen des
>> Pins und löschen des Pins in der ISR genug Zeit vergeht, damit der
>> Step-Impuls lange genug ist?
>
> Der A8982 braucht Schrittimpulse >= 1µs; bevor das Programm zum Löschen
> des OC1x-Pins kommt, muß die Interruptroutine jede Menge Register
> retten, was hinreichend Zeit braucht.

Same here: Der  DRV5525 brauch ebenfalls >= 1usec
 Rechnen wir noch eine "Angst-Microsekunde" dazu, wären das bei 16MHz 
gerade mal 32 takte.

>> ist das nicht eher "mutig" ?
>
> Wenn man es braucht, kann man ein Monoflop nachschalten (1), ein
> 'delay_ms(100);' einfügen (2), oder das Bit weiter hinten im
> Programmablauf löschen (3).
>
> Die richtige Lösung ist (3) ;-)

ich hätte noch (4):
1
while (TCNT1-OCR1A < 32);

die "Angst-Variante" :-) und die 32 könnte man sogar vom Compiler aus 
F_CPU und Impulsbreite ausrechnen lassen...

DANKE! ich betrachte das Problem damit als gelöst!

von m.n. (Gast)


Angehängte Dateien:

Lesenswert?

Michael Reinelt schrieb:
> ich hätte noch (4):
> while (TCNT1-OCR1A < 32);

Und richtige Angsthasen schreiben diesen Code 2 x nacheinander :-(

T1-int.txt zur Abschätzung der Laufzeit.

von Michael R. (Firma: Brainit GmbH) (fisa)


Lesenswert?

m.n. schrieb:
> Und richtige Angsthasen schreiben diesen Code 2 x nacheinander :-(

Woher weisst du? :-)

von m.n. (Gast)


Lesenswert?

Michael Reinelt schrieb:
> Woher weisst du? :-)

Ach, wenn man hier so einige Beiträge liest, hat man anschließend das 
Gefühl, ohne mindestens 10-20 Versicherungen nicht mehr vor die Tür 
gehen zu dürfen. Und dabei kann man sich nicht einmal gegen die eigene 
Blödheit versichern :-)

Berichte mal irgendwann, wie weit Du mit Deiner Schrittmotorgeschichte 
nebst Rampengenerierung gekommen bist. An anderer Stelle hattest Du ja 
schon 'gelernt', dass float- nicht langsamer als int-Berechnungen sein 
müssen.
Irgendwann mache ich das einmal mit einem STM32F4xx, der eine FPU auf 
dem Chip hat. Das geht schnell und man kann den Fix-Komma-Nichts-Punkt 
Experten eine lange Nase zeigen :-)

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.