Electrical – How to achieve positional servo control with an Atmega328P

atmegaatmega328pservo

I am trying to drive my SG90 servo using the timers on the Atmega329P using phase correct PWM. I have set up my motor well enough that it rotates, but I cannot get it to stop – the servo motor just continues rotating.

Here's my current code:
servo.c

#define F_CPU 16000000L

#include <avr/io.h>
#include <util/delay.h>
#include <avr/interrupt.h>
#include "servocontrol.h"

#define TOP 500 // 1000*(64/16000000)

void servo_delay() {
   _delay_ms(1500);

}


void setup_servos() {
   DDRD = (1 << DDD5) | (1 << DDD6);
   TCCR0A |= (1 << COM0A1) | (1 << COM0A0) | (1 << WGM00) | (1 << COM0B1);
   TCCR0B |= (1 << CS00) | (1 << CS01);
   OCR0A = 0x00;

}

void move_servos() {
   for (int i = 100; i < TOP; i++) {
      OCR0A = i;
      servo_delay();
      if (OCR0A == 300) {
          PORTD &= ~ (1 << PD5);
        }

    }
}

servocontrol.h

#ifndef SERVOCONTROL_H
#define SERVOCONTROL_H

void servo_delay();

void setup_servos();

void move_servos();

#endif

main.c

#define F_CPU 16000000L

#include <avr/io.h>
#include "servocontrol.h"

int main() {
    setup_servos();
    move_servos();
}

I'm trying to use timer0 in phase correct non-inverting mode, but I exprecienced the same problem when I used timer1.
How do I get the servo to stop at the location I want? I feel like there is a part of the PWM process that I am currently missing, but I cannot seem to figure it out. I will greatly appreciate any help.

Best Answer

At 16 Mhz and with 1/64 clock source you have 250 kHz TC frequency. You set TOP to FF (WGM00), so your PWM period is 2 ms. Normal hobby servos need period about 20 ms (50 Hz).

You can try 1/1024 clock for 32 ms period (at TOP = FF). Then OCR0A between 8 and 16 will give you 1 to 2 ms pulse width, for 8 positions of servo resolution.

You can use Fast PWM mode for 16 ms period. Then OCR0A between 16 and 32 will give you same 1 to 2 ms pulse width, for 16 positions of servo resolution.

Or you can use Timer1 with OCR1A as TOP for precise period control and OCR1B as duty cycle with much better resolution.

Related Topic