Forum: Mikrocontroller und Digitale Elektronik ATmega8 Servo ansteuern


von Udo (Gast)


Angehängte Dateien:

Lesenswert?

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

von Peter B. (pbuenger)


Lesenswert?

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 ..

von Alexander L. (lippi2000)


Lesenswert?

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

von Udo (Gast)


Lesenswert?

@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..

von Peter B. (pbuenger)


Lesenswert?

> 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

von Udo (Gast)


Lesenswert?

@Peter

Funktioniert , Vielen Dank.
Inzwischen habe ich auch verstanden was genau hinter den 6 Zeilen steht.

von Udo (Gast)


Lesenswert?

@ Peter

Auch Danke nochmal für die konstruktive Kritik, so kann man sehr gut 
Fehler verbessern. Stimme Dir in allen Punkten zu ..

Gruß
Udo

von Peter B. (pbuenger)


Lesenswert?

Danke für die Rückmeldung, da macht das Helfen auch mal Spaß.

Gruß,
Peter

von Christian J. (stormracer)


Lesenswert?

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

von STK500-Besitzer (Gast)


Lesenswert?

>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.

von Christian J. (stormracer)


Lesenswert?

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
Noch kein Account? Hier anmelden.