References to Study:
- Secrets of Arduino PWM, by Ken Shirriff
- ATmega328 Datasheet (660 pg version from 11/2015)
- ATmega168/328-Arduino Pin Mapping
Here's some oscilloscope screenshots of the output on Pin 3 produced by an Arduino Nano running the code below.
![]() |
| Rising edge to rising edge: Δx = 100us |
![]() |
| Zoomed-in view of high pulse. Rising edge to falling edge = 1us |
ADVERTISEMENT:
Here's the code. Don't be put off by it. Literally, it's only 5 key lines of code, surrounded by a little fluff and lots of comments. The 5 key lines are setting the pinMode, TCCR2A, TCCR2B, OCR2A, and OCR2B. Take a look:
/*
pulse_1us_100us
- use timer2 to make a 1us HIGH pulse followed by 99us LOW, for a duty cycle of
1us/(99+1)us = 1us/100us = 1%, and a period of 100us
By Gabriel Staples
- for my email address, click "Contact Me" link at top of my website here:
http://www.ElectricRCAircraftGuy.com/
References:
- Secrets of Arduino PWM: http://www.righto.com/2009/07/secrets-of-arduino-pwm.html
- ATmega328 Datasheet (660 pg version from 11/2015): http://www.atmel.com/images/Atmel-8271-8-bit-AVR-Microcontroller-ATmega48A-48PA-88A-88PA-168A-168PA-328-328P_datasheet_Complete.pdf
- https://www.arduino.cc/en/Hacking/PinMapping168
*/
void setup()
{
//set 1us HIGH pulse followed by 99us LOW pulse (1% duty cycle) on pin 3
pinMode(3, OUTPUT); //Note: pin 3 is OC2B <--so use port B, not A; see https://www.arduino.cc/en/Hacking/PinMapping168
//Set timer2 clock with prescaler 8 (0.5us per count, so 256 counts --> 128us); datasheet pg. 157: CS22/CS21/CS20 = 0/1/0
//Set to Fast PWM with Top==OCRA; datasheet p. 155: Mode 7; WGM22/WGM21/WGM20 = 1/1/1
//Set OC2B to non-inverting mode; Table 18-6, pg. 154: COM2B1/COM2B0 = 1/0
//TCCR2A: pg. 153; TCCR2B: pg. 156
TCCR2A = _BV(COM2B1) | _BV(WGM21) | _BV(WGM20);
TCCR2B = _BV(WGM22) | _BV(CS21);
//Set period to 100us and high pulse time to 1us
//-Note that the high time you set here is OCR2B + 1 clock cycles, so OCR2B + 1 in this case
// is 2, which is 1us, since each clock count is 0.5us
//-To get clock cycles we must multiply desired microseconds x 2 (again, with a prescaler
// of 8 and a 16MHz clock, each clock count is 0.5us)
//-For this Fast PWM mode, note that the period is OCR2A + 1 also
//-For reasons for the above, see "off-by-one" here: http://www.righto.com/2009/07/secrets-of-arduino-pwm.html
//--Ex: Notice where Output B duty cycle is calculated in his example here:
// "Output B duty cycle: (50+1) / (180+1) = 28.2%"
//--So, for the reasons above, we must subtract 1 below to get the right period and duty cycles
byte pd = 100; //us; period
byte highPulseTime = 1; //us
OCR2A = pd*2 - 1; //set period
OCR2B = highPulseTime*2 - 1; //set high time
}
void loop()
{
}
By Gabriel StaplesWritten: 31 Mar 2017
Last Updated: 1 Apr 2017
History (newest on top):
20170401 - minor wording additions for clarity and emphasis that the code is only 5 key lines
Other Articles:
- Arduino micros() function with 0.5us precision - using my Timer2_Counter Library
- Arduino-like millisecond (ms) and microsecond (us)-resolution timestamps in Python: millis(), micros(), delay(), & delayMicroseconds()
- BattleBots Season 2 "Buzz" Fire Drone for Team Caustic Creations, with Team Interviews & fire-shooting Videos
- The Power of Arduino
- Restoring/Recharging Over-discharged LiPo (Lithium Polymer) Batteries!
- Parallel Charging Your LiPo Batteries
- Using the Arduino Uno’s built-in 10-bit to 16+-bit ADC (Analog to Digital Converter)--an Article on Oversampling
- Beginner RC Airplane Setup


No comments:
Post a Comment
Thanks for your comment or question! If it is a question, I will try to get back to you quickly. Notice to spammers: I personally remove all spam promptly and report spammers to Google, so please don't do it.
Note: some HTML tags are allowed in your comments. To learn how to add bold (<b>...</b>), italics (<i>...</i>), or hyperlinks (<a href="URL">NAME</a>) to your comments, read here.
~Sincerely, Gabriel Staples.
P.S. Yo hablo español también. Je parle français aussi. (I speak Spanish & French too).