Electronic – ATtiny85 Servo PWM angle granularity

attinyavrpwmservotimer

I am currently working on controlling servo motors with an ATtiny85.
I have a hard time understanding how to achieve a fine granularity for the angles of the servo.

I am using a similar technique as the one stated by KyranF.

A servo angle is determined by the pulse width between 1-2ms of an 50Hz PWM.

I am using Timer 1 with a prescaler of 1 with a 8 Mhz clock. This means a timer overflow(tick) takes (1/8MHz) * 256 = 32 microseconds.

A 20ms period takes 625 overflows. This means my 1ms granularity is 625/20ms = 31,25 = ~31 ticks per ms.

Because a servo angle is controlled by setting the pulse width somewhere between 1-2ms, I can only have a precision of 31/180°= ~6 degrees.

Is there a way to achieve 1° precision ?

Best Answer

Because a servo angle is controlled by setting the pulse width somewhere between 1-2ms, I can only have a precision of 31/180°= ~6 degrees.

Is there a way to achieve 1° precision ?

Most servos only move ~120º with 1-2ms. However assuming 1-2ms = 180º you need 180 counts of 5.55us per count.

The Attiny85 has an 8 bit PWM generator that can do up to 256 counts, but doesn't have a prescaler division ratio that can do 5.55us steps at 8MHz. The nearest is 8us per count with a 1/64 prescale, which corresponds to 125 counts in 1ms for a resolution of 1.44º per count (if 1ms = 180º). To get this you could set up Timer0 to produce a one-shot PWM pulse of 125-250 which equals 1-2ms, and use timer1 to repeat the pulse at approximately 20ms intervals. Most servos should get close to 1º resolution with these 8us steps.

If 8us is not fine enough then you will have to use a software delay. At 8Mhz 44 CPU cycles take 5.5us, which is 99% of the desired 5.55us and provides enough instructions to make an accurate variable timing loop of 1-2ms. You could try writing the code for this in C (with a few NOPs to adjust the timing) but it might be easier to do in assembler.

To generate an entire frame you would first set up a timer to interrupt at ~20ms intervals. In the timer ISR you would start the servo pulse, wait for a variable 1-2ms using your software timer, then end the servo pulse. During this time the CPU can't do anything else, but you still have ~18-19ms available per 20ms frame.