Google-Apps
Hauptmenü

Post a Comment On: Ken Shirriff's blog

"Secrets of Arduino PWM"

67 Comments -

1 – 67 of 67
Anonymous Anonymous said...

Thank you for the article!

As a beginning Arduino user, this is very helpful!

November 1, 2009 at 10:46 AM

Blogger Unknown said...

Excellent paper. Many Thanks

January 10, 2010 at 5:57 AM

Blogger Unknown said...

exactly what I needed! thanks!

January 23, 2010 at 1:38 PM

Blogger Tom said...

I am so glad I found this. Just what I needed.
One question though-likely I am not understanding some subtlety.
It seems from the datasheet that the 64 pre-scale corresponds to 110. I am wondering if I am missing something, as you mention 100 as the 64 prescale divider.
Thank you!

February 7, 2010 at 9:56 AM

Anonymous Anonymous said...

Excellent article, I've been going through some example code but this made it all come together.

Thanks,
Mike

February 27, 2010 at 9:42 AM

Blogger Ken Shirriff said...

Tom, you asked about how to divide by 64 with the prescaler. For timer0 and timer1, the clock select bits are set to 011 (CS02,CS01,CS00 or CS12,CS11,CS10). But for timer2, the clock select bits are set to 100 (CS20,CS21,CS20). Confusingly, Timer 2 uses different clock select bit values from Timers 0 and 1.

March 16, 2010 at 11:22 PM

Blogger Unknown said...

Ken,

I am just learning about Arduino and I have a question about your article on “Secrets of Arduino PWM”.

Your example says
pinMode(3, OUTPUT);
pinMode(11, OUTPUT);
TCCR2A = _BV(COM2A1) | _BV(COM2B1) | _BV(WGM20);
TCCR2B = _BV(CS22);
OCR2A = 180;
OCR2B = 50;
What I am confused about is previously you stated that that these examples set the clock divisor to 64. Is there a bit inversion in the writes to an AVR register?
Your line TCCR2B = _BV(CS22); would set the TCCR2B register to 00000100b.

Is there something I’m missing here?

Thanks in advance for your response.

Monty

April 21, 2010 at 9:15 AM

Blogger Unknown said...

Very helpful, thanks--we're trying to use Arduinos to power a small pump and measure flow for an open source river modeling system, and I was hung on this topic until reading this--see our stuff at lrrd.blogspot.com.

May 22, 2010 at 6:06 PM

Blogger Matej said...

that is wonderful.. but whan i was looking at the library i saw in the comments that this will work only for 36-40khz modulation? Whay is that and how can i change it so it will work on 56khz?

May 23, 2010 at 1:32 AM

Blogger Cassiano Rabelo said...

Excellent tutorial Ken. Thanks a lot for sharing your knowledge.

Would you mind elaborating a bit more on how someone could use the sound card and a program such as xoscope to help debug this sort of thing? Do you mean by plugin a speaker to the arduino pin, getting it close to the computer mic and using such a software to graph the wave?

Thanks once again.

September 23, 2010 at 5:55 PM

Anonymous Colin Adamson said...

Most excellent thank you -- saved me days trying to make sense of that Atmega328 datasheet
I was using the default 490 Mhz arduino analogWrite PWM and was getting horribly low torque with some small DC motors on low duty cycles. Changed it to 30Hz and now its way better, still runs smooth.

December 16, 2010 at 11:44 PM

Blogger Ken Shirriff said...

Colin, thanks for your comment. I'm glad the article was helpful.

Cassiano, with a sound card oscilloscope, you connect the signal directly to the sound card through a resistor to reduce the current. There are details at http://www.ehow.com/how_2278973_use-sound-card-oscilloscope.html

December 17, 2010 at 10:27 PM

Blogger Thorsten said...

Thanks for explaining this matter so extensively! I was looking for a way to generate 1 MHz on one of the Arduino-pins. Your post helped me a great deal to accomplish that.

The reason I am writing this comment is the following: It took me almost 6 hours till I found out (mainly in sheer desperation) that the order of setting the timer control registers TCCR2* and the output compare registers OCR2* seems to matter! If you assign an OCR before setting the corresponding TCCR the timer simply doesn't start counting.

