วันพุธที่ 17 มกราคม พ.ศ. 2561

Bluetooth Arduino: SawTooth Signal sent by Arduino to a Data Acquisition...



Secrets of Arduino PWM

Pulse-width modulation (PWM) can be implemented on the Arduino in several ways. This article explains simple PWM techniques, as well as how to use the PWM registers directly for more control over the duty cycle and frequency. This article focuses on the Arduino Diecimila and Duemilanove models, which use the ATmega168 or ATmega328.If you're unfamiliar with Pulse Width Modulation, see the tutorial. Briefly, a PWM signal is a digital square wave, where the frequency is constant, but that fraction of the time the signal is on (the duty cycle) can be varied between 0 and 100%.
PWM examples
PWM has several uses:

  • Dimming an LED
  • Providing an analog output; if the digital output is filtered, it will provide an analog voltage between 0% and 100% .
  • Generating audio signals.
  • Providing variable speed control for motors.
  • Generating a modulated signal, for example to drive an infrared LED for a remote control.

Simple Pulse Width Modulation with analogWrite

The Arduino's programming language makes PWM easy to use; simply call analogWrite(pin, dutyCycle), where dutyCycle is a value from 0 to 255, and pin is one of the PWM pins (3, 5, 6, 9, 10, or 11). The analogWrite function provides a simple interface to the hardware PWM, but doesn't provide any control over frequency. (Note that despite the function name, the output is a digital signal.)Probably 99% of the readers can stop here, and just use analogWrite, but there are other options that provide more flexibility.

Bit-banging Pulse Width Modulation

You can "manually" implement PWM on any pin by repeatedly turning the pin on and off for the desired times. e.g.
void setup()
{
  pinMode(13, OUTPUT);
}

void loop()
{
  digitalWrite(13, HIGH);
  delayMicroseconds(100); // Approximately 10% duty cycle @ 1KHz
  digitalWrite(13, LOW);
  delayMicroseconds(900);
}
This technique has the advantage that it can use any digital output pin. In addition, you have full control the duty cycle and frequency. One major disadvantage is that any interrupts will affect the timing, which can cause considerable jitter unless you disable interrupts. A second disadvantage is you can't leave the output running while the processor does something else. Finally, it's difficult to determine the appropriate constants for a particular duty cycle and frequency unless you either carefully count cycles, or tweak the values while watching an oscilloscope.

Using the ATmega PWM registers directly

The ATmega168P/328P chip has three PWM timers, controlling 6 PWM outputs. By manipulating the chip's timer registers directly, you can obtain more control than the analogWrite function provides.The AVR ATmega328P datasheet provides a detailed description of the PWM timers, but the datasheet can be difficult to understand, due to the many different control and output modes of the timers. The following attempts to clarify the use of the timers.

The ATmega328P has three timers known as Timer 0, Timer 1, and Timer 2. Each timer has two output compare registers that control the PWM width for the timer's two outputs: when the timer reaches the compare register value, the corresponding output is toggled. The two outputs for each timer will normally have the same frequency, but can have different duty cycles (depending on the respective output compare register).

Each of the timers has a prescaler that generates the timer clock by dividing the system clock by a prescale factor such as 1, 8, 64, 256, or 1024. The Arduino has a system clock of 16MHz and the timer clock frequency will be the system clock frequency divided by the prescale factor. Note that Timer 2 has a different set of prescale values from the other timers.

The timers are complicated by several different modes. The main PWM modes are "Fast PWM" and "Phase-correct PWM", which will be described below. The timer can either run from 0 to 255, or from 0 to a fixed value. (The 16-bit Timer 1 has additional modes to supports timer values up to 16 bits.) Each output can also be inverted.

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.

Timer Registers

