AVR PWM - duty cycle confusion

Discussion in 'The Projects Forum' started by myztic_man, Jan 18, 2010.

  1. myztic_man

    Thread Starter Member

    Apr 27, 2009
    Hi there.
    I am trying to generate PWM to control a Servo from an ATMega128.

    I have read, and re-read the Atmel Datasheet, however I am still a little confused on exactly how I go about adjusting the duty cycle of the wave?

    As the servo (so I have read) runs on 50Hz PWM, and my Oscillator is 8Mhz, I am using a prescaler of 8, then counting to 20,000.

    Fpwm = fclk/(prescaler*(1+TOP))
    Fpwm = 8Mhz/(8*(20000))
    Fpwm = 50hz

    I am using the standard 16-bit counter1 in Fast PWM mode, which is setup to Toggle OC1A on Compare Match. I have done this with the following code:

    void initTimer1(){
    DDRB |= (1<<PORTB1); /* Setup OC1A as output */
    TCCR1A = 0x53; /* (1<<COM1A0) | (1<<WGM11) | (1<<WGM10); -- Toggle OC1A on Compare Match */
    OCR1A = 19999; /* OCR1A is TOP, count to 19,999 + 1 */
    TCCR1B |= (1 << CS10) | (1<<CS11) | (1 << WGM13) | (1<<WGM12); /* Setup Timer1 (16-bit) with prescaler of 8 running from 8Mhz CLK */

    However, this is where I get confused. My device (should) count to OCR1A, then toggle the output of OC1A. If I wanted a Duty cycle of 50%, I would want it to toggle after counting to 10000, however how do I set that?
    Is there some other register I can program that offers another comparison and (hence) another toggle? Or do I have to manually check the count value in the TCNT1 register and perform the task manually?

    Any help would be much appreciated, if you feel I am going about this the wrong way, please let me know, as this is my first expereicnce with the AVR series.
  2. retched

    AAC Fanatic!

    Dec 5, 2009
    Last edited: Jan 18, 2010
  3. hgmjr


    Jan 28, 2005
    See if the material at this link will help you get up higher on the learning curve.

  4. spacewrench


    Oct 5, 2009
    Servo control signals are a little different than (just) PWM. You need to make a pulse whose width is between 1ms and 2ms, and do it every 20ms (approximately). You may be able to do it using the Atmel PWM peripheral (for one or two outputs), but the signal is pretty slow (and pretty intermittent) so if you need more than 2 outputs, it's probably easier to do it in software.

    One project I did had 8 outputs, and I just had an ISR that got triggered every 20ms, which would start 8 pulses, let them sit for 1ms, and then turn outputs off at various times over the next 1ms, depending on where the servo on that channel was supposed to be.

    This wastes 2ms out of every 20ms, but you can improve it to waste only 1ms out of 20 (because all the outputs have to be high for at least 1ms). Or, if you're REALLY pressed for computing cycles, you can set ad hoc interrupts appropriately to turn off each individual output in an ISR.

    When dealing with servos, it's really handy to have an oscilloscope...
  5. Papabravo


    Feb 24, 2006
    Not all servos are of the hobby variety. There are industial servo motors that do not operate that way at all. So maybe the OP could clarify what type of servo he is dealing with.

    Ceratinaly the oscilliscope is a useful tool in many applications.
  6. myztic_man

    Thread Starter Member

    Apr 27, 2009
    I am still to read the links posted by the first two repliers, however I will do this after posting this reply.

    The servo was purchased from Sparkfun:

    I assume it is of the 'Hobby' variety - I found it hard to find information on how to control the servo.

    I am only going to be driving a single servo, it's for the rudder of a water device. Are you suggesting to use a timer and interrupt to drive the servo? This would be easy enough to program, but if it's possible I would like to keep the device running on PWM for simplicity - at 50hz a 1-2ms wave would simply be 5%->10% duty cycle.

    spacewrench, do you know how the signal (ie: 1ms) relates to the angle of the servo?
  7. myztic_man

    Thread Starter Member

    Apr 27, 2009
  8. Papabravo


    Feb 24, 2006
    If it is indeed a hooby servo then a 1 ms wide pulse every 20 ms will place the servo at the mid point of its travel. Increasing the puls width to 2 ms will take it in the full CW(CCW) direction while reducing the pulse width to near zero will take it in the other direction.

    This technique may or may not be achievable with the microprocessor's hardware. It may be easier to implement in software. A periodic interrupt with a period of 20 ms would certainly be a place to start. This would turn the output on and arm a second interrupt for the duration of the on pulse. The second interrupt would turn the output off. The process would restart on the next 20 ms interrupt.