February 13, 2011 at 11:47 AM

Anonymous Anonymous said...

but how can i get it to make a 38khz freq with 50% duty cicle?

March 8, 2011 at 2:14 PM

Anonymous Quarkninja said...

Very informative! Excellent Work! Thanks!

May 1, 2011 at 12:37 AM

Blogger Cooper Maa said...

Very helpful, thanks for your share.

As for debugging PWM, I think proteus ISIS is a good tool for that purpose. Proteus has a virtual osilloscope, see my post(in chinese, sorry):
http://coopermaa2nd.blogspot.com/2011/05/proteus-pwm.html

May 15, 2011 at 2:56 AM

Blogger Unknown said...

I wrote a brief article on creating PWM using the Arduino UNO, with ability to control the frequency on my blog. Just leaving a link here as I found this article very useful in my research !

http://smacula.blogspot.com/2011/04/creating-variable-frequency-pwm-output.html

June 27, 2011 at 8:21 AM

Anonymous Anonymous said...

Great summary and guide for using the ATmega328p timers! Thanks for taking the time to put this together. Very helpful.

July 24, 2011 at 2:05 PM

Blogger Michael said...

This may be a stupid question by a newbie, but what is the _BV function? Nowhere to be found in the Arduino reference.

August 14, 2011 at 11:58 PM

Blogger Cooper Maa said...

_BV is a macro defined in avr-libc:

#define _BV(x) (1 << x)

see http://194.81.104.27/~brian/microprocessor/BVMacro.pdf

August 15, 2011 at 12:47 AM

Anonymous Anonymous said...

Thank you very much, this is the best condensed reference I have seen, all clear and to the point!!!

January 19, 2012 at 1:21 AM

Anonymous mitch deoudes said...

The version of this article posted at arduino.cc is missing all of the diagrams except the first one.

February 3, 2012 at 9:32 PM

Anonymous Henry Best said...

I want to use a low frequency PWM, below 10Hz. The frequency isn't critical but would have to be in that area. Any ideas how to get down to that frequency? I want to use the Arduino Uno for other things whilst the PWM is being output.

February 6, 2012 at 10:02 PM

Anonymous Anonymous said...

Hi, is it possible for my Arduino Duemilanove to go down to 70 Hz? I need to output a PWM from my board at that frequency. Basically I am creating a buffer that takes in a PWM signal and outputs a PWM that has the same pulse width and frequency as the input signal. Is it also possible to update the frequency in every execution? I can't seem to get it to work
properly.. Thanks in advance!

March 29, 2012 at 8:50 PM

Blogger Unknown said...

Hi,

If you read my article: http://www.smacula.co.uk/2011/04/creating-variable-frequency-pwm-output.html

You can actually go as low as 15Hz. I have not tried to go that low myself though, but don't see why it would not work.

March 29, 2012 at 11:50 PM

Blogger GratefulFrog said...

Hi,
Your article has been a great help, but now I am working on an Arduino Micro with an ATMEGA 32u4 processor.

All I want to do is get phase-correct PWM at the highest possible frequency on 3 pins.

Will these 2 lines do that?

TCCR1B = _BV(CS00); // change the PWM frequencey to 31.25kHz - pins 9 & 10

// timer 0B : pin 3 & 11
TCCR0B = _BV(CS00); // change the PWM frequencey to 31.25 kHz - pin 3 & 11

please let me know, if you can, by relying to my id at gmail.
Cheers,
Bob

March 8, 2013 at 9:36 AM

Blogger Unknown said...

