Posted by on Jan 7, 2012 in Atmel AVR, Microcontrollers | 163 comments # AVR Timers – PWM Mode – Part II This article is in continuation with the previous PWM post. Learn how to program the timers to operate in PWM mode! So let’s begin!

Hello folks! Long time no see! :)

In my previous post, we have discussed the basic concepts of PWM. Let’s summarize it first:

• PWM stands for Pulse Width Modulation.
• It can be generated by comparing predetermined waveform with a reference voltage level or by making simple analog circuits.
• Duty Cycle of a PWM waveform is given by the following relation.
• There are three modes of PWM operation – Fast PWM, Phase Correct PWM and Frequency and Phase Correct PWM
• How to choose timer, operation mode and compare output mode for generating the desired PWM.
So now, without much hassle, let’s see how to implement it using the AVR microcontrollers. Before we proceed, I suggest you to go through my previous posts on Timers and PWM.

# Problem Statement

Let us take a problem statement. We need to generate a 50 Hz PWM signal having 45% duty cycle.

### Analysis

Given that

`Frequency = 50 Hz`

In other words, the time period, T

`T = T(on) + T(off) = 1/50 = 0.02 s = 20 ms`

Also, given that

`Duty Cycle = 45%`

Thus, solving according to equation given above, we get

```T(on)  = 9 ms
T(off) = 11 ms```

Now, this can be achieved in two ways:

1. Use Timer in CTC Mode
2. Use Timer in PWM Mode

# Methodology – CTC Mode

Okay, so I won’t be writing any code here (just the pseudo code). I assume that after reading my previous posts, you are smart enough to write one yourself! We will discuss only the concepts.

Firstly, choose a suitable timer. For this application, we can choose any of the three timers available in ATMEGA32. Choose a suitable prescaler. Then set up the timer and proceed as usual. The catch lies here is that you need to update the compare value of OCRx register everytime. One such way is discussed in the pseudo code given below.

This is analogous to the traditional LED flasher, except the fact that the on and off times are different.

### Pseudo Code

```#include <avr/io.h>
#include <avr/interrupt.h>

uint8_t count = 0;               // global counter

// initialize timer, interrupt and variable
void timerX_init()
{
// set up timerX with suitable prescaler and CTC mode
// initialize counter
// initialize compare value
// enable compare interrupt
// enable global interrupts
}

// process the ISR that is fired
ISR (TIMERx_COMPA_vect)
{
// do whatever you want to do here
// say, increment the global counter
count++;

// check for the global counter
// if count == odd, delay required = 11 ms
// if count == even, delay required = 9 ms
// thus, the value of the OCRx should be constantly updated
if (count % 2 == 0)
OCRx = 9999;      // calculate and substitute appropriate value
else
OCRx = 10999;     // calculate and substitute appropriate value
}

int main(void)
{
// initialize the output pin, say PC0
DDRC |= (1 << 0);

// initialize timerX
timerX_init();

// loop forever
while(1)
{
// do nothing

}
}```

Now this is one method. And it’s very inefficient. You can increase its efficiency by writing a better C code (syntax-wise), however the concept remains the same. If you have any other method/concept, you are most welcome to share it here! :)

UPDATE: One of the readers of maxEmbedded, “coolpales” has written this code, and it worked for him.

Please note that this code not tested yet! So, if any of you is trying it out, do post your results here, I would be happy to see them! :)

# Methodology – PWM Mode

Okay, so now lets learn about the PWM mode. The PWM Mode in AVR is hardware controlled. This means that everything, by everything I mean “everything”, is done by the AVR CPU. All you need to do is to initialize and start the timer, and set the duty cycle! Cool, eh?! Let’s learn how!

Here, I have used Timer0 of ATMEGA32 for demonstration. You can choose any other other timer or AVR microcontroller as well. Now let’s have a look at the registers.

## TCCR0 – Timer/Counter0 Control Register

We have come across this register in my Timer0 tutorial. Here, we will learn how to set appropriate bits to run the timer in PWM mode.

We will discuss only those bits which are of interest to us now.

## OCR0 – Output Compare Register

We have come across even this register in my Timer0 tutorial. We use this register to store the compare value. But when we use Timer0 in PWM mode, the value stored in it acts as the duty cycle (obviously!). In the problem statement, its given that the duty cycle is 45%, which means

`OCR0 = 45% of 255 = 114.75 = 115`

And that’s it! Now we are ready to write a code for it! :)

## Edit: Note

The following code discusses how to create a PWM signal of a desired duty cycle. If you wish to change its frequency, you need to alter the TOP value, which can be done using the ICRx register (which is not supported by 8-bit timers). For 16-bit Timer1, it can be varied using ICR1A. I will discuss about this soon when we discuss about servo control.

## Code

So here goes the code. To learn about I/O port operations in AVR, view this. To know about bit manipulations, view this. To learn how to use AVR Studio 5, view this. To learn how this code is structured, view the previous TIMER0 post.

