Total PWM n00b.

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

I've looked at Atmels site, the academy, and Google but I could not find a site that had a simple example of a PWM driving a LED or speaker at a set frequency. There were tons that would fade the LEDs and stuff but I can't seperate the fading part of the code from the basic PWM part.

Anyways as a simple demo I would like to buzz the piezo speaker on my Butterflys OCR1A port at 260Hz. The mega169v is running at 1MHz. I'm a bit confused about duty cycle and the prescaler. If I had a duty cycle of 50% and a prescaler of 1 would the frequency be 500KHz? :?

Here is my main() of some code that I scrapped from some fader examples. I don't even know what it should be doing (its not buzzing the piezo anyways).

int main(void)
{    
    // Program initalization
    Initialization();
	
	TIMSK0  = 0x80;                     // Int T1 Overflow enabled
	TCCR1A = (1 << COM1A1)+(1 << WGM01);   // non inverting / 8Bit PWM
	TCCR1B = (1 << CS10);                // CLK/1
	DDRD   = (1 << 5);               // PD5 (OC1A) as output
	OCRA1H = 0;
	OCRA1L = 80;
	OCRA1 = 80;
	sei();                     	     // Interrupts enabled
	
	return 0;
}

I'm sorry that this is so n00bish. I wish there was a tutorial on PWMs and how they work in an AVR.

Thanks! :)

Math is cool.
jevinskie.com

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

Hi Jevin,

I've just been coming up to speed on PWM myself. Hopefully this helps.

First, what I'm doing isn't really PWM. I'm running CTC mode which just toggles the OC0 output. But all you have to do is change the configuration and you are running PWM. For me, I wanted to change frequency and PWM is fixed frequency so what I do is load the OCR0 register with the value I want to count to and when counter0 hits that count, it toggles the output pin.

The pause() command is just using the 16-bit delay out of delay.h (slightly modified to get me more useful delay values) and is just for how long my beep lasts. The important parts are setting up how you want the counter to work - PWM mode or not and what variant, and then enabling the output pin (I'm using PB3 which is connected directly to a CUI CEP-1160 piezo buzzer and the other leg is connected to ground. Works like a champ and the piezo resonant frequency is right at 4 kHz so that's about what I shot for with my prescale values, etc. The equations are in the datasheet depending on the kind of PWM you use. Since I get a transition (1/2 cycle) on each counter max, my frequency is divided by two from what some of the other modes are. But that is in the equations. Also, the divider scales from your system clock. I'm using a divider value (N) of 8 from the 1 MHz internal oscillator. But match this up with the datasheet and it should help.

This is on a Mega16, btw.

void beep (uint8_t pwmset)
{
// Load up the OCR0 register (the count Counter0 counts to - basically 1/f)
OCR0 = pwmset;

// Toggle on OC0 output, CTC mode for TC0, prescale=8 (prescale starts counter)
TCCR0 = BIT(COM00) | BIT(WGM01) | BIT(CS01);

// Set buzzer pin to output
bit_set(DDRB,BIT(BUZZER));

pause(4000);

// Set buzzer pin to input to disable
bit_clear(DDRB,BIT(BUZZER));

// Unset Counter0 configuration bits to stop the counter
TCCR0 = 0;
}

This is just to demo the circuit though. What I'm doing now is setting it up where it's all interrupt driven and another counter does the delay and my main program can carry on with it's thing once I launch the beep routines which are handled totally by interrupts.

Please note - this post may not present all information available on a subject.

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

Maybe some basic principles are in order, here.

When you say buzz a piezo or flash an LED with the PWM, there are several things that you have to take into account:

1) The frequency of the buzz or the frequency of the LED flash is the PWM period.

2) The PWM period is controlled by four things:

a. The processor clock frequency
b. The counter prescale value
c. The max count value for te PWM timer
d. Whether or not you choose Phase Correct operation or not.

3) The PWM duty cycle has no effect on the primary tone of the buzz or the period of the flash

4) Flashing an LED at more than 10 per second will cause it to appear almost steady to your eye with the brightness depending on the PWM duty cycle.

So, suppose that you use an 8-bit counter. It takes 256 counts to go from bottom to top count. If you want the piezo tone to be about 250 hz, then the period is 1/250 sec or 4millisecond (4000 uS).

It takes 256 counts to cover this interval so you want each count to be 4000/256 us or 16 us per count (if my mental arithmetic is right).

So, to do this, you need a divided version of the processor clock that has a period of 16us or a frequency of 1/16us = 62.5KHz. This is where the prescaler comes in. It divides your processor clock to generate the clock for the counter. But, there are limited prescaler values. If the clock is 4MHz, then you would need a prescale value of 4MHz/62.5KHz = 64. That just might be one of the magic numbers.

Hope this helps.
Jim

Jim Wagner Oregon Research Electronics, Consulting Div. Tangent, OR, USA http://www.orelectronics.net

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

The only thing I would add is that 4K is a pretty high 'whistle'. The sonalerts used to beep at about 2K, and tones and boops and whatnot are usually more like 400, 800, 1000 Hz neighborhood....

Imagecraft compiler user