Voting resources, early voting, and poll worker information - VOTE. ... Adafruit is open and shipping.
0

Help with Atmega168 servo steering needed
Moderators: adafruit_support_bill, adafruit

Please be positive and constructive with your questions and comments.

Help with Atmega168 servo steering needed

by TriKri on Sun May 16, 2010 3:33 am

Hi! We are programming a robot in a school project, namely a Johnny 5. For the servo steering, one atmega168 is used, for steering 12 servos in total (pins 16 and 19 - 29, two of the servos has been removed), connected to pins belonging to two shift/storage registers (# 2 and 3). I have written test code and programmed it with, and I think that I should get some reactions from the arms, but nope, nothing happens. Anyway, here is the code that I've written to test it:

main.c:
Code: Select all | TOGGLE FULL SIZE
/*** Includes ***************************************************************/
/* External library headers */
#include <avr/interrupt.h>
#include <avr/io.h>
 
/* Project headers */
#include "servos/servos.h"
 
/*** Main function **********************************************************/
int main(void)
{
    /* Init pin values */
    init_system();
    /* enable interrupts */
    sei();

    while (1) /* prevent process from from terminating */
    {
        DDRD = 0xff; /* disable the compiler to optimize the loop away */
    }
 
    return 1;
}


servos/servos.h:
Code: Select all | TOGGLE FULL SIZE
#ifndef SERVOS_H
#define SERVOS_H

#include "common.h"

void
init_system(void);

#endif


servos/servos.c:
Code: Select all | TOGGLE FULL SIZE

/****************************************************************************
 * INCLUDE FILES                                                            *
 ****************************************************************************/

#include <stdint.h>

#include <avr/interrupt.h>
#include <avr/io.h>

#include "servos.h"
void
init_system(void)
{
    DDRD = 255;
    /* Use wavegeneration mode 12 and clock select 4 (prescaler = 256) */
    TCCR1A = 0;
    TCCR1B = _BV(WGM13)|_BV(WGM12)|_BV(CS12);
    /* Prescaler = 256, processor speed = 14745600 Hz, Timer frequency = 57600 Hz */
    ICR1 = 89; /* Counter max value ~ 1.55 ms */
    TIMSK1 = _BV(ICIE1); /* Enable input capture interrupt */
}

inline static void
test_func_servos(void)
{
    static uint8_t i = 0;
    /* i will count from 0 to 12 and then back to 0 again*/
    i++;
    if (i == 13)
    {
        i = 0;

        /* Set signals to servos high until next interrupt (should be in approx. 1.55 ms) */
        SPDR = 255; /* Sending to shift registers will start automatically when writing to this register... */
        /* Wait for transmission complete */
        while (!(SPSR & _BV(SPIF)) ) ;

        /* Clock out the content of the shift register, use BANK2-RCK as clock signal */
        PORTD |=  _BV(PD6);
        PORTD &= ~_BV(PD6);

        SPDR = 255;
        /* Wait for transmission complete */
        while (!(SPSR & _BV(SPIF)) ) ;

        /* Clock out the content of the shift register, use BANK3-RCK as clock signal */
        PORTD |=  _BV(PD7);
        /* __no_operation(); */
        PORTD &= ~_BV(PD7);
    }
    else
    {
        /* Set signals to servos low in the next 12 interrupts (should take 12 * 1.55 ~ 18,6 ms ) */
        SPDR = 0;
        /* Wait for transmission complete */
        while (!(SPSR & _BV(SPIF)) ) ;

        /* Clock out the content of the shift register, use BANK2-RCK as clock signal */
        PORTD |=  _BV(PD6);
        PORTD &= ~_BV(PD6);

        SPDR = 0;
        /* Wait for transmission complete */
        while (!(SPSR & _BV(SPIF)) ) ;

        /* Clock out the content of the shift register, use BANK3-RCK as clock signal */
        PORTD |=  _BV(PD7);
        /* __no_operation(); */
        PORTD &= ~_BV(PD7);
    }
}

/* Callback function to be called every time timer 1 reaches its top value and starts over again. */
ISR(TIMER1_CAPT_vect)
{
    test_func_servos();
}


Using this test program, I should have set up a timer which counts with 57600 Hz, and with a top value at 89, it should take only about 1.55 ms for the timer to loop, and about 20.1 ms for the timer to perform 13 loops. In my function test_func_servos that should be called every time the timer reaches it's top value and an interrupt occurs, the static variable i counts from 0 to twelve and then starts over again, getting a loop time at (1 + 12) * 1.55 ms ~ 20.1 ms, and a pulse at 1.55 ms should be sent to every servo once every 20.1 ms, which means that they all should set to their middle positions. However, nothing happens, and I have no idea of what is wrong. Coed anyone know why it is not working? Have I forgot to set some flag in some register or set some register incorrectly? Thanks in advance! :)
Last edited by TriKri on Sun Apr 10, 2011 4:46 pm, edited 1 time in total.
TriKri
 
Posts: 1
Joined: Sun May 16, 2010 1:59 am

Re: Help with Atmega168 servo steering needed

by adafruit_support_bill on Sun May 16, 2010 5:37 am

Have you put a scope on the output signal(s) to see what you are getting?

adafruit_support_bill
 
Posts: 78759
Joined: Sat Feb 07, 2009 10:11 am

Please be positive and constructive with your questions and comments.