ATmega8 Servo ansteuern

Gast #905797
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
Angehängte Dateien:
#905857
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 ..
#905861
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
Gast #905890
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..
#905961
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
#994508
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
Gast #994585
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.
#995333
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

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren