mikrocontroller.net

Forum: Mikrocontroller und Digitale Elektronik ATmega8 Servo ansteuern


Autor: Udo (Gast)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht 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

Autor: Peter Bünger (pbuenger)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo Udo,

um zwei Servos an den OC1A und OC1B Pins eines Mega8 zu betreiben,
reicht schon eine Handvoll Codezeilen:

// Servo Frame-Time:
#define FRAME_TIME 20 // msec

// init timer 1:
ICR1   = FRAME_TIME * 1000;                      // PWM cycle time in usec
TCCR1A = (1<<COM1A1) | (1<<COM1B1) | (1<<WGM11); // OC1A/B clr on match, set on TOP
TCCR1B = (1<<WGM13) | (1<<WGM12) | (1<<CS11);    // TOP = ICR1, clk = sysclk/8 (->1us)
TCNT1  = 0;                                      // reset Timer

OCR1A  = 1000;    // set Servo 1 to 1ms-position
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 ..

Autor: Alexander Liebhold (lippi2000)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hi,
also du musst schon den Zählwert des Timers schreiben, bevor du ihn 
aktivierst.

Irgendwas stimmt aber mit deiner IRQ-Routine nicht...
ISR(TIMER2_OVF_vect) /* veraltet: SIGNAL(SIG_OVERFLOW0) */
{
u08 countdown;

//Es wird immer nur IF-Bedingung ausgeführt, da TCCR2 immer 5 bleibt!!!

  if (TCCR2 == 5){ // Prescaler 1024 (nach 20ms)
    TCNT2=151; //131x weiterzählen +20x für die noch zu verbrauchenden takte der schleife
    TCCR2= (1<<CS22); // prescaler 64 für genau 1ms
    PORTB |= (1 << PB2); 
//PORT B2 wird High und der Zählwert wird neu gesetzt --> schleife wird verlassen (nächster int mit diesem Zählwert!!!
    
  }
  else{
    for(countdown = 0xff; countdown !=0; countdown --){
  
      if(stellung == countdown){
        PORTB &= ~(1 << PB2); 
      }
    _delay_us(95);
    }
    TCNT2 = 100;
    TCCR2 = 5; // presc 1024 für 20ms
  }
}

Also du willst doch die Tasten entprellen???Da solltest du grundlegend 
nochmals überlegen.

Gruß Alexander

Autor: Udo (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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.
//Es wird immer nur IF-Bedingung ausgeführt, da TCCR2 immer 5 bleibt!!!

  if (TCCR2 == 5){ // Prescaler 1024 (nach 20ms)
    TCNT2=151; //
    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 ? 
    PORTB |= (1 << PB2); 
 
  }

Danke für eure Hilfe, und superschnell..

Autor: Peter Bünger (pbuenger)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Udo (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@Peter

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

Autor: Udo (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Peter Bünger (pbuenger)
Datum:

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

Gruß,
Peter

Autor: Christian J. (stormracer)
Datum:

Bewertung
0 lesenswert
nicht 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:
>
>
>
// Servo Frame-Time:
> #define FRAME_TIME 20 // msec
> 
> // init timer 1:
> ICR1   = FRAME_TIME * 1000;                      // PWM cycle time in
> usec
> TCCR1A = (1<<COM1A1) | (1<<COM1B1) | (1<<WGM11); // OC1A/B clr on match,
> set on TOP
> TCCR1B = (1<<WGM13) | (1<<WGM12) | (1<<CS11);    // TOP = ICR1, clk =
> sysclk/8 (->1us)
> TCNT1  = 0;                                      // reset Timer
> 
> OCR1A  = 1000;    // set Servo 1 to 1ms-position
> 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 ..

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

Autor: STK500-Besitzer (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Christian J. (stormracer)
Datum:

Bewertung
0 lesenswert
nicht 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

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.