Several registers are used to control each timer. The Timer/Counter Control Registers TCCRnA and TCCRnB hold the main control bits for the timer. (Note that TCCRnA and TCCRnB do not correspond to the outputs A and B.) These registers hold several groups of bits:
  • Waveform Generation Mode bits (WGM): these control the overall mode of the timer. (These bits are split between TCCRnA and TCCRnB.)
  • Clock Select bits (CS): these control the clock prescaler
  • Compare Match Output A Mode bits (COMnA): these enable/disable/invert output A
  • Compare Match Output B Mode bits (COMnB): these enable/disable/invert output B
The Output Compare Registers OCRnA and OCRnB set the levels at which outputs A and B will be affected. When the timer value matches the register value, the corresponding output will be modified as specified by the mode.The bits are slightly different for each timer, so consult the datasheet for details. Timer 1 is a 16-bit timer and has additional modes. Timer 2 has different prescaler values.



Fast PWM

In the simplest PWM mode, the timer repeatedly counts from 0 to 255. The output turns on when the timer is at 0, and turns off when the timer matches the output compare register. The higher the value in the output compare register, the higher the duty cycle. This mode is known as Fast PWM Mode.
The following diagram shows the outputs for two particular values of OCRnA and OCRnB. Note that both outputs have the same frequency, matching the frequency of a complete timer cycle.
Fast PWM Mode
The following code fragment sets up fast PWM on pins 3 and 11 (Timer 2). To summarize the register settings, setting the waveform generation mode bits WGM to 011 selects fast PWM. Setting the COM2A bits and COM2B bits to 10 provides non-inverted PWM for outputs A and B. Setting the CS bits to 100 sets the prescaler to divide the clock by 64. (Since the bits are different for the different timers, consult the datasheet for the right values.) The output compare registers are arbitrarily set to 180 and 50 to control the PWM duty cycle of outputs A and B. (Of course, you can modify the registers directly instead of using pinMode, but you do need to set the pins to output.)
pinMode(3, OUTPUT);
  pinMode(11, OUTPUT);
  TCCR2A = _BV(COM2A1) | _BV(COM2B1) | _BV(WGM21) | _BV(WGM20);
  TCCR2B = _BV(CS22);
  OCR2A = 180;
  OCR2B = 50;
On the Arduino Duemilanove, these values yield:
  • Output A frequency: 16 MHz / 64 / 256 = 976.5625Hz
  • Output A duty cycle: (180+1) / 256 = 70.7%
  • Output B frequency: 16 MHz / 64 / 256 = 976.5625Hz
  • Output B duty cycle: (50+1) / 256 = 19.9%
The output frequency is the 16MHz system clock frequency, divided by the prescaler value (64), divided by the 256 cycles it takes for the timer to wrap around. Note that fast PWM holds the output high one cycle longer than the compare register value.

Phase-Correct PWM

The second PWM mode is called phase-correct PWM. In this mode, the timer counts from 0 to 255 and then back down to 0. The output turns off as the timer hits the output compare register value on the way up, and turns back on as the timer hits the output compare register value on the way down. The result is a more symmetrical output. The output frequency will be approximately half of the value for fast PWM mode, because the timer runs both up and down.
Phase-Correct PWM
The following code fragment sets up phase-correct PWM on pins 3 and 11 (Timer 2). The waveform generation mode bits WGM are set to to 001 for phase-correct PWM. The other bits are the same as for fast PWM.
pinMode(3, OUTPUT);
  pinMode(11, OUTPUT);
  TCCR2A = _BV(COM2A1) | _BV(COM2B1) | _BV(WGM20);
  TCCR2B = _BV(CS22);
  OCR2A = 180;
  OCR2B = 50;
On the Arduino Duemilanove, these values yield:
  • Output A frequency: 16 MHz / 64 / 255 / 2 = 490.196Hz
  • Output A duty cycle: 180 / 255 = 70.6%
  • Output B frequency: 16 MHz / 64 / 255 / 2 = 490.196Hz
  • Output B duty cycle: 50 / 255 = 19.6%
