Moinmoin zusammen,
ich habe probleme beim benutzen des Timer2 auf einem ATMEGA 328P.
Grundsätzliche Aufgabenstellung:
Ansteuerung von 2 Schrittmotoren mit unabhängiger Drehzahl.
Dafür möchte ich Timer 1 und 2 benutzen. Timer 1 funktioniert super. Für
Timer2 wollte ich eine Library verwenden. Es handelt sich um MsTimer2.
Diese bietet allerdings nur msec resolution, ich brauche aber
Mikrosekunden. Ich werde jetzt allerdings aus den genauen Einstellungen
nicht schlau. Die Library setzt über die CS-Bits den Prescaler.
tcnt2 = 256 - (int)((float)F_CPU * 0.001 / prescaler)
Hier fängt mein Verständnisproblem an. Der Rechte Teil wäre ja quasi so
zu verstehen
F_CPU/prescaler --> Eingangsfrequenz des Timers --> 250kHz * 0.001 um
auf Msec zu kommen.
256 - wäre dann der Wert bis zu dem Hochgezählt werden muss um beim
Overflow auf 1 Msec zu kommen. Aber ich finde im Datenblatt keine
Informationen darüber wie genau das tcnt2 funktioniert.
das beantwortet meine Frage nicht ganz. Ich ging davon aus, dass der
Timer bis 0xFF läuft und TCNT2 den aktuellen Zählerstand enthält. Es
sieht ja aber so aus als wäre TCNT2 im vorliegenden Fall die Schwelle
BIS zu der gezählt wird? nur so ergeben die Rechnungen ja Sinn?
cableer,
es steht doch alle zu den verschiedene Timer2-Modi und den Registern im
Datenblatt.
tcnt2 ist das Zählregister.
Es wird bei jedem Timertick, i.a. um 1 erhöht.
Karl M. schrieb:> cableer,>> es steht doch alle zu den verschiedene Timer2-Modi und den Registern im> Datenblatt.>> tcnt2 ist das Zählregister.> Es wird bei jedem Timertick, i.a. um 1 erhöht.
Das ist aber keine Antwort die zum Problem und der Library passt. Dort
wird TCNT2 explizit auf einen errechneten Wert gesetzt. Das ist das was
ich nicht ganz verstehe
cableer schrieb:> Ich ging davon aus, dass der> Timer bis 0xFF läuft und TCNT2 den aktuellen Zählerstand enthält.
Das ist auch so.
cableer schrieb:> Es> sieht ja aber so aus als wäre TCNT2 im vorliegenden Fall die Schwelle> BIS zu der gezählt wird?
Nö. Wenn du einen CTC Modus benutzt, würde MAX durch OCR2A bestimmt.
TCNT2 ist der aktuelle Zählerstand. Siehe Tabelle 18-8.
Matthias S. schrieb:> cableer schrieb:>> Ich ging davon aus, dass der>> Timer bis 0xFF läuft und TCNT2 den aktuellen Zählerstand enthält.>> Das ist auch so.>> cableer schrieb:>> Es>> sieht ja aber so aus als wäre TCNT2 im vorliegenden Fall die Schwelle>> BIS zu der gezählt wird?>> Nö. Wenn du einen CTC Modus benutzt, würde MAX durch OCR2A bestimmt.> TCNT2 ist der aktuelle Zählerstand. Siehe Tabelle 18-8.
Dann verstehe ich diese Zeile in der Library nicht:
tcnt2 = 2; //256 - (int)((float)F_CPU * 0.001 / prescaler);
sorry das war jetzt misleading, im original so:
tcnt2 = 256 - (int)((float)F_CPU * 0.001 / prescaler);
die 2 war für einen versuch von mir mit dem oszi
diese Zeile deute darauf hin, das Timer2 im Overflow Modus mit 1000Hz
läuft, da brauche ich mir nicht mal den restlichen Code ansehen.
Der Overlow Mode ist im Datenblatt beschrieben.
Vom der aktuellen Zählerstand bis 0xff wird gezählt und bei 0x00 wird
ein Interrupt generiert.
So wird meistens der Zählerstand in der ISR wieder auf
1
tcnt2=256-(uint16_t)(1.0*F_CPU/1000/prescaler);
gesetzt, so dass der Timer2 immer den gleichen Rhythmus (1000Hz) hat.
Karl M. schrieb:> tcnt2 = 256 - (uint16_t)(1.0 *F_CPU /1000 /prescaler);diese Zeile deute> darauf hin, das Timer2 im Overflow Modus mit 1000Hz> läuft, da brauche ich mir nicht mal den restlichen Code ansehen.>> Der Overlow Mode ist im Datenblatt beschrieben.> Vom der aktuellen Zählerstand bis 0xff wird gezählt und bei 0x00 wird> ein Interrupt generiert.> So wird meistens der Zählerstand in der ISR wieder auftcnt2 = 256 -> (uint16_t)(1.0 *F_CPU /1000 /prescaler);gesetzt, so dass der Timer2> immer den gleichen Rhythmus (1000Hz) hat.
Das hatte ich ja auch vermutet, allerdings kann ich in der ISR nichts
derartiges sehen?
Karl M. schrieb:
> tcnt2 = 256 - (uint16_t)(1.0 *F_CPU /1000 /prescaler);diese Zeile deute> darauf hin, das Timer2 im Overflow Modus mit 1000Hz> läuft, da brauche ich mir nicht mal den restlichen Code ansehen.>> Der Overlow Mode ist im Datenblatt beschrieben.> Vom der aktuellen Zählerstand bis 0xff wird gezählt und bei 0x00 wird> ein Interrupt generiert.> So wird meistens der Zählerstand in der ISR wieder auftcnt2 = 256 -> (uint16_t)(1.0 *F_CPU /1000 /prescaler);gesetzt, so dass der Timer2> immer den gleichen Rhythmus (1000Hz) hat.
Das hatte ich ja auch vermutet, allerdings kann ich in der ISR nichts
derartiges sehen?
ich 'nehm alles zurück! Danke Karl, ich habe es jetzt verstanden
Die Hardware dafür existiert schon, ich muss mich also an ein
vorgegebenes Pinout halten und deswegen die Ausgänge über
Portmanipulationen in der ISR schalten.
Allgemein:
Wie wäre es denn generell möglich mit nur einem Timer verschiedene
Ausgangsfrequenzen zu erzeugen? Also nicht nur irgendwelche Bits
abzapfen sondern wirklich mit Timerclock-Auflösung einstellbar?
cableer schrieb:> Wie wäre es denn generell möglich mit nur einem Timer verschiedene> Ausgangsfrequenzen zu erzeugen?
Indem man z.B. die beiden Compare-Einheiten des Timers benutzt und in
deren ISRs den OC2x-Wert um das gewünschte Intervall erhöht.
...
cableer schrieb:> Die Hardware dafür existiert schon, ich muss mich also an ein> vorgegebenes Pinout halten und deswegen die Ausgänge über> Portmanipulationen in der ISR schalten.
Das ist doch kein Problem.
cableer schrieb:> Wie wäre es denn generell möglich mit nur einem Timer verschiedene> Ausgangsfrequenzen zu erzeugen? Also nicht nur irgendwelche Bits> abzapfen sondern wirklich mit Timerclock-Auflösung einstellbar?
Dafür hatte ich Dir die passenden Routinen geliefert. Aber mach, wie Du
meinst.
M. K. schrieb:> Mal ne doofe Frage: Warum benutzt du dafür ne fremde Libraray?> Sowas> macht man doch in 10 Minuten selbst dass Timer 2 jede Mikrosekunde mal> zuckt.
Simple Antwort: Um zu schauen wie andere Leute das gelöst haben und um
Timer2 besser zu verstehen. In der Anwendung benutze ich das nicht mehr.
Es geht mir ja nicht darum die Library als Ersatz für eigenes
Verständnis zu verwenden. Sie war einfach eine Einsteigshilfe für
Timer2.
m.n. schrieb:> cableer schrieb:>> Wie wäre es denn generell möglich mit nur einem Timer verschiedene>> Ausgangsfrequenzen zu erzeugen? Also nicht nur irgendwelche Bits>> abzapfen sondern wirklich mit Timerclock-Auflösung einstellbar?>> Dafür hatte ich Dir die passenden Routinen geliefert. Aber mach, wie Du> meinst.
Ich hab deinen Code getestet. Das Grundproblem war folgendes: Zu viel
Code in der ISR -> zu geringe Fmax. Ich bin mit dem ganzen leider schon
fast an der Grenze für den 328 bei 16MHz. Der Stepper hat schon ohne
Microstepping 800 steps/turn und ich muss leider sowohl sehr genaue als
auch einigermaßen zügige Bewegungen kommandieren können. Vermutliche
werde ich Microstepping und Vollschrittbetrieb mixen müssen
cableer schrieb:> Um zu schauen wie andere Leute das gelöst haben und um> Timer2 besser zu verstehen.
Das ist auch völlig OK
Aber wenn du jetzt was eigenes nutzt: Wo ist das Problem nun? Es ist
doch kein Hexenwerk zwei Schrittmotoren mit einem Atmega328 unabhängig
voneinander zu steuern. Erst recht wenn man zwei verschiedene Timer
benutzt. Ich habe grade irgendwie wirklich ein Problem dein Problem zu
erfassen. Dachte du hättest ein Problem mit der Lib, die du benutzt hast
aber jetzt schreibst du
cableer schrieb:> In der Anwendung benutze ich das nicht mehr.
und dann sollte es doch gar kein Problem sein zwei Schrittmotoren
anzusteuern.
m.n. hat ja auch schon ein gutes Beispiel dafür geliefert.
cableer schrieb:> Ich hab deinen Code getestet. Das Grundproblem war folgendes: Zu viel> Code in der ISR -> zu geringe Fmax. Ich bin mit dem ganzen leider schon> fast an der Grenze für den 328 bei 16MHz. Der Stepper hat schon ohne> Microstepping 800 steps/turn und ich muss leider sowohl sehr genaue als> auch einigermaßen zügige Bewegungen kommandieren können. Vermutliche> werde ich Microstepping und Vollschrittbetrieb mixen müssen
Dann wird es wohl nichts mit einem ATmega328. Zur Not kannst Du noch
Assembler bemühen und dabei nur die notwendigen Register
retten/wiederherstellen. Aber sobald noch eine weitere ISR verwendet
wird, kann das Timing in die Hose gehen. Es wird auch nicht besser, zwei
Timer zu verwenden, zumal 8-Bit Timer mit hoher Auflösung noch mehr
Rechenzeit für die Teilperioden brauchen.
Auch ein dynamisches Umschalten zwischen Mikro- und Vollschritt erzeugt
mehr Code in der ISR. Beschleunigungsrampen sind auch noch nirgends
vorhanden.
Sofern der Mega328 schon jetzt an der Grenze arbeitet, sieh Dich nach
einem anderen µC um oder verteile die Ansteuerung auf einen zweiten AVR.
Sonst kommst Du an den Punkt, an dem die Motore nur noch piepsen, sich
aber nicht mehr drehen ;-)
cableer schrieb:> Timer 1 funktioniert super.cableer schrieb:> Simple Antwort: Um zu schauen wie andere Leute das gelöst haben und um> Timer2 besser zu verstehen. In der Anwendung benutze ich das nicht mehr.> Es geht mir ja nicht darum die Library als Ersatz für eigenes> Verständnis zu verwenden. Sie war einfach eine Einsteigshilfe für> Timer2.
Eine der beiden Aussagen stimmt nicht...
Oliver
Nimm doch den Xmega32E5, der kann doppelt so schnell takten und hat
genügend Hardware, die sich um die gestellte Aufgabe kümmert, ohne dass
die CPU belastet wird. Achtung: Xmegas vertragen nur maximal 3.6V als
Betriebsspannung und Pin-Pegel.
Also Leute. Ein Atmega328 kann aber mal ganz locker auch alleine zwei
Schrittmotoren unabhängig von einander ansteuern. Hier jetzt einen
Atxmega auszupacken ist das sprichwörtliche "Mit Kanonen auf Spatzen"
schießen.
Microstepping mit hoher Geschwindigkeit ist schon eine Hausnummer. Und
das Ganze x2... Entweder Programmablauf optimieren oder schnelleren
Controller mit aufgebohrter Peripherie verwenden.
Knut B. schrieb:> Microstepping mit hoher Geschwindigkeit ist schon eine Hausnummer. Und> das Ganze x2... Entweder Programmablauf optimieren oder schnelleren> Controller mit aufgebohrter Peripherie verwenden.
Das ganze funktioniert jetzt soweit, allerdings habe ich folgendes
Problem:
In der ISR sieht es folgendermaßen aus
void timerISR()
{
counter1++;
counter2++;
if(counter1 > timing1 && steps1 > 0)
{
PORTD ^= B00100000;
counter1=0;
steps1--;
}
…gleiches für den 2. Stepper
}
Wenn ich für steps1 oder 2 ausserhalb des Main-loops Werte setze werden
diese sauber abgefahren. Sobald ich auf steps1/2 im Main loop zugreife
passiert in der ISR nichts mehr. Die variable erhält den korrekten Wert,
am Ausgang ist es aber still.
steps sind unsigned long int und global definiert.
Was mache ich da falsch/habe ich übersehen?
}