```#include <avr/io.h>
#include <util/delay.h>
void pwm_init()
{
// initialize TCCR0 as per requirement, say as follows
TCCR0 |= (1<<WGM00)|(1<<COM01)|(1<<WGM01)|(1<<CS00);

// make sure to make OC0 pin (pin PB3 for atmega32) as output pin
DDRB |= (1<<PB3);
}

void main()
{
uint8_t duty;
duty = 115;       // duty cycle = 45% of 255 = 114.75 = 115

// initialize timer in PWM mode
pwm_init();

// run forever
while(1)
{
OCR0 = duty;
}
}
```

# Problem Statement

So now, let’s take another problem statement. This one is going to be a more of a practical stuff unlike the previous one!

Let’s take the traditional LED flasher where we need to blink an LED at a particular frequency. But hey, wait, didn’t we discuss it long back in this post (scroll down towards the end)? Hmm, so let’s modify it so as to incorporate PWM. Unlike the traditional LED flasher (where LEDs are either ON or OFF), lets make it glow at the maximum brightness, and then slowly decrease its brightness till it reaches zero, and then again increase its brightness slowly till it becomes maximum.

### Analysis and Code

So how do we do it? Yes, you guessed it right! Decrease the duty cycle slowly from 255 to zero, and then increase it from zero to 255. Depending upon the duty cycle, the voltage applied to the LED varies, and thus the brightness. The following formula gives the relation between voltage and duty cycle. So here goes the code. I won’t explain it, you can decode it yourself. To learn about I/O port operations in AVR, view this. To know about bit manipulations, view this. To learn how to use AVR Studio 5, view this. To learn how this code is structured, view the previous TIMER0 post.

```// program to change brightness of an LED
// demonstration of PWM

#include <avr/io.h>
#include <util/delay.h>

// initialize PWM
void pwm_init()
{
// initialize timer0 in PWM mode
TCCR0 |= (1<<WGM00)|(1<<COM01)|(1<<WGM01)|(1<<CS00);

// make sure to make OC0 pin (pin PB3 for atmega32) as output pin
DDRB |= (1<<PB3);
}

void main()
{
uint8_t brightness;

// initialize timer0 in PWM mode
pwm_init();

// run forever
while(1)
{
// increasing brightness
for (brightness = 0; brightness < 255; ++brightness)
{
// set the brightness as duty cycle
OCR0 = brightness;

// delay so as to make the user "see" the change in brightness
_delay_ms(10);
}

// decreasing brightness
for (brightness = 255; brightness > 0; --brightness)
{
// set the brightness as duty cycle
OCR0 = brightness;

// delay so as to make the user "see" the change in brightness
_delay_ms(10);
}

// repeat this forever
}
}```

So here ends my another much awaited and long tutorial! Next up.. Serial Communication! See you around!! :)

And yeah, if you have any suggestions, doubts, constructive criticisms, etc, you are most welcome to drop a note  below! Subscribe to my blog or grab the RSS Feeds to stay updated!

1. Great job!!! Thanks for your time and for sharing you knowledge. These pages were very useful for me.
Thanks.

• Thank you! :)

2. Nice tutorials… Keep on…

• Thank you Karthick! :)

3. Using Timer0 PWM Mode , The Required time period of the pulse to be generated is 20ms Timer0 is pre-scaled to 0 and 255 counts will give us a time period of 16 micro-seconds. If we do pre-scale Tmer0 to 1024 the max. time period we can get is 16 milliseconds. I am thing of controlling the moving the servo to various position using Timer0 . servo requires 20ms compulsory .

• Hi BhanuKiran,
Servos cannot be controlled using Timer0, since it is 8 bit timer and will give you very low resolution. Try using the 16 bit Timer1 for this purpose.

4. my ctc pwm code, simple but it worked :)

• Hi coolpales,
Sorry, seems like I missed to see this post. I know its late, but thanks for trying it out! I’m adding the link to this code in my post above. Thanks! :)

5. Can you help me?
I want to change this code to ATmega1280.
But i can’t.Pls

6. sir plz can u explain me the concept of _delay_loop_2() .. how to use in for loop to get some appproximate delay in program execution??

• `void _delay_loop_2 (uint16_t __count) `
Delay loop using a 16-bit counter `__count`, so up to 65536 iterations are possible. (The value 65536 would have to be passed as 0.) The loop executes four CPU cycles per iteration, not including the overhead the compiler requires to setup the counter register pair. Thus, at a CPU speed of 1 MHz, delays of up to about 262.1 milliseconds can be achieved.
Try looking up the nongnu documentation here.

7. sir, how to find out the relation between pulse width and servo angle for a particular servo.. m having a vigor VS-2 servo..?

• Hi Shubham,
Usually the pulse width is in the range of 600us to 2100us for an angle of 0 degrees through 180 degrees. However the exact value depends upon the servo. I would suggest to go for hit and trial method. You already know this range, now use hit and trail to determine the exact value.

