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?
Hi
>Nehm ich halt einfach zwei 16bit-Timer (Haha, wenn es denn zwei gäbe)
In DIL: ATMega1284P.
MfG Spess
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
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
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.
@ 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.
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...
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.
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)
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.
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.
@ 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.
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
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 | }
|
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!
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!
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) ;-)
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!
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.
m.n. schrieb: > Und richtige Angsthasen schreiben diesen Code 2 x nacheinander :-( Woher weisst du? :-)
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.