Go Down

Topic: PWM generation and question about code (Read 4054 times) previous topic - next topic

arcom

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);
}


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.

Grumpy_Mike

Quote
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.

Quote
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.

arcom


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.

arcom

Hi Mike, thanks for your reply.


Quote

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?

Quote
...

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.



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.

joshuabardwell


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:

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

arcom

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

Grumpy_Mike

Quote
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.

arcom

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

Grumpy_Mike


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.


Go Up