PWM generation and question about code

Hi, I need to generate a PWM signal at 141 Hz.

I've found this code on the web (Thanks Jeson Pepas), I really can't understand the part regarding the TCCR and OCR registers. All is working fine except that I need to generate a TONE and when I output a tone the pwm stops working.

My question is:

How can I output a PWM signal at 141 Hz just using the PWM outputs without using the OCR and TCCR registers?

THANKS

here you are the code I'm using:

// by jason pepas (jasonpepas@gmail.com) // released under the GPLv2.

// min and max duty cycles which the actuator will respond to.

define DUTY_MIN 15

define DUTY_MAX 98

uint8_t duty_cycle = DUTY_MIN;

// min and max periods which the actuator will respond to.

define PERIOD_MIN 106

define PERIOD_MAX 115

uint8_t period = 110;

void setup() { pinMode(3, OUTPUT); // OC2B // we are using waveform generator mode "7", which is fast pwm with TOP = OCRA. // see the atmega168 datasheet page 157, table 17-8. //TCCR2A = _BV(COM2B1) | _BV(WGM21) | _BV(WGM20); // actually, I want "inverting" mode, because I am now driving an n-channel mosfet. TCCR2A = _BV(COM2B1) | _BV(COM2B0) | _BV(WGM21) | _BV(WGM20); TCCR2B = _BV(WGM22) | _BV(CS22) | _BV(CS21) | _BV(CS20); OCR2A = period; // sets TOP (thus, frequency). 111 should be just over 140hz. OCR2B = (uint8_t)(period * (duty_cycle / 100.0)); // sets duty cycle. }

boolean walk_duty = true; boolean duty_climbing = true;

boolean walk_period = false; boolean period_climbing = false;

void loop() { if (walk_duty == true) { if (duty_cycle < DUTY_MIN) duty_cycle = DUTY_MIN; if (duty_cycle > DUTY_MAX) duty_cycle = DUTY_MAX; if (duty_cycle == DUTY_MAX) { duty_climbing = false; } if (duty_cycle == DUTY_MIN) { duty_climbing = true; } if (duty_climbing == true) { duty_cycle++; } else // (duty_climbing == false) { duty_cycle--; } OCR2A = period; OCR2B = (uint8_t)(period * (duty_cycle / 100.0)); // sets duty cycle. }

if (walk_period == true) { if (period < PERIOD_MIN) period = PERIOD_MIN; if (period > PERIOD_MAX) period = PERIOD_MAX; if (period == PERIOD_MAX) { period_climbing = false; } if (period == PERIOD_MIN) { period_climbing = true; } if (period_climbing == true) { period++; } else // (period_climbing == false) { period--; } OCR2A = period; OCR2B = (uint8_t)(period * (duty_cycle / 100.0)); // sets duty cycle. }

delay(20); }

You could probably get 141Hz using the blink without delay example, using "micros" instead of "millis". Do you mind if I ask the application? It's a strange value.

All is working fine except that I need to generate a TONE and when I output a tone the pwm stops working.

Yes that is because the tone generator and the PWM are both using the same timer. So change what timer one of them uses.

I really can't understand the part regarding the TCCR and OCR registers

For full information on the options with the timer see the processor's data sheet.

It is not likely you will be able to get exactly 141Hz but you should get close.

AWOL: You could probably get 141Hz using the blink without delay example, using "micros" instead of "millis". Do you mind if I ask the application? It's a strange value.

AWOL I 'm driving an electronic actuator that accepts PWM inputs.

Hi Mike, thanks for your reply.

Grumpy_Mike:

Yes that is because the tone generator and the PWM are both using the same timer. So change what timer one of them uses.

How do I do this? just changing the buzzer pin?

...

It is not likely you will be able to get exactly 141Hz but you should get close.

Using the register method I get very close to what I need, as you mentioned, but seems there is no other way to reach that frequency if not using the registers.

Furthermore I've just discovered another problem: for the final project an arduino mega 2560 should be used, but I found out that obviously the registers used on the atmega 328 are not working on the atmega 2560, this means I HAVE TO find another method to implement PWM's without touching the registers.

Thanks.

arcom: Furthermore I've just discovered another problem: for the final project an arduino mega 2560 should be used, but I found out that obviously the registers used on the atmega 328 are not working on the atmega 2560, this means I HAVE TO find another method to implement PWM's without touching the registers.

Thanks.

See earlier post:

You could probably get 141Hz using the blink without delay example, using "micros" instead of "millis".

I'm reading the mentioned example, I will let you know

this means I HAVE TO find another method to implement PWM's without touching the registers.

No it doesn't.

The 2560 has all the registers of a 328 and then more. So there are more to play with. This is why you can get more PWM signals on this processor because of the extra timers.

I've uploaded the above mentioned sketch on a 2560 Mega and it just dosen't work.

arcom: I've uploaded the above mentioned sketch on a 2560 Mega and it just dosen't work.

So you find out why. There are minor differences in the way the timers work. You need to study the data sheets.

thanks