PWM ATmega88 Timer0 problem [Solved?]

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

On the ATmega88 I can get pulse length (duty cycle) controlled by OCR0A:

#include 

int main(void)
{

   DDRD |= (1<<PD6);
   PORTD |= (1<<PD6);  


// 8 bit timer for PWM (Timer0)
   TCCR0A |= (1<<COM0A1) | (1<<WGM01) | (1<<WGM00);
   TCCR0B |= (1<<CS01); // divide by 8
 
   OCR0A = 20; // duty cycle
 	
   while(1);

   return 0;
}

but now want to control the frequency more accurately then just using the prescalar divide ratios.

I have read that you can use OCR0B for this purpose, but haven't seen an example to help me sort it out.

Does this trick on Timer0, without an ICRx register, involve interrupts?

davef

Last Edited: Sun. Jan 23, 2011 - 05:20 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Some thing like: Use one comp int to set freq, clear the output in this handler, use the other comp int scaled to 0-100% of the first comp reg to set the output, giving desired duty and desired freq?

Imagecraft compiler user

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

Quote:

pulse length (duty cycle)

No, pulse length is period. period = 1/frequency. Duty cycle is the ratio of the on time to the off time often expressed as a percentage.

You can put lipstick on a pig, but it is still a pig.

I've never met a pig I didn't like, as long as you have some salt and pepper.

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

theusch - thanks for correction and
bob - for the hints.

davef

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

Quote:

theusch - thanks for correction

So--with the terminology in mind, what do you need to do? Are you restricted to timer0?

You can put lipstick on a pig, but it is still a pig.

I've never met a pig I didn't like, as long as you have some salt and pepper.

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

I want to make a 50us pulse every 1ms (1kHz) and to be able to turn it ON and OFF (by setting and clearing the prescalar clock bits?).

I am using Timer1 to get some long time periods and it looks like Timer2 hasn't got ICR either.

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

Following Bob's suggestion I have something that works, but can't find the solution to having 0C0A or B provide the output signal.

#include 
#include 


int main(void)
{

   DDRD |= (1<<PD7);

// 8 bit timer for PWM (Timer0)
//   TCCR0A |= (1<<COM0A1) | (1<<COM0B1) | (1<<COM0B0) | (1<<WGM01) | (1<<WGM00);
	TCCR0A |= (1<<WGM01) | (1<<WGM00);
   TCCR0B |= (1<<WGM02) | (1<<CS01) | (1<<CS00); // divide by 64  
   TIMSK0 |= (1<<OCIE0A) | (1<<OCIE0B);
  
   OCR0A = 50; // frequency
   OCR0B = 48; // sets the pulse duration


   sei();

   while(1);

   return 0;
}


ISR(TIMER0_COMPA_vect)
{
	PORTD &= ~(1<<PD7);
} 


ISR(TIMER0_COMPB_vect)
{
	PORTD |= (1<<PD7);
}
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Both compares are looking at the same counter. CompA has to be the freq (period?) and CompB is the pulse width. CompB fires 1st, sets the out, then CompA fires and resets it?

Imagecraft compiler user

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

Just a bit confused here. Are you telling me how the code operates or should operate?

My only concern now is having to use a port other than OCR0A or B to output the required PWM signal. Seems like one step towards a software PWM.

I have plenty of output ports.

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

You could use timer2 for a 1mS ISR() and when it fires , enable timer0 ISR() to do a 50uS pulse. WHen t0_ISR() fires you can disable it. Repeating when needed.

If you can afford a 1mS res. to your T1, you don't need to use T2.

1) Studio 4.18 build 716 (SP3)
2) WinAvr 20100110
3) PN, all on Doze XP... For Now
A) Avr Dragon ver. 1
B) Avr MKII ISP, 2009 model
C) MKII JTAGICE ver. 1

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

What I meant was: If you have a handler for the Turn On event, and the Turn Off event, you can set and reset any output in those handlers. Your example looks OK to me.

Imagecraft compiler user

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

OK, thanks guys.

The key point here is that you need to get control of TOP using WGM02 and as WGM02 by itself is you need to either to use WGM00 or WGM01 AND WGM001 as well.

Unless there is some combination of setting COM0A0, COM0A1, COM0B0 and COM0B1 to enable use of OCR0A or OCR0B as the output port then you need to use another port.

Happy to entertain any other solutions to update my understanding!