Phase-correct PWM divides the frequency by two compared to fast PWM, because the timer goes both up and down. Somewhat surprisingly, the frequency is divided by 255 instead of 256, and the duty cycle calculations do not add one as for fast PWM. See the explanation below under "Off-by-one".

Varying the timer top limit: fast PWM

Both fast PWM and phase correct PWM have an additional mode that gives control over the output frequency. In this mode, the timer counts from 0 to OCRA (the value of output compare register A), rather than from 0 to 255. This gives much more control over the output frequency than the previous modes. (For even more frequency control, use the 16-bit Timer 1.)Note that in this mode, only output B can be used for PWM; OCRA cannot be used both as the top value and the PWM compare value. However, there is a special-case mode "Toggle OCnA on Compare Match" that will toggle output A at the end of each cycle, generating a fixed 50% duty cycle and half frequency in this case. The examples will use this mode.

In the following diagram, the timer resets when it matches OCRnA, yielding a faster output frequency for OCnB than in the previous diagrams. Note how OCnA toggles once for each timer reset.
Fast PWM Mode with OCRA top
The following code fragment sets up fast PWM on pins 3 and 11 (Timer 2), using OCR2A as the top value for the timer. The waveform generation mode bits WGM are set to to 111 for fast PWM with OCRA controlling the top limit. The OCR2A top limit is arbitrarily set to 180, and the OCR2B compare register is arbitrarily set to 50. OCR2A's mode is set to "Toggle on Compare Match" by setting the COM2A bits to 01.

pinMode(3, OUTPUT);
  pinMode(11, OUTPUT);
  TCCR2A = _BV(COM2A0) | _BV(COM2B1) | _BV(WGM21) | _BV(WGM20);
  TCCR2B = _BV(WGM22) | _BV(CS22);
  OCR2A = 180;
  OCR2B = 50;
On the Arduino Duemilanove, these values yield:
  • Output A frequency: 16 MHz / 64 / (180+1) / 2 = 690.6Hz
  • Output A duty cycle: 50%
  • Output B frequency: 16 MHz / 64 / (180+1) = 1381.2Hz
  • Output B duty cycle: (50+1) / (180+1) = 28.2%
Note that in this example, the timer goes from 0 to 180, which takes 181 clock cycles, so the output frequency is divided by 181. Output A has half the frequency of Output B because the Toggle on Compare Match mode toggles Output A once each complete timer cycle.

Varying the timer top limit: phase-correct PWM

Similarly, the timer can be configured in phase-correct PWM mode to reset when it reaches OCRnA.
Phase-Correct PWM with OCRA top
The following code fragment sets up phase-correct PWM on pins 3 and 11 (Timer 2), using OCR2A as the top value for the timer. The waveform generation mode bits WGM are set to to 101 for phase-correct PWM with OCRA controlling the top limit. The OCR2A top limit is arbitrarily set to 180, and the OCR2B compare register is arbitrarily set to 50. OCR2A's mode is set to "Toggle on Compare Match" by setting the COM2A bits to 01.
pinMode(3, OUTPUT);
  pinMode(11, OUTPUT);
  TCCR2A = _BV(COM2A0) | _BV(COM2B1) | _BV(WGM20);
  TCCR2B = _BV(WGM22) | _BV(CS22);
  OCR2A = 180;
  OCR2B = 50;
On the Arduino Duemilanove, these values yield:
  • Output A frequency: 16 MHz / 64 / 180 / 2 / 2 = 347.2Hz
  • Output A duty cycle: 50%
  • Output B frequency: 16 MHz / 64 / 180 / 2 = 694.4Hz
  • Output B duty cycle: 50 / 180 = 27.8%
Note that in this example, the timer goes from 0 to 180 and back to 0, which takes 360 clock cycles. Thus, everything is divided by 180 or 360, unlike the fast PWM case, which divided everything by 181; see below for details.

