NerdKits - electronics education for a digital generation

You are not logged in. [log in]

NEW: Learning electronics? Ask your questions on the new Electronics Questions & Answers site hosted by CircuitLab.

Support Forum » Software PWM

March 30, 2010
by kapkunal
kapkunal's Avatar

Hi, Anybody knows how to set up PINs except OCs to use for servo control? Lets say if I want to control a servo connected to PC1 which is obviously not a PWM pin. I had read on internet, it is called as software PWM. It will be helpful if somebody comes up with the program.

March 31, 2010
by hevans
(NerdKits Staff)

hevans's Avatar

Hi kapkunal,

This actually sounds like a pretty neat learning exercise that I encourage you to try. The basic idea would be to set up timers correctly to time the on and off portions your PWM, and have interrupts set up to fire and simply toggle your output pins in the interrupt handlers. The idea was touched on in this forum thread.

Let us know if you try it. I would love to see it in action.

Humberto

April 03, 2010
by kapkunal
kapkunal's Avatar

Do u mean we should use TOV flag? if we chose 8 bit timer we need to setup interrupts by sei then TIMSK0 = _BV(TOIE0); TCCR0A = (1<<WGM01) | (1<<WGM00); TCCR0B = (1<CS00);

255 top and no prescaling

in this mode TOV0 will be set whenever timer overflows. Is that you implied to me? also we need to set TOV0 to zero either by writing 0 or by using interrupts.

April 04, 2010
by mrobbins
(NerdKits Staff)

mrobbins's Avatar

Hi kapkunal,

You probably don't have to explicitly look at the TOV flag.

Think about Fast PWM mode with 8-bits (top=255): basically, when the counter overflows, the output pin(s) are turned on, and then when the counter equals the OCRnx value, then the pin is turned off.

The chip handles that automatically, but if you want to use arbitrary (non-output-compare pins) for that purpose, you could write two interrupt handlers that do the two functions above:

ISR(TIMER0_OVF_vect) {
  //....
}

ISR(TIMER0_COMPA_vect) {
  //....
}

or something along those lines. There are lots of ways to adapt this kind of idea to controlling servos, depending on complexity, the number of servos that you want to control at once, whether or not you have other processing that you need to do at the same time, etc.

So please think about those kinds of issues, and hopefully you can come up with a way to use the timers to control your servo in a way that's compatible with the rest of your system!

Mike

April 05, 2010
by kapkunal
kapkunal's Avatar

Hey Mike!! thanks a lot I was playing with interrupt handlers and led after getting the information from the link you posted. below is the simple code of making led blink at every 1 milliseconds using interrupts. Let me know if I am on the right track. :D

// led_blink.c
// for NerdKits with ATmega168
// hevans@nerdkits.edu

#define F_CPU 14745600

#include <stdio.h>

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

#include "../libnerdkits/delay.h"
#include "../libnerdkits/lcd.h"

// PIN DEFINITIONS:
//
// PC4 -- LED anode

void initTimer0()

{

  TCCR0A = 0x00;            // Normal timer0 8 bit mode dissabling all the channels

  TIMSK0 |= _BV(TOIE0);     // Enable timer0 overflow mask bit

  TCCR0B = 0x05;            // start timer0 1024 prescaling

}

ISR(TIMER0_OVF_vect)        // timer0 overflow vector

{  
PORTC |= (1<<PC4);

delay_ms(1);

PORTC &= ~(1<<PC4);

}

int main()

{

  DDRC |= (1<<PC4);

  DDRC |= (1<<PC3);

  TCNT0 = 0;            // set the timer to zero

  initTimer0();

  sei();                // enable globle interrupt

  while(1)

{

}

return 0;

}
April 06, 2010
by mrobbins
(NerdKits Staff)

mrobbins's Avatar

Hi kapkunal,

I think you're on the right track! However, I expect your code to turn on PC4 for about 1ms every 17ms (1024*256/14745600). That's not exactly what you described, so I wanted to verify that it is what you intended to do.

A few notes: The delay_ms function is not particularly accurate -- maybe within 2% or so. Additionally, it's not considered good practice to put processing-intensive things inside an interrupt handler (such as the delay_ms(1) call) because it blocks other things from potentially running. Finally, while this may or may not be a problem depending on the final outcome, you have to be careful because the timer is itself still running while the interrupt handler is running.

Another way to go about this: in the ISR(TIMER0_OVF_vect), leave only the turning on of PC4, and remove the delay and PC4-low parts. Then, add a ISR(TIMER0_COMPA_vect) interrupt handler which turns PC4 low. Enable the OCIE0A bit in TIMSK0 to enable that interrupt, and finally, set OCR0A = 14. This may actually be slightly farther from 1ms, but you can extend this concept in some more ways that may or may not be useful to you. Does that help?

Mike

April 11, 2010
by kapkunal
kapkunal's Avatar

Absolutely Mike. You solved my problem. Thanks for all. I tried the program and its working fine.

June 10, 2010
by Ralphxyz
Ralphxyz's Avatar

kapkunal,

Would you post or give a link to your working code?

I am "trying" to learn interrupts.

Thanks,

Ralph

Post a Reply

Please log in to post a reply.

Did you know that a square wave sounds different than a sine wave? Learn more...