PWM for servo control

Status
Not open for further replies.
i tested with the below code but the servo is not responding.
Code:
#include <avr/io.h> 
#include<avr/interrupt.h>
#include<util/delay.h>

 
// Volatile keyword is important
volatile char count=0;
 unsigned int degrees;
// We use this ISR to leave only every sixth pulse and remove the rest.
// This reduces the PWM frequency to ~56Hz.
ISR(TIMER2_COMP_vect) {
	if (count){ // Disconnect the OC2 to reduce pulse rate
		TCCR2 &= ~(1<<COM21);
		count--;
	}
	else { // Connect the OC2 (PD7) for this pulse
		TCCR2 |= (1<<COM21);
		count=6;
	}
}
 
int main(void) { 
	DDRD|=(1<<PD7); // selcet OC0 as output pin
	// Fast PWM, TOP = 255, Prescale = 128, F_CPU = 11.0592Mhz
	TCCR2 |= (0<<FOC2)|(1<<WGM20)|(1<<WGM21)|(0<<COM20)|(1<<COM21)|(1<<CS20)|(0<<CS21)|(1<<CS22);
	// This gives you ~1ms pulse. (86.4 is accurate value).
	OCR2=0;
 
	// Setup interrupt so we can remove pulses from the pulse train
	TIMSK |= OCIE2;
	sei();
 
		while(1) 
		{ 
		    _delay_ms(1000);
			OCR2 = 65 + ((130 * degrees) / 180);
			degrees=degrees+1;
			if(degrees==180)
			degrees =0;
		} 
}
 
Last edited:
You need to define the cpu frequency for the _delay_ms();
I'm not sure if AVR studio does this for you. Try adding this before the library inclusion.

#define F_CPU 11059200UL
#include<util/delay.h>

Also, you need to turn on optimization for the compiler.
 
With one second delay and one degree increment it takes 3 minutes for the servo to turn 180 degrees . That is difficult to observe.

Try:
degrees=degrees+30;
if(degrees>180)
degrees =0;
 
Its alivee!! thanks a lot for this.. and one more question, is this same for PWM with timer/counter module 0 too? if you say, its faster than me going through datasheet.. so...!
 
is this same for PWM with timer/counter module 0 too?

Otherwise it would be, but as it turned out there is no prescaler of 128 for timer/counter0, so all the calculations need to be done for different prescaler.. and the resolution will be much worse (half, actually).

Take a look at my post #4. Those settings are for timer/counter0. Only the interrupt is missing from that code.


EDIT: Here is similar code for Timer0

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

// Volatile keyword is important
volatile char count=0;

// We use this ISR to leave only every third pulse and remove the rest.
// This reduces the PWM frequency to ~56Hz.
ISR(TIMER0_COMP_vect) {
	if (count){ // Disconnect the OC0 to reduce pulse rate
		TCCR0 &= ~(1<<COM01);
		count--;
	}
	else { // Connect the OC0 (PB3) for this pulse
		TCCR0 |= (1<<COM01);
		count=3;
	}
}

int main(void) { 
	DDRB|=(1<<PB3); // selcet OC0 as output pin
	// Fast PWM, TOP = 255, Prescale = 256, F_CPU = 11.0592Mhz
	TCCR0 |= (0<<FOC0)|(1<<WGM00)|(1<<WGM01)|(0<<COM00)|(1<<COM01)|(0<<CS00)|(0<<CS01)|(1<<CS02);
	// This gives you ~1ms pulse. (43.2 is accurate value).
	OCR0=43;
	
	// Setup interrupt so we can remove pulses from the pulse train
	TIMSK |= OCIE0;
	sei();
	
		while(1) { 
		 
		} 
}


The formula would be:

OCR0 = 33 + ((64 * degrees) / 180);
 
Last edited:
Status
Not open for further replies.
Cookies are required to use this site. You must accept them to continue using the site. Learn more…