Off-by-one

You may have noticed that fast PWM and phase-correct PWM seem to be off-by-one with respect to each other, dividing by 256 versus 255 and adding one in various places. The documentation is a bit opaque here, so I'll explain in a bit of detail.Suppose the timer is set to fast PWM mode and is set to count up to an OCRnA value of 3. The timer will take on the values 012301230123... Note that there are 4 clock cycles in each timer cycle. Thus, the frequency will be divided by 4, not 3. The duty cycle will be a multiple of 25%, since the output can be high for 0, 1, 2, 3, or 4 cycles out of the four. Likewise, if the timer counts up to 255, there will be 256 clock cycles in each timer cycle, and the duty cycle will be a multiple of 1/256. To summarize, fast PWM divides by N+1 where N is the maximum timer value (either OCRnA or 255).

Now consider phase-correct PWM mode with the timer counting up to an OCRnA value of 3. The timer values will be 012321012321... There are 6 clock cycles in each timer cycle (012321). Thus the frequency will be divided by 6. The duty cycle will be a multiple of 33%, since the output can be high for 0, 2, 4, or 6 of the 6 cycles. Likewise, if the timer counts up to 255 and back down, there will be 510 clock cycles in each timer cycle, and the duty cycle will be a multiple of 1/255. To summarize, phase-correct PWM divides by 2N, where N is the maximum timer value.

The second important timing difference is that fast PWM holds the output high for one cycle longer than the output compare register value. The motivation for this is that for fast PWM counting to 255, the duty cycle can be from 0 to 256 cycles, but the output compare register can only hold a value from 0 to 255. What happens to the missing value? The fast PWM mode keeps the output high for N+1 cycles when the output compare register is set to N so an output compare register value of 255 is 100% duty cycle, but an output compare register value of 0 is not 0% duty cycle but 1/256 duty cycle. This is unlike phase-correct PWM, where a register value of 255 is 100% duty cycle and a value of 0 is a 0% duty cycle.

Timers and the Arduino

The Arduino supports PWM on a subset of its output pins. It may not be immediately obvious which timer controls which output, but the following table will clarify the situation. It gives for each timer output the output pin on the Arduino (i.e. the silkscreened label on the board), the pin on the ATmega chip, and the name and bit of the output port. For instance Timer 0 output OC0A is connected to the Arduino output pin 6; it uses chip pin 12 which is also known as PD6.
Timer outputArduino outputChip pinPin name
OC0A612PD6
OC0B511PD5
OC1A915PB1
OC1B1016PB2
OC2A1117PB3
OC2B35PD3
The Arduino performs some initialization of the timers. The Arduino initializes the prescaler on all three timers to divide the clock by 64. Timer 0 is initialized to Fast PWM, while Timer 1 and Timer 2 is initialized to Phase Correct PWM. See the Arduino source file wiring.cfor details.

The Arduino uses Timer 0 internally for the millis() and delay()functions, so be warned that changing the frequency of this timer will cause those functions to be erroneous. Using the PWM outputs is safe if you don't change the frequency, though.

The analogWrite(pin, duty_cycle) function sets the appropriate pin to PWM and sets the appropriate output compare register to duty_cycle (with the special case for duty cycle of 0 on Timer 0). The digitalWrite() function turns off PWM output if called on a timer pin. The relevant code is wiring_analog.c and wiring_digital.c.

If you use analogWrite(5, 0) you get a duty cycle of 0%, even though pin 5's timer (Timer 0) is using fast PWM. How can this be, when a fast PWM value of 0 yields a duty cycle of 1/256 as explained above? The answer is that analogWrite "cheats"; it has special-case code to explicitly turn off the pin when called on Timer 0 with a duty cycle of 0. As a consequency, the duty cycle of 1/256 is unavailable when you use analogWrite on Timer0, and there is a jump in the actual duty cycle between values of 0 and 1.

