Hallo, ATmega8, 8Mhz interner RC-Takt, avr-gcc (WinAVR 20080512) 4.3.0 Schon zig Beiträge im Forum, ich finde leider trotzdem keine Lösung für mein Problem. Vielleicht kann jemand einen Blick auf den Code werfen und sieht einen Fehler. Timer0 verwende ich für die Tasten-Entprellung. Ich möchte per Taster die Stellung des Servos verändern. Der Servo reagiert nicht, bekommt also keine vernünftigen Impulse. Ich hab den Servo probiert über eine einfache delay-Funktion anzusteuern, das funktioniert. Ich bin noch relativ ungeübt mit Timern/Interrupts, allerdings will ich mir das aneignen und ich denke es ist die wesentlich elegantere Variante als über eine Delay-Funktion. Gruß Udo
Hallo Udo, um zwei Servos an den OC1A und OC1B Pins eines Mega8 zu betreiben, reicht schon eine Handvoll Codezeilen:
1 | // Servo Frame-Time:
|
2 | #define FRAME_TIME 20 // msec
|
3 | |
4 | // init timer 1:
|
5 | ICR1 = FRAME_TIME * 1000; // PWM cycle time in usec |
6 | TCCR1A = (1<<COM1A1) | (1<<COM1B1) | (1<<WGM11); // OC1A/B clr on match, set on TOP |
7 | TCCR1B = (1<<WGM13) | (1<<WGM12) | (1<<CS11); // TOP = ICR1, clk = sysclk/8 (->1us) |
8 | TCNT1 = 0; // reset Timer |
9 | |
10 | OCR1A = 1000; // set Servo 1 to 1ms-position |
11 | OCR1B = 2000; // set Servo 1 to 2ms-position |
Durch die Verwendung der Output-Compare-Funktion des 16bit-Timers 1 bleiben die Servos gesteuert, ohne dass der Prozessor auch nur einen einzigen Befehl dazu abarbeiten müsste. Mit Deinen Tasten brauchst Du jetzt nur noch die OCR-Register zu verändern. Gruß, Peter P.S. Dein Code ist ja echt gruselig ..
Hi, also du musst schon den Zählwert des Timers schreiben, bevor du ihn aktivierst. Irgendwas stimmt aber mit deiner IRQ-Routine nicht...
1 | ISR(TIMER2_OVF_vect) /* veraltet: SIGNAL(SIG_OVERFLOW0) */ |
2 | { |
3 | u08 countdown; |
4 | |
5 | //Es wird immer nur IF-Bedingung ausgeführt, da TCCR2 immer 5 bleibt!!! |
6 | |
7 | if (TCCR2 == 5){ // Prescaler 1024 (nach 20ms) |
8 | TCNT2=151; //131x weiterzählen +20x für die noch zu verbrauchenden takte der schleife |
9 | TCCR2= (1<<CS22); // prescaler 64 für genau 1ms |
10 | PORTB |= (1 << PB2); |
11 | //PORT B2 wird High und der Zählwert wird neu gesetzt --> schleife wird verlassen (nächster int mit diesem Zählwert!!! |
12 | |
13 | } |
14 | else{ |
15 | for(countdown = 0xff; countdown !=0; countdown --){ |
16 | |
17 | if(stellung == countdown){ |
18 | PORTB &= ~(1 << PB2); |
19 | } |
20 | _delay_us(95); |
21 | } |
22 | TCNT2 = 100; |
23 | TCCR2 = 5; // presc 1024 für 20ms |
24 | } |
25 | } |
Also du willst doch die Tasten entprellen???Da solltest du grundlegend nochmals überlegen. Gruß Alexander
@Peter Danke werd es damit mal probieren. Inwiefern ist der gruselig ? In Bezug auf den Stil oder Inhalt ? @Alexander Die Tasten entprell ich mit Timer0, die haben mit meinem Problem eigentlich nichts zu tun.
1 | //Es wird immer nur IF-Bedingung ausgeführt, da TCCR2 immer 5 bleibt!!!
|
2 | |
3 | if (TCCR2 == 5){ // Prescaler 1024 (nach 20ms) |
4 | TCNT2=151; // |
5 | TCCR2= (1<<CS22); // wird hier nicht ein neuer Wert für TCCR2 gesetzt, der erst mit der nächsten else-Schleife wieder auf 5 geändert wird ? |
6 | PORTB |= (1 << PB2); |
7 | |
8 | }
|
Danke für eure Hilfe, und superschnell..
> Inwiefern ist der gruselig ? In Bezug auf den Stil oder Inhalt ?
Beides. Bespiel für Stil:
Du initialisierst TCCR2 schön lesbar mit
"(1<<CS22)|(1<<CS20)|(1<<CS21)", fragst dann aber in der ISR auf "(TCCR2
== 5)" ab. Hier muss der Leser unnötigerweise erstmal Bits in Dezimal
umrechnen. Und eine Abfrage ">=255" mit einer 8Bit unsigned-Variablen
ist ziemlich verwirrend, da deren Wertebereich eben nur mal bis 255
geht.
Beispiel Inhalt:
Delay-Funktionen innerhalb einer ISR sind absolut PFUI, BAH! Dann
scheinst Du die Funktionsweise des Timers noch nicht verstanden zu
haben. Wenn Du TCNT2 mit 151 beschreibst, dann zählt der Timer von dort
aus weiter bis 255 und erzeugt einen Interrupt. Bis dahin hat er 255-151
Takte gezählt, und nicht 151.
Gruß,
Peter
@Peter Funktioniert , Vielen Dank. Inzwischen habe ich auch verstanden was genau hinter den 6 Zeilen steht.
@ Peter Auch Danke nochmal für die konstruktive Kritik, so kann man sehr gut Fehler verbessern. Stimme Dir in allen Punkten zu .. Gruß Udo
Danke für die Rückmeldung, da macht das Helfen auch mal Spaß. Gruß, Peter
Peter Bünger wrote: > Hallo Udo, > > um zwei Servos an den OC1A und OC1B Pins eines Mega8 zu betreiben, > reicht schon eine Handvoll Codezeilen: > > >
1 | // Servo Frame-Time:
|
2 | > #define FRAME_TIME 20 // msec |
3 | >
|
4 | > // init timer 1: |
5 | > ICR1 = FRAME_TIME * 1000; // PWM cycle time in |
6 | > usec |
7 | > TCCR1A = (1<<COM1A1) | (1<<COM1B1) | (1<<WGM11); // OC1A/B clr on match, |
8 | > set on TOP |
9 | > TCCR1B = (1<<WGM13) | (1<<WGM12) | (1<<CS11); // TOP = ICR1, clk = |
10 | > sysclk/8 (->1us) |
11 | > TCNT1 = 0; // reset Timer |
12 | >
|
13 | > OCR1A = 1000; // set Servo 1 to 1ms-position |
14 | > OCR1B = 2000; // set Servo 1 to 2ms-position |
15 | >
|
> > > Durch die Verwendung der Output-Compare-Funktion des 16bit-Timers 1 > bleiben die Servos gesteuert, ohne dass der Prozessor auch nur einen > einzigen Befehl dazu abarbeiten müsste. Mit Deinen Tasten brauchst Du > jetzt nur noch die OCR-Register zu verändern. > > Gruß, > Peter > > P.S. Dein Code ist ja echt gruselig .. Hallo, dieser Thread ist zwar schon ein paar Monate alt, aber das hier gepostete Problem dekt sich ganz gut mit meinem. Auch ich möchte zwei Servos ansteuern und habe auch den Timer1 dafür gedacht. Die von Peter Bünger geposteten Codezeilen scheinen also auch für mein Problem die richtigen zu sein. Mein Problem ist jetzt nur, dass ich einen Mega32 verwende. Der mit einem Takt von 16Mhz betrieben wird. Also müsste ich ja eigentlich den Prescaler auf 16 setzten, den es aber leider nicht gibt. Also hab ich mir als nächstes gedacht, dass ich bei ICR1 40000 setzte. Damit er länger braucht um den Match zu haben. Nur leider funktioniert das ganze nicht so, wie es soll. Ich muss bei OCR1X Werte zwischen ca. 1000 und ca. 5000 angeben, damit er sich ziemlich weit dreht. Allerdings erreicht er dadurch noch nicht seine Endpositionen. Bei Werten über 6000 "zittert" er nur noch. Wahscheinlich habe ich bei der Berechnung der Frequenz und des Puls / Pause Verhältnisses etwas noch nicht richtig verstanden. Über Hinweise und Lösungsvorschläge würde ich mich sehr freuen. Gruß Christian
>Also hab ich mir als nächstes gedacht, dass ich bei ICR1 40000 setzte. >Damit er länger braucht um den Match zu haben. Schon mal richtig gerechnet. >Nur leider funktioniert das ganze nicht so, wie es soll. Ich muss bei >OCR1X Werte zwischen ca. 1000 und ca. 5000 angeben, damit er sich >ziemlich weit dreht. Allerdings erreicht er dadurch noch nicht seine >Endpositionen. Bei Werten über 6000 "zittert" er nur noch. Bei 16MHz und einer Teilung durch Acht, ergibt sich eine Timer-Tick-Periodendauer von 0,5µs (oder auch 500 Nanosekunden). 1 ms sind dann 2000 Ticks (OCR1x-Wert), 2 ms sind dann 4000 Ticks. Alles dazwischen sollte dein Servo anfahren können. Alles darüber verwirrt ihn nur.
Danke für die hilfreichen Erklärungen TOP Funktioniert nun alles wie gewünscht. Ich hatte gestern Versucht mit Hilfe einer For Schleife den ganzen Wertebereich immer durchzuzählen. Dabei habe ich dann noch vergessen, dem Servo Zeit zu gegben, die Position anzufahren. Daduch hat er auch nie die Endpunkte erreicht. Danke schön und Gruß Christian
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.