Atmega8 servo interface

Go To Last Post
7 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I have researched the forum but have had no luck I am new to Microcontrollers and cant seem to get the servo to move. If I am making a basic mistake I apologize in advance. Any help would be greatly appreciated!

#include
#include 
#define MCU_FREQ 1000000UL

int main(void)
{
DDRB=(1<<PB1);//set OC1A as output pin
TCCR1A = 0;
TCCR1B =(1<<WGM13) | (1<<CS10);//set counter1 to mode 8,phase
// and frequency correct PWM,ICR1 equals top with no prescaler
ICR1 = 10000;//set ICR1 to produce 50Hz frequency
//(MCU_FREQ = 1000000/(2 x n=1 x 10000)) = 50Hz //n=prescaler
//OCR1A = 1300;set value between 1000 and 2000 
//(1 and 2ms) to move servo
	
while (1)
   {
    PORTB |=(1<<PB1);//Enable OC1A pin for PWM output
   for (OCR1A = 1300; OCR1A != 2000; OCR1A++);
  _delay_ms(400);//simple code to display movement
      
   }
}

Incidentally, some good resources for learning more are about PWM are here:
http://www.triindia.co.in/resour...
http://mil.ufl.edu/~achamber/ser...
http://www.arduino.cc/playground...
http://instruct1.cit.cornell.edu...
http://www.barello.net/Papers/RC...

Lachlan

What we need to learn,
we learn by doing.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

does this work? I know there are restictions of max. delaytime. But i´m not familiar with C.

_delay_ms(400)

also if you wait 400ms every step from 1300 to 2000 it needs, 4 minutes and 40 seconds. Isn´t that very slow?

Klaus
********************************
Look at: www.megausb.de (German)
********************************

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Thanks Klaus,
I tried many other smaller intervals and all I get is a slight movement at power up and thats all. I will keep searching.

Lachlan

What we need to learn,
we learn by doing.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

In the project section of the site, there is a project called "avr 20 servo controller" which you may want to check out.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Check the statement:

TCCR1A = 0;

With all bits cleared, the OC1A/B pins will not be connected, and the PB1 pin works as a normal port pin; ie. no pulses on PB1.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0
    PORTB |=(1<<PB1);//Enable OC1A pin for PWM output 

No, this does not enable anything. It simply sets the pin to 1. Furthermore, since it is in the while loop, it is continually set to 1 even though you have absolutely no code that sets it to 0. As knutbr says, you have to enable the pin for PWM in the TCCR1A register. After that, you need to do nothing more with the pin, the PWM takes care of everything (assuming that the pin is set to output as you have done). All you need to do is set the duty cycle with OCR1A.

   for (OCR1A = 1300; OCR1A != 2000; OCR1A++); 
  _delay_ms(400);//simple code to display movement 

I don't believe that this is what you intended. This will change the value of OCR1A from 1300 to 2000 as rapidly as it can, and then wait 400ms. I believe you wanted:

   for (OCR1A = 1300; OCR1A != 2000; OCR1A++)
   {
      _delay_ms(400);//simple code to display movement 
   }

Also, as MegaUSBFreak said, 400 is beyond the range of the _delay_ms function. The largest value allowable at 1MHz is about 262. Please read the usage note in delay.h.

Regards,
Steve A.

The Board helps those that help themselves.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Thanks to the helpful advice from the above members I was able to fix my initial errors and get the servo sweeping back and forth.

//Program function to interface an ATMEGA8L-8PI
// to a HEXTRONIK HXT900 servo
#include
#include 
#define MCU_FREQ 1000000UL
int main(void)
{
DDRB=(1<<PB1);//set OC1A as output pin
TCCR1A = 0x80;//set OC1A to bottom
TCCR1B =(1<<WGM13) | (1<<CS10);//set counter1 to mode 8,
//phase and frequency correct PWM, 
//ICR1 equals top with no prescaler
ICR1 = 10000;//set ICR1 to produce 50Hz frequency
//(MCU_FREQ = 1000000/(2 x n=1 x 10000)) = 50Hz n=prescaler
OCR1A = 300;//initial value
	

while (1)
   {

//Note: After trial and error, for full range, actual
// servo values are lower than normally used.
   for (OCR1A = 300;OCR1A<=1500;OCR1A++)
   {_delay_ms(1);}
    for (OCR1A = 1501;OCR1A>=301;OCR1A--) 
   {_delay_ms(1);}
	
  
   }
}

//           |
//highvalue |servo|lowvalue


Once again help was greatly appreciated, hope the above code is useful to people trying to do something similar.

Lachlan

What we need to learn,
we learn by doing.