Some other Arduino models use dfferent AVR processors with similar timers. The Arduino Mega uses the ATmega1280 (datasheet), which has four 16-bit timers with 3 outputs each and two 8-bit timers with 2 outputs each. Only 14 of the PWM outputs are supported by the Arduino Wiring library, however. Some older Arduino models use the ATmega8 (datasheet), which has three timers but only 3 PWM outputs: Timer 0 has no PWM, Timer 1 is 16 bits and has two PWM outputs, and Timer 2 is 8 bits and has one PWM output.

Troubleshooting

It can be tricky to get the PWM outputs to work. Some tips:
  • You need to both enable the pin for output and enable the PWM mode on the pin in order to get any output. I.e. you need to do pinMode() and set the COM bits.
  • The different timers use the control bits and prescaler differently; check the documentation for the appropriate timer.
  • Some combinations of bits that you might expect to work are reserved, which means if you try to use them, they won't work. For example, toggle mode doesn't work with fast PWM to 255, or with output B.
  • Make sure the bits are set the way you think. Bit operations can be tricky, so print out the register values and make sure they are what you expect.
  • Make sure you're using the right output pins. See the table above.
  • You'll probably want a decoupling capacitor to avoid spikes on the output.
An oscilloscope is very handy for debugging PWM if you have access to one. If you don't have one, I recommend using your sound card and a program such as xoscope.

Conclusion

I hope this article helps explain the PWM modes of the Arduino. I found the documentation of the different modes somewhat opaque, and the off-by-one issues unexplained. Please let me know if you encounter any errors.

62 comments:


Anonymous said...
Thank you for the article!

As a beginning Arduino user, this is very helpful!
Didier said...
Excellent paper. Many Thanks
Jason said...
exactly what I needed! thanks!
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!
Anonymous said...
Excellent article, I've been going through some example code but this made it all come together.

Thanks,
Mike
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.
monty 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
Steve Gough 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.
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?
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.
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.
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
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.
Anonymous said...
but how can i get it to make a 38khz freq with 50% duty cicle?
Quarkninja said...
Very informative! Excellent Work! Thanks!
coopermaa 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
Sami Mughal 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
Anonymous said...
Great summary and guide for using the ATmega328p timers! Thanks for taking the time to put this together. Very helpful.
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.
coopermaa said...
_BV is a macro defined in avr-libc:

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

see http://194.81.104.27/~brian/microprocessor/BVMacro.pdf
Anonymous said...
Thank you very much, this is the best condensed reference I have seen, all clear and to the point!!!
mitch deoudes said...
The version of this article posted at arduino.cc is missing all of the diagrams except the first one.
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.
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!
Sami Mughal 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.
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
Сергей Орляк 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!
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.
Gabriel 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/
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!!
Gabriel 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?
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/
Rohit Varma 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
emgab 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
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
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)
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)
Gabriel 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/
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;
SOLID said...
Solved it.... All by myself... thanks to this tutorial that clarified the avr guide... SUPER>....
Александр Собецкий said...
Solid, please tell me the solution
s0bes@mail.ru
s0bes68@gmail.com
Paul Moore 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?
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.
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.
Mark Shanks said...
Ah, thanks Gabriel, my brain didn't see the 'microseconds' after delay. My bad.
Saytinh said...
Great article. Thanks for sharing your knowledge.

Can you give more instruction to make a oscilloscope from a sound card?
gurumoorthi said...
CAN YOU PLEASE SAY HOW TO STOP NEGATIVE SIDE OUTPUT OF PWM
Paul 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%.
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. 
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
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.
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.
Ravi kumar said...
Is it possible to generate 38khz digital pulse with arduino.
sergio massip said...
Excellent explanation !!
Thank, It have helped me a lot.
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?
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.
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.
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.
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.
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.
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?
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.

ไม่มีความคิดเห็น:

แสดงความคิดเห็น