How can I control several servo motors using 2 timers in an ATmega16? I have searched for "servo bit banging" but no coherent post explains it fully. I found some code but I don't thoroughly understand it.

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

    volatile u8 X, lowCount, highCount, arrCount = 0;
    u8 array[180]={0};

void main( void)
    DDRD = 0xff;
    PORTD = 0b11111111;
    //DDRA = 0xff;
    // Set no prescaler for both t- and t2
    TCCR0 = (0<<CS02) |(0<<CS01) | (1<<CS00) ;
    TCCR2 = (0<<CS22) |(0<<CS21) | (1<<CS20) ;

    // for the first time only let the interrupts start
    TCNT0 = 0xd4;
    TCNT2 = 0xf4;


    // Enable Global Interrrupt



    TCNT2 = 0xd4;

        X = 0xff;
    else if( arrCount<180)
        X = array[arrCount];
    else if(lowCount< 1591)
        X = 0;
        X, lowCount, highCount, arrCount = 0;
    //PORTA ^=0b10000000;


    TCNT0 = 0xd4;
    PORTD = X;
    //PORTA ^=0b00000001;

Any link or explanation would be great.

  • \$\begingroup\$ Download and install the Arduino IDE. It has a servo library that works quite well, and the source code is installed when you install the Arduino IDE. It might be easier to understand, and you could ask for help on the Arduino forum, or the Arduino stack exchange. \$\endgroup\$ – gbulmer Dec 19 '15 at 17:09
  • \$\begingroup\$ Where did you find this code? What is it supposed to do? \$\endgroup\$ – Bruce Abbott Dec 19 '15 at 17:28
  • \$\begingroup\$ @bruce It is supposed to control 8 servos on portd according to the data in the array X. I can't get whats the second ISR is for, why can't I just assign PORTD=X; at the end of the first ISR. \$\endgroup\$ – Aelgawad Dec 19 '15 at 18:06
  • \$\begingroup\$ I don't either, perhaps to get more accurate timing? You should be able to put the X assignment right after 'TCNT2 = 0xd4;' in the first isr, and delete the second isr. This code also appears to have several errors ("std_typed.h"? lowcount should be an int, attempting make multiple variables = 0 by putting commas between them), and I don't understand how the 180 array elements translate to 8 servo pulses. \$\endgroup\$ – Bruce Abbott Dec 19 '15 at 18:23
  • \$\begingroup\$ But regardless of this code, there has to be a standard or a conventional way to do it. \$\endgroup\$ – Aelgawad Dec 19 '15 at 19:56

The high time used to command a hobby type servo motor is around 500us to 1500us. The period is 20mS.

Lets say you have 3 servoes connected to digital outputs I'll call S1,S2,S3. You want the servo on time to be 0.8ms 1.2ms, 1.0mS.

Code will need to do the following: 0) At the start of each 20mS period: 1) Assert S1 signal high and wait for 0.8mS. (Using a timer, or sleep, delay etc) 2) 0.8mS has elapsed, negate S1, and assert S2. Wait 1.2mS. 3) Negate S2, assert S3 - Wait 1 mS. 4) Negate S3. Wait the remainer of the 20mS. (17mS)

If there are other ISRs operating on the machine, then the waits might no be accurate and you'll get some jitter.

A better way to implment this is in an ISR where on entry the signal assertion / negation is done - and the timer configured to generate the next ISR after the desired time.

The best way (zero jitter), if you have the hardware support is to use output compares. Assuming the OCs have a high if less than compare mode then:

1) Program the 3 OCs compare values with the desired duration of each PWM. 2) Config the timer to wrap every 20mS 3) Enabled the OCs and start the timer.
4) When TCNT is < the OC comparea value the output of each PWM will be high, and automatically go low when TCNT == the OC compare.

| improve this answer | |

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.