Go Down

Topic: PWM to 50 hz (Read 3284 times) previous topic - next topic

thrinker

Feb 20, 2013, 03:03 pm Last Edit: Feb 20, 2013, 07:48 pm by thrinker Reason: 1
Hello!

How do i set one of the PWM port to 50hz with a 0.5ms pulse width?

So far i got this:
Code: [Select]
 pinMode(11, OUTPUT);
 TCCR2A = _BV(COM2A1) | _BV(COM2B1) | _BV(WGM20);
 TCCR2B = TCCR2B & 0b11111000 | 0x07;
 OCR2A = 180;
 OCR2B = 50;


This code generates a 30.6hz signal with 22.8ms pulse width.

http://arduino.cc/en/Tutorial/SecretsOfArduinoPWM
http://playground.arduino.cc/Main/TimerPWMCheatsheet

Thanks in advance

retrolefty

bandwidth ?

You seem to be misusing that term or don't understand what the term means, do you mean duty cycle or pulse width?

Lefty

holmes4

"Blink without delay" see examples will let you do this.

Mark

AWOL

Try using the Servo library, using "writeMicroseconds (500);"
"Pete, it's a fool looks for logic in the chambers of the human heart." Ulysses Everett McGill.
Do not send technical questions via personal messaging - they will be ignored.

holmes4

Look in the playground - lots of ways to do this kind of thing listed there.

Mark

thrinker

I edited my post, i ment pulsewidth and not bandwidth. I dont want to use the arduino servo library. I want to write to the registers myself..

afremont

#6
Feb 20, 2013, 10:09 pm Last Edit: Feb 20, 2013, 11:10 pm by afremont Reason: 1
You want to pay special attention to this section of the :
Varying the timer top limit: fast PWM on this page
http://arduino.cc/en/Tutorial/SecretsOfArduinoPWM
This is probably the most confusing configuration you'll run into.  It's not very intuitive because it looks like you will be toggling OC2A (Pin 11), but you really toggle OC2B (Pin 3).  This is because you hijack the OCR2A register to set the TOP limit so it can't possibly set a duty cycle now.  The duty cycle is set by OCR2B and consequently it toggles OC2B (Pin 3).  This is all necessary because you want to use a "non standard" PWM frequency.
Code: [Select]

 pinMode(3, OUTPUT);
 pinMode(11, OUTPUT);
 TCCR2A = _BV(COM2A0) | _BV(COM2B1) | _BV(WGM20);
 TCCR2B = _BV(WGM22) | _BV(CS22)| _BV(CS21)| _BV(CS20);           //
 OCR2A = 156;
 OCR2B = 4;


This should give you a 50.1 Hz update rate with a .512mS pulse width on Pin 3.  I haven't tested it, but I think it's right.

EDIT:  I tested it on the scope and it works.  Pin 11 has a 25Hz 50% duty cycle waveform on it.
Experience, it's what you get when you were expecting something else.

thrinker


You want to pay special attention to this section of the :
Varying the timer top limit: fast PWM on this page
http://arduino.cc/en/Tutorial/SecretsOfArduinoPWM
This is probably the most confusing configuration you'll run into.  It's not very intuitive because it looks like you will be toggling OC2A (Pin 11), but you really toggle OC2B (Pin 3).  This is because you hijack the OCR2A register to set the TOP limit so it can't possibly set a duty cycle now.  The duty cycle is set by OCR2B and consequently it toggles OC2B (Pin 3).  This is all necessary because you want to use a "non standard" PWM frequency.
Code: [Select]

 pinMode(3, OUTPUT);
 pinMode(11, OUTPUT);
 TCCR2A = _BV(COM2A0) | _BV(COM2B1) | _BV(WGM20);
 TCCR2B = _BV(WGM22) | _BV(CS22)| _BV(CS21)| _BV(CS20);           //
 OCR2A = 156;
 OCR2B = 4;


This should give you a 50.1 Hz update rate with a .512mS pulse width on Pin 3.  I haven't tested it, but I think it's right.

EDIT:  I tested it on the scope and it works.  Pin 11 has a 25Hz 50% duty cycle waveform on it.



Thanks alot! That works great. To change the pulse width i edit the output compare register b, OCR2B = 4 gives me 510us width. When i change the OCR2B value to 20 i get a 2.560ms width. Between 10 and 11 the value is 1.280ms and 1.410ms, is it possible to get a value inbetween those two? like 1.300?

Thanks in advance!

afremont

The problem is that with a 50Hz update rate, the possible pulse length is 20mS.  This is spread across 156 possible widths.  This only gives .13mS resolution as you already can see.  To achieve .02mS resolution as you asked, would require several more bits of resolution in the PWM unit and that's not going to happen, you're stuck at 8 bits maximum; right now you barely have 7 since the TOP count is 156.  You are asking for 10 bits of PWM resolution.  It's just not possible with the 8-bit timers.
Experience, it's what you get when you were expecting something else.

AWOL

Or you could use the Servo library (or look at the source, and see which bits you want to use, if you don't want to use the library itself)
"Pete, it's a fool looks for logic in the chambers of the human heart." Ulysses Everett McGill.
Do not send technical questions via personal messaging - they will be ignored.

afremont

#10
Feb 23, 2013, 09:26 am Last Edit: Feb 23, 2013, 09:33 am by afremont Reason: 1
I glanced (literally five minutes) at the servo library code and it looks like it uses Timer1 initially.  This is a 16 bit counter.  It puts it in ordinary count mode and enables overflow interrupts.  With the prescaler of 8, it should overflow roughly 30.5 times per second.  This would be the update rate to the servo, not 50Hz.  This means one cycle is about 33mS long but is divided into 65536 possible parts for 500nS resolution on the duty cycle.  It's not using the PWM feature of the chip, it's simulating it with software in the ISR so that it can run a multitude of servos.  Given this method, it should work on any output pin.

EDIT:  When you hijack Timer1, it disables the ability to use analogWrite() on Pins 9 and 10 for PWM.
Experience, it's what you get when you were expecting something else.

AWOL

Quote
I glanced (literally five minutes) at the servo library code and it looks like it uses Timer1 initially.  This is a 16 bit counter.  It puts it in ordinary count mode and enables overflow interrupts.  With the prescaler of 8, it should overflow roughly 30.5 times per second.  This would be the update rate to the servo, not 50Hz
I don't have the source to hand to glance at, but I do have a Servo library project and a 'scope.
50Hz, pretty much on the nose.
"Pete, it's a fool looks for logic in the chambers of the human heart." Ulysses Everett McGill.
Do not send technical questions via personal messaging - they will be ignored.

afremont

Yep, you're right.  I looked thru the code a little more and the library does go to the trouble to dink the Timer for a 20mS period (50Hz).  I commend the author for doing it right.
Experience, it's what you get when you were expecting something else.

thrinker

Thanks alot for all the help. I will look in the servo library and try to use timer1.

afremont


Thanks alot for all the help. I will look in the servo library and try to use timer1.


Your welcome.  Feel free to ask, I spent some time last night getting acquainted with the servo library source code.  It's pretty well done.  I experimented with TImer1 some more and played around with Timer0 to see what kind of impact its ISR was having on other interrupts.  I didn't specifically experiment with PWM modes on Timer1, but I'm pretty sure I could help you get it set up if you want to go that way.  The library is probably the best way to sacrifice Timer1 for the most return.
Experience, it's what you get when you were expecting something else.

Go Up