8. is it possible to use all 3 timers in a single code wile dimming a rgb led

• Hi Johney
Its a very nice question. The answer to your question is Yes.
Actually operation of timers depends upon the timer interrupt
available to them, and in all the microcontrollers each timer
is assigned with its own timer interrupt, whose operation is
independent of other timer interrupts.
So you can use the all the timers at the same time.

• thanx

9. brilliant tutorials.
Although I could not find the tutorial for servo control. Can you upload it ?
thanks

• Hi Prajval,
It is on our list! It should be up by next month. Thanks for your suggestion! :)

10. Hey guys, I want to change the TOP value of timer 1, 10 bit PWM to be lower to get a frequency of 20KHz for my DC motor, I know we need to use something like input capture but I have no idea how to use it, can someone help me?

11. Atmega datasheet states that frequency of the PWM equals f_pwm=(f_cpu)/(256*prescaler), so with 1MHz internal clock and no prescaler f_pwm = 3906Hz.
How did you ensure that the PWM will run at 50Hz ? I cant see it anywhere in the code, unless you’re using some super slow external oscillator

• Hello!
The datasheet states Frequency of PWM= f(clock)/(prescaler*(1+TOP)). Since TOP is variable as according to the PWM Mode one is using, and also the value one sets in the OCRx or ICRx, so you can get the desired frequency.
The one you are talking about is when TOP is 0xFF.

12. Can we have at output also variable voltage ex. 1-12V?
Can you advice how to do it?

• Hi Piotr,
I didn’t get you. Do you want a variable output range of 1-12 volts from the microcontroller? Okay, so here is something I want you to try. Generate a PWM signal at one of the pins of the microcontroller, and then take a multimeter/voltmeter and measure the voltage at that pin wrt GND. What do you observe?

You’ll observe that the voltage varies in between VCC and GND. The multimeter shows the average voltage at that point. If you want voltage as high as 12v, then you must connect a driver or relay at the output of the PWM pin. Check out this post where we have connected a motor driver to get a 12v output. You can use a similar setup if you want. You can also replace the motor driver with a 12v relay. It will give you a variable output in the range of GND and +12v.

13. Hi,

when driving a DC motor, should one use fast PWM or phase correct PWM?

• Hi Sue,
It doesn’t matter as far as driving DC motors is concerned.
-Max

14. please do a blog on pwm using 16-bit atmega timer.

• Hello Rabia,
If you have followed all my timer tutorials, you shouldn’t have trouble writing the code yourself.

15. Well lemme start my sayin am a newbie and dude that was one awesome way to explain …. am doing my final year project on LED lamps and am on the process of designing a dimmer circuit.Can u please tell me how to generate a unit step saw tooth wave in a microcontroller,Compare it with a given input wave and obtain the duty cycle of the thus generated PWM wave? am looking forward for your reply…

• Ara,
You don’t need to worry about generating the sawtooth waveform, comparison and waveform generation. Simply follow my tutorial and specify the desired duty cycle. All these things happen internally and you get the desired waveform directly.

16. sir, will u post the article on servo motor control..on the web site…if yes, when? thank you

17. hi,
how turn on 2 LEDs
but from the start same time
use ATMEGA 8535/16

• I can’t understand the challenge you’re facing. What’s the problem?
Technically speaking, this is impossible, since AVR CPU is a single core CPU and it can process just one instruction at a time. However, it is possible logically since the time lag between the two timers would be so small that it can be neglected.

18. Hi, Mayank. I hope you can help me.
I have to control 2 DC motors with the Atmega88PA. I’m going to control them with L298. I want to know how to do the code. I was thinking about using a “switch case” instruction for changing the duty cycle between 25,50,75 and 100% (I’m not sure if 100% is possible). Is it correct (the switch case)? If so, how could I prove it? Increasing, decreasing the brightness of LED’s (like your second example) would be a good way? And the parameters to change the duty cycle could be 2 switchs?

• Sounds reasonable! As long as your logic is correct, and you follow a valid GNU C syntax, you should be good.

• Other thing. In your second code I don’t see the PORT to see the LED. Does OC0 act like a PORT?

• OC0 doesn’t act like a PORT, instead it controls/changes the PORT values.

• Thanks!
My last question, I won’t bother you anymore. How should I select the frequency of work for my motors? Do I need it ot it’s not necessary?

• Since you are controlling you motors using PWM, it does need a frequency. Frequency as low as 50Hz should work for DC motors. Try it out.

19. Heyy. I wanted to know if i can use all 4 pwm pins of atmega16 simultaneously. If yes, how???

• Yes you can. Just program each one of them separately and run them together.

20. hi mayank…all your tutorials are superb… just this one thing… when will you post the tutorials on servo motor control….? looking forward for it…

• Thank you! Pretty soon.. it’s coming! :)

This site uses Akismet to reduce spam. Learn how your comment data is processed.