Projects for geeks


11 Aug 2009

The angle of the servo is determined by the duration of a pulse that is applied to the control wire. Typical hobby servo expects pulse every 0.02s, in other words it is controlled by the 50 Hz PWM signal (1/0.02s=50Hz).

To turn motor to neutral position (90°) pulse width must be 1.5ms. If the pulse is shorter than 1.5ms, the motor will turn to 0°, for longer than 1.5ms motor turns closer to 180°. Using PWM terminology, 7.5% (1.5ms) duty cycle turns servo shaft to 90°, 6.25% (1.25ms) to 0° and 8.75% (1.75ms) to 180°.

Note that physical limits and timings of the servo hardware varies between brands and models. For example you can buy servo with 1ms pulse for 0° and 2ms for 180°.

We use timer1 to control servo and the best mode to control servo for this timer is Phase/Frequency Correct PWM mode. This mode is useful because you can adjust frequency and phase and frequency is correct. In fact any other mode that allows to fine tune frequency to 50Hz can be used.

First timer1 must be configured for 50Hz wave. Frequency is equal:

TOP is this case is the value to be written to ICR1 register. It directly affects frequency.

Our goal is to have 50Hz signal. Playing a bit with spreadsheet we discover that the following parameters give 50Hz wave for 8 MHz system clock:

Prescaler TOP value Frequency
1 80,000 50 Hz
8 10,000 50 Hz
64 1250 50 Hz
256 312.5 50 Hz
1024 78.125 50 Hz

At first glance 80,000 can be ignored because it is bigger then maximum 16 bit integer 216-1=65535 (timer1 is 16 bit). 312.5 and 78.125 are not integer numbers, we could use 312 and 78 but resulting wave is 50.8Hz not our perfect 50Hz.

Two numbers left: 10,000 and 1250. We use 10,000 because resolution is better; general rule is to use as big number as you can. To prove that, we can compute bit resolution based on equation from ATmega32 specification:

TOP value Resolution in bits
10000 13.29
1250 10.29

It is obvious that 13 bit resolution is better then 10 bits.

Finally prescaler divider 8 and TOP value 10000 is chosen. We know how to setup 50Hz wave, but how to generate pulses from 1.25ms to 1.75ms?

OCRx register is responsible for pulse width. If OCRx is 10000, pulse width is equal to period 20ms, so conversion factor from milliseconds to OCRx is 10000/20ms = 500.

To generate 1.5ms pulse value 750 (500×1.5) have to be written to OCRx; for 1.25ms 625 (500×1.25); for 1.75ms 875 (500×1.75). In general, to turn servo shaft from 0° to 180°, values from 625 to 875 have to be used.

As mentioned earlier, timings may vary between servo models, so it is good to experiment a bit to get satisfying results.

Other timers

ATmega16 and ATmega32 has two more timers: timer0 and timer2. Both can generate PWM wave, but in practice they are less useful for servo control.

These timers have only 3 PWM modes. In CTC mode it is possible to configure precise 50Hz frequency, but it is not possible to change duty cycle. In Fast PWM and Phase Correct modes, frequency depends only on prescaler divider, which gives 5 (timer0) or 6 (timer2) possible frequencies.

Fast PWM frequency is PWM=F/(N*256), for Phase Correct mode it is PWM=F(N*510). Using all available prescalers it is not possible to configure 50Hz for 8MHz system clock. The only possibility to get 50Hz is to use different frequency then 8MHz. For Fast PWM mode crystal 13,107,200Hz and prescaler divider 1024 gives 50Hz, for Phase Correct it is 6,528,000Hz and prescaler divider 256. These are rather odd values.

Lets assume usage of 6.528MHz crystal. In Phase Correct mode and 256 prescaler divider it gives us 50Hz. Now, we must compute OCRx values to be used to generate pulses from 1.25ms to 1.75ms.
Maximum OCRx value is 255 (timer0 and timer2 are 8 bit), for 50Hz period is 20ms, so conversion factor is 255/20=12.75. To generate 1.25ms pulse OCRx=1.25×12.75=15.9, for 1.75ms pulse OCRx=1.75×12.75=22.3125. Of course nearest integer values must be used. To control servo shaft from 0° to 180° values from 16 to 22 have to be written to OCRx register.

The range [16,22] offers only 7 possible numbers to use! If we want to control rotation from 0° to 180° that gives us 180°/7=25.7° accuracy. The smallest angle you can rotate servo is 25°. It may not be sufficient for all applications.
This is the reason why most of the software use 16 bit timers to control servos.

How to connect servo

A typical hobby servo has 3 wires:

  • GND
  • +5V
  • signal

Signal wire must be connected to OC1B pin (PWM wave). You can not swap GND and +5V. Here is the color code for the most popular types of connectors:

Wire Futaba Hitec
GND Black Black
+5V Red Red
signal White Yellow

For more information look at Servos Wiring Diagrams

Code snippets

Here are the code snippets for timer1. It’s assumed servo control line is connected to OC1B pin, 8MHz system clock is used.

Output on OC1B pin.

DDRD |= _BV(DDD4); //OC1B as output

Setup 50Hz

ICR1 = 10000;

Non inverted mode

TCCR1A |= _BV(COM1B1);  // Clear OC1A/OC1B on compare match

Phase/Frequency Correct PWM mode for timer1 and prescaler divider 8.
This begins generating PWM wave.

TCCR1B |= _BV(WGM13) //mode 8, PWM, Phase and Frequency Correct (TOP value is ICR1)
       |  _BV(CS11); // Prescaler 8

Move servo shaft to neutral position

OCR1B = 750;

Sample project

Chip ATmega32
System clock 8MHz
Compiler AVR Studio + GCC
AVR hardware timer1
External hardware hobby servo

The sample application moves servo to 3 positions: 0°, 90° and 180°.
If your servo do not reach minimum and maximum limits try to adjust MinOCR and MaxOCR values in InitPWM() function.

Package icon pwm_servo.zip3.13 KB