Hi Ken,
Thank you for your library!
I modified it a bit to work with Hitachi air conditioning. But there is one momnet I can not understand. I had to increase the buffer to 600 (RAWBUF 600). But then I try to read I can read only 532 byte. While there is still 8 :( In what may be another reason of not getting all the data from the console?
Thank you! And excuse me for my english!

April 14, 2013 at 9:33 AM

Blogger Ken Shirriff said...

Сергей: another user of the irremote library found that rawlen type (uint8_t) is too small for more than 256 entries, so try replacing it by unsigned short int. Also, discussion of the irremote library is here.

April 15, 2013 at 8:42 AM

Blogger Gabriel Staples said...

Fantastic Article!!! Thanks a ton.

As Mitch Deoudes, said, "The version of this article posted at arduino.cc is missing all of the diagrams except the first one." This is still true. If you could figure out how to get the diagrams added back into the article on arduino.cc (http://arduino.cc/en/Tutorial/SecretsOfArduinoPWM) that would be great!

Thanks!
Gabriel Staples
http://electricrcaircraftguy.blogspot.com/

December 21, 2013 at 9:29 PM

Blogger dafaddah said...

I'm working on 'sculpting' an output signal to meet certain shape and frequency parameters. This is the first time I'm beginning to see the light at the end of the tunnel trying to understand how to code PWM to accomplish this. Many thanks!!

February 11, 2014 at 4:22 AM

Blogger Gabriel Staples said...

dafaddah, that sounds very interesting; I'd like to see what you can do to "sculpt" a signal shape, so would you mind sharing a link here when you are done, so others can see your work?

February 11, 2014 at 4:56 AM

Anonymous Gabriel said...

dafaddah,

Since posting my last question to you, I've learned that you can turn a PWM signal into a true analog output by using an R-C filter (ex: Resistor of 10k and Capacitor of 0.1uF). I'm now guessing that you are using an R-C analog filter to turn a high-freq PWM output into a true analog signal....just like a DAC (Digital to Analog Converter). Is this correct? If so, what freq are you using, and what R-C values are you using on your filter?

In either case, for anyone who wants to see an example of this, see pgs. 217-219 of Simon Monk's book "Programming Arduino Next Steps: Going Further with Sketches." Figure 13-4 on the bottom of pg. 217 shows the R-C filter with R=10k and C=100nF (0.1uF), feeding a PWM-generated signal into an Oscilloscope, as a filtered analog signal. Figure 13-5 on pg. 219 shows the actual 1KHz wave form (a sine wave) produced by the Arduino Uno with a 10KHz PWM signal sent through this analog filter. The top sine wave is the input signal to the Arduino, as created by a nice signal generator, and the bottom sine wave (a little rougher looking), is the signal that the Arduino generated itself, again, using a 10KHz PWM signal going through that simple R-C filter. This is very cool! An R-C filter like that is only a few cents, and now you have a true analog output using a cheap Arduino! For anyone wanting to see these pages, they are viewable on Amazon here, by clicking the book image to look inside: http://www.amazon.com/Programming-Arduino-Next-Steps-Sketches/dp/0071830251.

Have fun!

~Gabriel
http://electricrcaircraftguy.blogspot.com/

July 1, 2014 at 9:09 PM

Blogger Unknown said...

Hii ken i need to generate digital AM signal using arduino using timer 0 and 1
http://www.ncbi.nlm.nih.gov/pubmed/24689560
please help any help would be gretly appreciated

September 9, 2014 at 6:49 AM

Blogger Unknown said...

Excellent article, never saw something as comprehensive and clear about Timeers and PWM before - many thanks for your time and efforts.

kind regards, Mike from Mannheim, Germany

November 6, 2014 at 5:56 AM

Anonymous Anonymous said...

Hello Ken,

I need some help from you on my the same task.

I need to generate 4 independent PWM signals with fixed frequency of 25Khz.

I am currently using UNO. I have implemented the same code which was in this blog, setting the same PRESCALE and OUTPUT COMPARE REG for a test.

As UNO is ATMEGA 328, the FAST PWM should work on this too having same CS values.

I did not get any waveform at the desired PIN. Do you suggest me work on any other board?

Need some inputs, so that i can move in that direction.

Thank you in advance.

SAFWAN

November 11, 2014 at 2:36 AM

Blogger DvanF said...

Ken, thanks for this usefull document. I have tried the examples and they do work fine. What I would like is some more detailed information on how to use the PWM outputs with a controllable frequency AND separately controleed duty cycle. In your examples I can't find a way to change the frequency. I want to use it for speed control of my model train (Märklin scale Z).
Thanks, Dick van Fulpen, Houten (NL)

November 17, 2014 at 5:26 AM

Blogger DvanF said...

Ken, thanks for this usefull document. I have tried the examples and they do work fine. What I would like is some more detailed information on how to use the PWM outputs with a controllable frequency AND separately controleed duty cycle. In your examples I can't find a way to change the frequency. I want to use it for speed control of my model train (Märklin scale Z).
Thanks, Dick van Fulpen, Houten (NL)

November 17, 2014 at 5:27 AM

Blogger Gabriel Staples said...

DvanF, it's all there. Looks like you need to do a closer read. See the section "Varying the timer top limit: fast PWM", for example. Varying OCR2A in that example sets the frequency, and varying OCR2B sets the duty cycle of output B.

I hope that helps. Good luck!

~Gabriel Staples
http://electricrcaircraftguy.blogspot.com/

November 19, 2014 at 7:31 PM

Blogger SOLID said...

I am a newbie to arduino and this tutorial was excellent in solving so many problems for me. The problem is that I would like to do same with the other timers (1 and 0).. Could you please confirm that what I have currently setup is correct..

pinMode(3, OUTPUT);
pinMode(11, OUTPUT);
pinMode(6, OUTPUT);
pinMode(5, OUTPUT);
pinMode(9, OUTPUT);
pinMode(10, OUTPUT);
TCCR2A = _BV(COM2A1) | _BV(COM2B1) | _BV(WGM21) | _BV(WGM20);
TCCR2B = _BV(CS22);
TCCR1A = _BV(COM1A1) | _BV(COM1B1) | _BV(WGM11) | _BV(WGM10);
TCCR1B = _BV(CS22);
TCCR0A = _BV(COM0A1) | _BV(COM0B1) | _BV(WGM01) | _BV(WGM00);
TCCR0B = _BV(CS22);
OCR2A = 180;
OCR2B = 50;
OCR1A = 180;
OCR1B = 50;
OCR0A = 180;
OCR0B = 50;

January 16, 2015 at 2:45 AM

Blogger SOLID said...

Solved it.... All by myself... thanks to this tutorial that clarified the avr guide... SUPER>....

January 16, 2015 at 8:16 AM

Blogger Unknown said...

Solid, please tell me the solution
s0bes@mail.ru
s0bes68@gmail.com

January 28, 2015 at 2:57 AM

Blogger Unknown said...

Hello Ken and thank you for this post -- I am looking at doing a 60Hz AC inverter - so I need to push a new Duty Cycle setting to the timer for every pulse.
Based on your info I am expecting to use Timer 2 for the Phase Correct ( ensuring A or B can have a true 0% DS output. ( I am using an H Bridge) - So for 1/2 cycle A will go from 0 to 100% and back with B at 0%.
So the questions is...As the timer is running, I do my calculation and come up with the next pulse DS and I have to write this to the OCR2A and B - whaile the output is active - does this work? - or will this reset the timer and start the pulse all over?
- I am guessing this is more in the guts of the register management for the 328 - the DS says they are double buffered, and I would assume this means you can write to them while the timer is running ( in one pulse period) -
Do I have this correct?

March 25, 2015 at 6:18 AM

Blogger Mark Shanks said...

I'm pretty sure the comment in the first example code should be 10% duty cycle at 1Hz, not 1kHz. Good article though.

January 17, 2016 at 5:19 PM

Blogger Gabriel Staples said...

That's delayMicroseconds, not delay, so no, it's 1 kHz. 100 us on/1000us total period = 10% at 1ms period, or 1khz.

January 17, 2016 at 11:28 PM

Blogger Mark Shanks said...

Ah, thanks Gabriel, my brain didn't see the 'microseconds' after delay. My bad.

January 18, 2016 at 6:20 AM

Blogger Unknown said...

Great article. Thanks for sharing your knowledge.

Can you give more instruction to make a oscilloscope from a sound card?

April 18, 2016 at 9:27 PM

Blogger gurumoorthi said...

CAN YOU PLEASE SAY HOW TO STOP NEGATIVE SIDE OUTPUT OF PWM

May 25, 2016 at 8:13 AM

Blogger Paul R. Potts said...

This is very helpful, Ken -- I have been reading the datasheets for the ATtiny family and while they spend many pages covering PWM, the subtleties of the counting modes are _not_ all that clear, especially critical bits of information like your explanation of how fast PWM mode can't go to 0%.

August 17, 2016 at 6:45 AM

Blogger Alex's Blog said...

Question do you know if the shape of the pwm curve has any effect of positive or negative. There is literature on soft swtiching so the shape is more angled instead of hard edges but is there any benefit of the a curved shape.

October 12, 2016 at 10:36 AM

Blogger thomas said...

Hey, thanks for the great article. I would need around 250 kHz with adjustable duty cycle on pin 9. Is this possible and how? Many thanks! Thomas

May 19, 2017 at 2:59 PM

Blogger Gabriel Staples said...

thomas, Ken is a pretty busy guy. I don't think he'll have time to respond.

If this is important to you and you can't figure it out based on this and similar articles, nor can you find the solution elsewhere, contact me and I'll give you the source code with a solution to do exactly what you asked for above within 24~48 hrs of receiving $200 in my paypal account for the service. Seriously, this is not a scam. I don't sell hours, I sell expertise. You may not be needing this service that bad, in which case it won't hurt my feelings any if you don't contact me. One caveat, however: for 250kHz PWM you can only have a resolution of 64 instead of 256. If this meets your need, hit me up! You'll have working code with proof of functionality via oscilloscope screen shots I'll send you in no time.

Ken, if you have any problem with me posting this post on your website here, please contact me and let me know and I'll remove it.

May 20, 2017 at 7:53 PM

Blogger Ken Shirriff said...

Thomas: look at the section "Varying the timer top limit: fast PWM". To get 250kHz from a 16MHz clock, set OCRnA to count to 64 (to divide by 64), and then change OCRnB to get the duty cycle you want. If you need more details, you can consult with Gabriel :-) I'll leave Gabriel's offer here, but in general my blog isn't a place to advertise consulting.

May 20, 2017 at 10:46 PM

Blogger Unknown said...

Is it possible to generate 38khz digital pulse with arduino.

July 6, 2017 at 10:10 AM

Blogger Unknown said...

Excellent explanation !!
Thank, It have helped me a lot.

October 12, 2017 at 9:57 AM

Blogger peterpan said...

I'd like to use the PWM functionality to do one of those candle simulations. My hope is to have my program's main loop generate multiple up/down ramp counts at different rates, combining them to simulate a random affect, and then using the final result to vary the PWM duty cycle to a LED driver. The PWM will hopefully allow for more natural looking brightness changes than the abrupt changes you usually see in simpler simulations. But for maximum smooth transitions, I think I'll need to ensure that changes to the PWM limit counter (or counters depending on the method I guess) happen at predictable times, like when the counter reaches its limit, or when it returns to zero. Is it possible that in addition to the PWM functionality I could tie an ISR to one of these occurrences? That way my main loop could simply adjust "brightness" variables, and I would know that changes to the timer register always happen at a predictable point in time. Does that make sense?

November 16, 2017 at 11:26 AM

Blogger Ken Shirriff said...

peterpan: the candle simulation sounds like a cool project. Given the speed of the PWM, I expect any glitches due to updates would be invisible. So I'd recommend trying out the simple approach before worrying about complex update strategies.

November 16, 2017 at 2:45 PM

Blogger peterpan said...

Thanks Ken. Is it at least possible to stuff the count limit register without re-initializing the whole count sequence? If so, I'm probably concerned about nothing, because stuffing the register is likely going to be an atomic operation. If the only choice were to call a single canned function that also restarted/reset the count everytime limit register were set. The main loop, after all, will be adjusting the PWM limit register pretty often.

November 17, 2017 at 6:38 AM

Blogger Ken Shirriff said...

peterpan: the ATmega328 datasheet says the PWM registers are double-buffered and updated at the top or bottom of the count, so the PWM output is glitch-free (page 129). So this shouldn't be a problem.

November 17, 2017 at 8:54 AM

Blogger peterpan said...

One more question Ken. If nothing else it will help me and maybe others appreciate what the PWM functionalty can do for them compared to working without it. Based on your experience with the execution speed of the Nano boards, what if the above described candle simulation did not have the benefit of a built in hardware aided PWM functionality. What if in addition to the various moving accumulators I described to continually alter the PWM, what if I brute forced my own PWM as part of the loop, using ordinary data pins? Not much different from bit banging serial data back in the days of "yore". Since there are only a couple of timers, manually doing the PWM would mean I could control as many "candles" as there are available pins whose state could be toggled, of course depending on execution speed. There is a microsecond timer available for such fast decisions, but obviously even with a well written loop the CPU would have to be pretty darn fast. If each manual PWM output needed say just 16 brightness levels, and the whole on/off cycle (at any duty cycle) had to be over 30 time a second to avoid flicker, that would mean the whole loop better execute all its decisions and complete 480 times per second. That doesn't sound like a lot for a modern CPU, but what about the much less sophisticated 328 Nano? Of course I'll have to try it myself to see, but maybe you already have a feel for whether this is in the "maybe" category or is more in the "ice cream's chance in hell" category.

November 29, 2017 at 7:25 AM

Blogger Ken Shirriff said...

peterpan: that sounds like it would work, although it would be more programming than using the PWM. One possibility would be to have the "PWM" data in a 16-entry table, so the main loop would just need to step through the table and write out the data. I.e. it would be fast. It could even run as an interrupt routine so you could get constant timing. You could have a separate routine that runs occasionally to update the table with the new brightness data, and this part could be slower. But personally I'd just use PWM, at least to try it out and get the candle simulation algorithm working.

November 29, 2017 at 8:53 AM

Blogger Unknown said...

"The timers can also generate interrupts on overflow and/or match against either output compare register, but that's beyond the scope of this article."

I am having trouble trying to setup multiple interrupts, where might I find more info on that?

December 1, 2017 at 2:07 PM

Blogger peterpan said...

By the way, I finally had some downtime (scarce) and implemented that candle sim. I took your advise and just did it using the PWM calls, and now I see (I think) that if I stick with the simple "fast PWM" methods, should allow me 6 independent candles. I probably wen't overboard combining multiple prime number based counters and extra random vars to make the timing creep, all to attempt more believable randomness, and I also did it as a class to make it easier to implement more or less candles. So far I only have 2 "burning", but it seems to work well. I won't fill up your blog with my code, especially since I'm a freak about commenting. But if you'd like to see, shoot me an alternate way of getting it to you. I'm not really on many forums for arduino, but maybe I'll post it somewhere on my web site, and share a link wherever its allowed. It requires simple transistor 'driver' circuits to power lamps or LEDs, but I can throw a simple diagram together for that.

December 20, 2017 at 1:16 PM

Anonymous Anonymous said...

Hey there would you mind sharing which blog platform you're working with?
I'm planning to start my own blog in the near future but I'm having a tough time choosing between BlogEngine/Wordpress/B2evolution and Drupal.

The reason I ask is because your layout seems different then most blogs and I'm looking for something completely unique.
P.S Sorry for getting off-topic but I had to ask!

March 20, 2018 at 11:44 AM

Blogger Ken Shirriff said...

Anonymous: I use Blogger for my blog. I started with one of the default layouts but have modified and customized it over time.

March 20, 2018 at 1:28 PM

Blogger Jet Labviewer said...

Hi

I am using LIFA to generate PWM. I copied the above codes and checked the frequency. The frequency in any case is 1000 Hz. Would anyone help me to solve the issue. I need frequencies between 20 and 50 Hz.

February 18, 2020 at 9:34 AM

Blogger Joshua said...

Please can tell me how to generate SPWM with the code especially varying the time on and off

April 20, 2020 at 3:18 AM

Anonymous TheOnlineShed said...

Your post really helped me. Thanks! I used it to trigger an ultrasonic sensor without blocking the Arduino main loop. This means you can do other cool stuff at the same time. Here's a link to explain...
http://theonlineshed.com/arduino-multi-tasking

June 6, 2020 at 2:58 AM

You can use some HTML tags, such as <b>, <i>, <a>

Comment moderation has been enabled. All comments must be approved by the blog author.

You will be asked to sign in after submitting your comment.
Please prove you're not a robot