1. Welcome to our site! Electro Tech is an online community (with over 170,000 members) who enjoy talking about and building electronic circuits, projects and gadgets. To participate you need to register. Registration is free. Click here to register now.
    Dismiss Notice

PWM for servo control

Discussion in 'AVR' started by magvitron, Mar 1, 2013.

  1. magvitron

    magvitron Active Member

    Joined:
    Jan 11, 2013
    Messages:
    256
    Likes:
    28
    Location:
    John Lennon !magine land.
    i tested with the below code but the servo is not responding. :(
    Code (text):
    #include <avr/io.h>
    #include<avr/interrupt.h>
    #include<util/delay.h>

     
    // Volatile keyword is important
    volatile char count=0;
     unsigned int degrees;
    // We use this ISR to leave only every sixth pulse and remove the rest.
    // This reduces the PWM frequency to ~56Hz.
    ISR(TIMER2_COMP_vect) {
        if (count){ // Disconnect the OC2 to reduce pulse rate
            TCCR2 &= ~(1<<COM21);
            count--;
        }
        else { // Connect the OC2 (PD7) for this pulse
            TCCR2 |= (1<<COM21);
            count=6;
        }
    }
     
    int main(void) {
        DDRD|=(1<<PD7); // selcet OC0 as output pin
        // Fast PWM, TOP = 255, Prescale = 128, F_CPU = 11.0592Mhz
        TCCR2 |= (0<<FOC2)|(1<<WGM20)|(1<<WGM21)|(0<<COM20)|(1<<COM21)|(1<<CS20)|(0<<CS21)|(1<<CS22);
        // This gives you ~1ms pulse. (86.4 is accurate value).
        OCR2=0;
     
        // Setup interrupt so we can remove pulses from the pulse train
        TIMSK |= OCIE2;
        sei();
     
            while(1)
            {
                _delay_ms(1000);
                OCR2 = 65 + ((130 * degrees) / 180);
                degrees=degrees+1;
                if(degrees==180)
                degrees =0;
            }
    }
     
     
    Last edited: Mar 6, 2013
  2. misterT

    misterT Well-Known Member Most Helpful Member

    Joined:
    Apr 19, 2010
    Messages:
    2,697
    Likes:
    368
    Location:
    Finland
    You need to define the cpu frequency for the _delay_ms();
    I'm not sure if AVR studio does this for you. Try adding this before the library inclusion.

    #define F_CPU 11059200UL
    #include<util/delay.h>

    Also, you need to turn on optimization for the compiler.
     
    • Like Like x 1
  3. misterT

    misterT Well-Known Member Most Helpful Member

    Joined:
    Apr 19, 2010
    Messages:
    2,697
    Likes:
    368
    Location:
    Finland
    With one second delay and one degree increment it takes 3 minutes for the servo to turn 180 degrees :). That is difficult to observe.

    Try:
    degrees=degrees+30;
    if(degrees>180)
    degrees =0;
     
    • Like Like x 1
  4. dave

    Dave New Member

    Joined:
    Jan 12, 1997
    Messages:
    -
    Likes:
    0


     
  5. magvitron

    magvitron Active Member

    Joined:
    Jan 11, 2013
    Messages:
    256
    Likes:
    28
    Location:
    John Lennon !magine land.

    Its alivee!! :D thanks a lot for this.. :) and one more question, is this same for PWM with timer/counter module 0 too? if you say, its faster than me going through datasheet.. so...!
     
  6. misterT

    misterT Well-Known Member Most Helpful Member

    Joined:
    Apr 19, 2010
    Messages:
    2,697
    Likes:
    368
    Location:
    Finland
    Otherwise it would be, but as it turned out there is no prescaler of 128 for timer/counter0, so all the calculations need to be done for different prescaler.. and the resolution will be much worse (half, actually).

    Take a look at my post #4. Those settings are for timer/counter0. Only the interrupt is missing from that code.


    EDIT: Here is similar code for Timer0

    Code (text):

    #include <avr/io.h>
    #include<avr/interrupt.h>

    // Volatile keyword is important
    volatile char count=0;

    // We use this ISR to leave only every third pulse and remove the rest.
    // This reduces the PWM frequency to ~56Hz.
    ISR(TIMER0_COMP_vect) {
        if (count){ // Disconnect the OC0 to reduce pulse rate
            TCCR0 &= ~(1<<COM01);
            count--;
        }
        else { // Connect the OC0 (PB3) for this pulse
            TCCR0 |= (1<<COM01);
            count=3;
        }
    }

    int main(void) {
        DDRB|=(1<<PB3); // selcet OC0 as output pin
        // Fast PWM, TOP = 255, Prescale = 256, F_CPU = 11.0592Mhz
        TCCR0 |= (0<<FOC0)|(1<<WGM00)|(1<<WGM01)|(0<<COM00)|(1<<COM01)|(0<<CS00)|(0<<CS01)|(1<<CS02);
        // This gives you ~1ms pulse. (43.2 is accurate value).
        OCR0=43;
       
        // Setup interrupt so we can remove pulses from the pulse train
        TIMSK |= OCIE0;
        sei();
       
            while(1) {
             
            }
    }
     

    The formula would be:

    OCR0 = 33 + ((64 * degrees) / 180);
     
    Last edited: Mar 6, 2013

Share This Page