Hallo! ich wuerde gerne wissen ob ich die Forumsbeitraege bezueglich Servos richtig verstanden habe! Hier mein Vorhaben (arbeite mit ATMega16 (16MHz), WinAVR-GCC): Ich will insgesamt 4 Servos ansteuern; das Hauptprogramm hat einiges zu rechnen (ca. 20 * sin/cos/atan u.a. pro Durchlauf). Ich opfere einen Timer der mir alle 3 Sekunden einen Interrupt erzeugt waehrend dem ich nacheinander fuer die 4 Servos einen Puls(5V) von 1ms...2ms erzeuge. Ausserhalb dieser Impulse sind die Servo-Pins low(0V). Das ergibt eine maximale Periodendauer von 4*(3+2)=20ms und eine minimale von 4*(3+1)=16ms. In den jeweils 3ms zwischen den Interrupts lass ich dem uC Zeit fuer meine sin, cos usw... richtig/falsch gedacht? prinzipielle Verbesserungen? danke allen Erfahrenen! mg, Johannes
Ich bin mir nicht sicher, aber brauchen die Servos nicht alle 20ms den Impuls? ich glaub bei mir war es so, sonst drehen die durch.
Du könntest auch den Timer dauernd einen 1-2ms-Impuls erzeugen lassen - das würde die Servos nicht stören. Einfach in der ISR einen neuen OC-Wert setzen und das nächste Servo einschalten. Und das im Kreis herum... Die Werte würden dann in einem Feld liegen, dessen Einträge durch die Berechnungen (vermutlich) verändert werden. Bei 4 Servos hat man dann sogar eine Simpel-Ringpuffer-taugliche Zahl...
ich denke mal deine 3 sekunden sollen Millisekunden sein... das mit Timer und Interrupt ist die eleganteste Lösung vergiss blos die volatile für die Servowerte nicht. Der Stellbereich von Servos liegt zwischen 0,8 und 2,2 ms mit 1 bis 2ms bekommt man je nach Typ nicht die vollen 180 grad. Danach solltest du ihnen etwas Zeit lassen. Etwas besser ist es nur jeweils die High Zeiten für das jeweilige Servo zu nehmen und dann eine Wartezeit bis 20ms einzulegen. Also in Timerinterrupt: 1. Servo1 auf 1 Lade Zeit für Servo1 in Timer Timer starten raus aus interrupt beim nächsten Timerinterrupt Servo1 auf 0 Servo2 auf 1 Lade Zeit für Servo2 in Timer Timer starten raus.. etc. bis zum letzten Servo dann Servox auf 0 Lade verbleibende Zeit bis 20ms Timer starten raus.. danach wieder zu 1. damit kannst du 10 Servos (bei max 2ms) betreiben und bleibst in der Spezifikation von 20ms. Wobei die meisten Servos auch eine längere Ruhepause akzeptieren. Dein Mikrocontroller hat für seine Berechnungen dabei die ganze Zeit abzüglich der paar Mikrosekunden für den Timerinterrupt.
Hallo, danke fuer eure Beitraege, ganz besonders @Wolfram!! Ich hab mal mit dem Timer angefangen und nach vielem Probieren und Ueberlegen nicht herausgefunden, warum mein Timer nicht geht?! warscheinlich ists ein Trivialikus den ich ueberseh. Die LEDs an PortC tun gar nix; eigentlich sollten eines 1s an, und danach 1s aus sein. Hier der Code: #include <avr/io.h> #include <inttypes.h> #include <avr/interrupt.h> #include <avr/signal.h> #ifndef F_CPU #define F_CPU 16000000 /* Oszillator-Frequenz in Hz */ #endif #define UART_BAUD_RATE 9600 #define UART_BAUD_CALC(UART_BAUD_RATE,F_OSC) ((F_CPU)/((UART_BAUD_RATE)*16L)-1) //globals volatile uint8_t counter; /*------Interrupt Service Routines---------------*/ /* output compare ISR, executed when TCNT1 = OCR1A*/ SIGNAL(SIG_OUTPUT_COMPARE1A) { counter++; } /*------------------------------Functions------------------------------- --*/ void timer16_load(uint16_t microsec) { //Zeitbasis fuer diesen Timer sind 0.5us, deswegen wird microsec mal zwei genommen (um eine Stelle geshiftet) // microsec = 2 -> OCF1A-interrupt in 2 us // microsec = 1000 -> OCF1A-interrupt in 1 ms OCR1A = (uint16_t)(microsec<<1); //loading timer-interrupt value } int main(void) { // Timer1 (16bit) config //prescaler = 8; -> Zeitbasis =0.47us ~= 0.5us CLEARBIT(TCCR2, CS22); SETBIT(TCCR2, CS21); CLEARBIT(TCCR2, CS20); //setting CTC mode = clear timer on compare SETBIT(TCCR1B, WGM12); //enable output compare interrupt (when TCNT1=OCR1A) SETBIT(TIMSK, OCIE1A); //other initialization stuff counter = 0; DDRC = 0XFF; PORTC = 0x00; sei(); timer16_load(32000); //load 32ms in den Timer for(;;) { if (counter>=31) //31*32ms = 992ms ~= 1s SETBIT(PORTC,PC3); else CLEARBIT(PORTC,PC2); if (counter>= 62) counter=0; }//for(;;) }//main() also wer sieht den Fehler??
SETBIT und CLEARBIT sollen natuerlich dasselbe bit PC2 verwenden. Das hatte ich nur aus Testzwecken geaendert...
Hallo! also ich hab's. Es ist tatsaechlich ein Trivialikus gewesen: Ich hab staendig vom Timer1 geredet und gelesen und gesucht und Register gechecked bis mir ... grgrgrgr Sollte jemand meinen obigen Code verwenden muessen folgende drei Zeilen ersetzt werden: CLEARBIT(TCCR2, CS22); SETBIT(TCCR2, CS21); CLEARBIT(TCCR2, CS20); zu ersetztn durch: CLEARBIT(TCCR1B, CS22); SETBIT(TCCR1B, CS21); CLEARBIT(TCCR1B, CS20); mg, Johannes
Das dürfte aber noch nicht ganz richtig sein. Jetzt mal ohne deine Werte nachzurechnen... Der TimerInterrupt sollte eigentlich nur kommen, wenn im Statusregister allgemein Interrupts erlaubt sind.(zusätzlich zu TIMSK Interruptflag) mit CLEARBIT/SETBIT änderst du die Bits einzeln nacheinander! d.h. du setzt 3x eine andere Zeitbasis für den Timer ,der beim ersten setzen losläuft. Dies hat in diesem Fall, da es unmittelbar hintereinander geschieht wahrscheinlich keinen Einfluß, aber dein Timer läuft los ,es könnte also ein Interrupt vor deinen 32ms auftreten. Erst die Werte setzen dann eine Taktquelle an den Timer legen,denn dann läuft er los.
..Zitat CLEARBIT(TCCR2, CS22); SETBIT(TCCR2, CS21); CLEARBIT(TCCR2, CS20); zu ersetztn durch: CLEARBIT(TCCR1B, CS22); SETBIT(TCCR1B, CS21); CLEARBIT(TCCR1B, CS20); /Zitat noch richtiger, obwohl das gleiche: CLEARBIT(TCCR2, CS22); SETBIT(TCCR2, CS21); CLEARBIT(TCCR2, CS20); zu ersetztn durch: CLEARBIT(TCCR1B, CS12); SETBIT(TCCR1B, CS11); CLEARBIT(TCCR1B, CS10); Beim Teilerfaktor 8 haut das alles noch hin. Dusseliger wird es, wenn Du 256 vorteilen willst und alle drei Timer gleich initialisierst, (weil du zB alle in deiner Applikation brauchst) Dadurch, dass sich beim Timer2 der Faktor 1/128 "zwischenschiebt", stimmt dann garnichts mehr. Siehe Datenblatt Seite 112 Tabelle 48 (Timer1 Prescaler) und zum Vergleich Seite 129 Tabelle 54 (Timer2 Prescaler) Gruß Axel
Hallo, also die Bemerkung von Wolfram bezueglich Timerinitialisierung [dreimal SETBIT() ist ungut -> verwende anstelle TCCR1B |= (1<<CSxx)|(1<<CSxx)|(1<<CSxx) ] leuchtet mir ein! Danke fuer den Hinweis. @AxelR In meiner Applikation verwend ich tatsaechlich manchmal alle Timer, und zwar mit ganz unterschiedlichen Teilfaktoren. Ich versteh aber leider nicht auf welches Problem du dich beziehst? Die Timer sind doch unabhaengig voneinander; ich kann sie doch initialisieren wo und wann ich will ohne dass sie sich beeinflussen. Prescaler-Faktoren sind natuerlich teilweise unterschiedlich... Sitz ich auf der Leitung? bitte um Aufklaerung. mg, Johannes
Jahaa, war ja nur für die faulen.. ich hatte mir temp1(R16) mit den (für alle drei gleichen) Teilerfaktor geladen und nacheinander die drei TCCRs damit geladen, da tanzte dann ein Timer aus der Reihe. ich weiss, Thema verfehlt, 6, setzen. :-)
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.