- 3D-Druck Einstieg und Tipps         
Ergebnis 1 bis 9 von 9

Thema: Servo mit 8-bit Timer (AVRmega32) ?

  1. #1

    Servo mit 8-bit Timer (AVRmega32) ?

    Anzeige

    LiFePo4 Akku selber bauen - Video
    Hallo,
    wie kann ich 50Hz frequent für mein servo mit 8-bit timer (timer0 oder timer2 von mega32) erzeugen? Ich benutze 16mhz Taktfrequent
    Timer1 in mein Board ist shon besetzt, ich kann das nicht benutzen.

    sorry für mein schlechtes deutsch.
    Vielen Dank.

  2. #2
    Erfahrener Benutzer Robotik Einstein Avatar von wkrug
    Registriert seit
    17.08.2006
    Ort
    Dietfurt
    Beiträge
    2.214
    Das kommt halt darauf an, mit welcher Präzision das Servo angesteuert werden soll.
    Ich würd es mal mit einem preload Wert im TCNT2 versuchen.
    Und zu diesem Zeitpunkt den Impulsausgang einschalten.
    Dann in der Timer 2 Overflow Routine ein Register hochzählen, bis der Sollwert erreicht ist (zwischen 1 und 2ms).
    Ist dieser erreicht den Impulsausgang wieder abschalten.
    Die Pausen zwischen den Impulsen (ca. 20ms) könnte man auch so erzeugen.
    Lediglich die Berechnung des Preload Wertes stell ich mir ein bischen Trickreich vor.
    Ich weiss jetzt blos nicht sicher, ob man den Prescaler für den TCNT 2 einzeln einstellen kann, oder ob der nicht mit einem anderen Zähler gekoppelt ist.

  3. #3
    Benutzer Stammmitglied
    Registriert seit
    05.03.2005
    Beiträge
    36

    Da hätte ich auch mal eine Frage zu...

    Hi Leutz,

    ich steh eigentlich vor dem selben Problem:

    Code:
    #include <avr/io.h>
    #include <avr/interrupt.h>
    #include <util/delay.h>
    
    unsigned int ontime = 0;
    unsigned int offtime = 2000;
    
    ISR(TIMER0_COMP_vect)
    {
        offtime--;
    
        if( offtime == 0 )
        {
            offtime = 2000;
            PORTA &= ~0x80;
        }
        if(offtime == ontime )
        {
            PORTA |= 0x80;
        }    
    }
    
    int main(void)
    {
    
        DDRC = 0xFF;
        PORTC = 0x0F;   // alles aus
    
        DDRA = 0x80;
        PORTA = 0x00;
    
        // CLK/8 Prescaler                CS01
        TCCR0 = (1<<CS01);
    
    
        OCR0 = 20;  // 16000000/8 = 1999490Hz/20 = 99974,50Hz => 0,01ms
    
        TIMSK |= (1<<OCIE0);
    
        sei();
    
        int i = 0;
    
        ontime = 100;
    
        for(i=0;i<25;i++)
            _delay_ms( 200 );
    
        ontime = 125;
    
        for(i=0;i<25;i++)
            _delay_ms( 200 );
    
        ontime = 150;
    
        for(i=0;i<25;i++)
            _delay_ms( 200 );
    
        ontime = 175;
    
        for(i=0;i<25;i++)
            _delay_ms( 200 );
    
        ontime = 200;
    
        for(i=0;i<25;i++)
            _delay_ms( 200 );
    
        ontime = 0;
    
        while(1){  }
    }
    Ich benutze den Billig-Servo von Conrad (Basetech ES-05). Sollte ich das mit den Timern richtig verstanden haben, so müsste doch die Interrupt-Routine alle 0.01ms aufgerufen werden. Sprich 20ms = 2000 Aufrufe. Damit wäre ein ontime von 100 = 1ms usw.?
    Auch die _delay_ms-Funktion sollte bei 25*200ms = 5000ms = 5 Sekunden warten, was sie auch nicht tut (F_CPU ist über AVR Studio mit 16000000 für ATmega32 gesetzt ).

    Inzwischen glaube ich, dieses Mikrocontroller-Zeug ist von bösen Zauberern erfunden worden und nur Magiekundigen zugänglich, die ihre Seele bereits dem Satan verkauft haben und durch Zölibat und Selbstgeisselung die schwarze Kunst der Elektronenbeeinflussung beherrschen.

    Grütze

    Banzai

  4. #4
    Erfahrener Benutzer Robotik Visionär Avatar von Hubert.G
    Registriert seit
    14.10.2006
    Ort
    Pasching OÖ
    Beiträge
    6.220
    @Banzai
    Wenn ich die avr-libc richtig gelesen habe dann wäre dein _delay_ms( 200 ) nur bei 1MHz Takt 200msek, bei 16MHz nur 1/16 .

  5. #5
    Erfahrener Benutzer Roboter-Spezialist
    Registriert seit
    04.01.2004
    Beiträge
    317
    @Banzai:

    Ich möchte allerdings kein Servo ansteuern (jedenfalls noch nicht) sondern das Signal vom Empfänger auswerten (also im Prinziep die Impulslänge messen und dann vergleichen)
    mfG Henry

  6. #6
    Erfahrener Benutzer Robotik Visionär Avatar von Hubert.G
    Registriert seit
    14.10.2006
    Ort
    Pasching OÖ
    Beiträge
    6.220
    @Henry
    Das Signal vom Empfänger auf den INT0 oder INT1 Eingang legen, bei der steigenden oder fallenden Flanke den Timer starten, bei der nächsten Flanke den Timer stoppen, auslesen, neustarten usw. Wenn du den Timer so einstelllst das die max-Zeit bis zum Überlauf etwas mehr als die max. Impulszeit ist kannst du mit dem Overflow auch gleich die Pause auswerten.

  7. #7
    Benutzer Stammmitglied
    Registriert seit
    05.03.2005
    Beiträge
    36
    Hallo Leutz,

    ich habe meinen Servo soweit, dass er sich entsprechend seiner Funktion verhält.
    Warum weiss ich allerdings nicht.

    Code:
    #include <avr/io.h>
    #include <avr/interrupt.h>
    #include <util/delay.h>
    
    int ontime = 0;
    int offtime = 2000;
    
    ISR(TIMER0_COMP_vect)
    {
        static int onBuf;
    
        if( offtime - ontime > 0 )
        {
            onBuf = ontime;
            offtime--;
        }
        else
        {
            if( onBuf == 0 )
            {
                offtime = 8000;
                PORTA &= ~0x80;
                onBuf = ontime;
            }
            else
            {
                if( onBuf == ontime )
                    PORTA |= 0x80;
                onBuf--;
            }
        }   
    }
    
    int main(void)
    {
    
        DDRA = 0x80;
        PORTA = 0x00;
    
        // CLK/8 Prescaler                  CS01
        TCCR0 = (1<<CS01);
    
        OCR0 = 20;  // 16000000/8 = 1999490/20 = 99974,50Hz => 0,01ms
    
        TIMSK |= (1<<OCIE0);
    
        sei();
    
        int i = 0;
    
        ontime = 3; // links
    
        for(i=0;i<312;i++)
            _delay_ms( 16 );
    
        ontime = 11; // mitte
    
        for(i=0;i<312;i++)
            _delay_ms( 16 );
    
        ontime = 19; // rechts
    
        for(i=0;i<312;i++)
            _delay_ms( 16 );
    
        ontime = 0;
    
        while(1);
    }
    Kann mir einer meinen Code erklären (klingt lächerlich, ich weiss)?

    Warum müsste lt. Theorie die Interrupt-Routine alle 0.01ms aufgerufen werden oder täusche ich mich da?
    @Hubert G.: Du hattest recht, auch wenn diese minimalistische Bemerkung, das hätte was mit 1MHz zu tun, in der avr-Libc-Doku irgendwie missverständlich für eine _delay_ms-Funktion ist.
    Warum veranlasst ein ontime=4 die linke Position, wenn das theoretisch niemals 1ms sein kann?
    Warum diese komischen anderen Werte für Mitte/Links?
    Ich benutze kein PWM, generiere ich da unwissentlich ein Software-PWM?
    Bewegt sich ein Servo immer in so ruckartigen Bewegungen, oder gibt es eine Möglichkeit von einer zur nächsten Position kontinuierlich zu kommen?

    thx4Help

    Banzai

  8. #8
    1) k.a. was du da für einen Servo hast, aber es sind echt 30us Links voll und 200us Rechts voll.
    2) Warum stellst du die Offtime in der Interruptroutine plötzlich auf 8000? war nicht 2000 geplant? (beim Programmstart stellst dus auf 2000)
    2) Du generierst eine SoftwarePWM.
    3) Du kannst die Servos langsamer drehen lassen. Einfach die Position langsam verändern. die Dinger sollen im Modellbau ja SCHNELL ihre Pos. ändern können, das passt schon so.

    Ich geb mal dem Servo die schuld an seinem l(i/u)stigem verhalten. hast du ein Oszi oder ein messgerät mit Oszifunktion? Dann kannst dir ja die Signale anzeigen lassen, die der Servo wirklich kriegt.

  9. #9
    Benutzer Stammmitglied
    Registriert seit
    05.03.2005
    Beiträge
    36
    @der Gärtner:
    1.) Hoch lebe die Definition, nieder mit der Regel!
    2.) Ein Fehler meinerseits. Die 8000 resultierten noch aus einem Versuch mit einem Zähler von 5 statt 20 (also 0.0025ms/Interrupt). Sollte schon 2000 heissen.
    2(3).) Ui, dann kann ich sowas, ohne zu wissen dass es ich kann )
    3(4).) Langsamer => längere Pausen zwischen den Werte-wechseln, oder?

    Nein, leider bin ich nicht in Besitz von Oszi (weder real, noch über Bekannte oder Arbeit), obwohl sowas gerade in der Anfangszeit bestimmt nützlich wäre.

    Und was das l(i/u)stige Verhalten angeht, würde ich fast behaupten, dass ist sogar hinter* und un* :-|

    thx4Hints

    Banzai

Berechtigungen

  • Neue Themen erstellen: Nein
  • Themen beantworten: Nein
  • Anhänge hochladen: Nein
  • Beiträge bearbeiten: Nein
  •  

12V Akku bauen