In this tutorial we will set up the TIMER0 in fast pwm mode and use it to generate PWM signals of varying duty cycles. In this way we would be generating analog signals of voltages between 0 and 5v. In the example we will connect this output to a LED and see how it varies its brightness. Please see the previous tutorials on PWM and TIMERs before reading this tutorial.
PWM
Timers
Setting Up TIMER0 in Fast PWM mode
Setting up the TIMER0 in fast pwm mode is very easy and just require one line of code. You only need to deal with one register named TCCR0 (Timer Counter Control Register For Timer 0). You just need to set up various bits in it to get the required setting. The various bits of TCCR0 is given below.
TCCR0
This register is used for configuring the TIMER0. See Timer Tutorial for more info. The explanation of various bits of this register is as follows.
Bit No |
7 |
6 |
5 |
4 |
3 |
2 |
1 |
0 |
Name |
FOC0 |
WGM00 |
COM01 |
COM00 |
WGM01 |
CS02 |
CS01 |
CS00 |
Initial Val |
0 |
0 |
1 |
0 |
0 |
0 |
0 |
0 |
(Note The Bits in RED are discussed here)
WGM - Wave Form Generation Mode
The table below shows the various modes supported by TIMER0. We have covered Normal mode in "Timer0 tutorial" and CTC mode in "Timers In compare mode" tutorial. And this tutorial we are interested in Fast PWM mode.
Mode |
WGM00 |
WGM01 |
Mode Of Operation |
0 |
0 |
0 |
Normal |
1 |
0 |
1 |
PWM Phase Correct |
2 |
1 |
0 |
CTC |
3 |
1 |
1 |
Fast PWM |
From the table it is clear that for Fast PWM we need mode 3. To get it we must set WGM00=1 and WGM01=1
COM - Compare Output Mode
These bits are used to set the Output mode in various Wave form generation mode. For Fast PWM mode these can be used to achieve following output modes.
COM01 |
COM00 |
Output Mode |
0 |
0 |
Normal Port Operation (OC0 disconnected) |
1 |
0 |
RESERVED |
0 |
1 |
Non Inverted PWM |
1 |
1 |
Inverted PWM |
We need the "Non Inverted PWM output mode" so we set COM01=0 and COM00=1
CS - Clock Select
These are used to set an Input Clock for TIMER. We set them as follows to get Ftimer=F_CPU (i.e. no prescalling). See "Timer Tutorial" for more info.
CS02 = 0
CS01 = 0
CS00 = 1
Now the TIMER is in Fast PWM mode to vary its output duty cycle we just need to set the OCR0 (Output Compare Register for Timer 0). For example setting it to 0 will generate PWM with duty cycle 0% (Totally off) while setting it to 128 will generate 50% duty cycle and 255 will generate 100% duty cycle signals.
Note: The output waveform is available in the associated Output Compare Pin of the microcontroller. For example for Timer 0 the associated OC pin is OC0. You can find its location from Pin diagram in datasheet. In ATmega16 and ATmega32 it is on PORTB bit 3, i.e. PB3. This pin must be set to output to get the PWM signals.
Sample Program
The in the following program we set up TIMER0 in fast pwm mode and use the generated PWM signals to vary the brightness of a LED. This is the simplest program to get you started with PWM signal generation. We start with minimum brightness and increase it gradually and then again reduce it gradually to zero. This process is repeated as long as the system is powered.
#include <avr/io.h>
#include <util/delay.h>
void InitPWM()
{
/*
TCCR0 - Timer Counter Control Register (TIMER0)
-----------------------------------------------
BITS DESCRIPTION
NO: NAME DESCRIPTION
--------------------------
BIT 7 : FOC0 Force Output Compare [Not used in this example]
BIT 6 : WGM00 Wave form generartion mode [SET to 1]
BIT 5 : COM01 Compare Output Mode [SET to 1]
BIT 4 : COM00 Compare Output Mode [SET to 0]
BIT 3 : WGM01 Wave form generation mode [SET to 1]
BIT 2 : CS02 Clock Select [SET to 0]
BIT 1 : CS01 Clock Select [SET to 0]
BIT 0 : CS00 Clock Select [SET to 1]
The above settings are for
--------------------------
Timer Clock = CPU Clock (No Prescalling)
Mode = Fast PWM
PWM Output = Non Inverted
*/
TCCR0|=(1<<WGM00)|(1<<WGM01)|(1<<COM01)|(1<<CS00);
//Set OC0 PIN as output. It is PB3 on ATmega16 ATmega32
DDRB|=(1<<PB3);
}
/******************************************************************
Sets the duty cycle of output.
Arguments
---------
duty: Between 0 - 255
0= 0%
255= 100%
The Function sets the duty cycle of pwm output generated on OC0 PIN
The average voltage on this output pin will be
duty
Vout= ------ x 5v
255
This can be used to control the brightness of LED or Speed of Motor.
*********************************************************************/
void SetPWMOutput(uint8_t duty)
{
OCR0=duty;
}
/********************************************************************
Simple Wait Loop
*********************************************************************/
void Wait()
{
_delay_loop_2(3200);
}
void main()
{
uint8_t brightness=0;
//Initialize PWM Channel 0
InitPWM();
//Do this forever
while(1)
{
//Now Loop with increasing brightness
for(brightness=0;brightness<255;brightness++)
{
//Now Set The Brighness using PWM
SetPWMOutput(brightness);
//Now Wait For Some Time
Wait();
}
//Now Loop with decreasing brightness
for(brightness=255;brightness>0;brightness--)
{
//Now Set The Brighness using PWM
SetPWMOutput(brightness);
//Now Wait For Some Time
Wait();
}
}
}
Download Compiled HEX file for ATmega16 / ATmega32 @ 1 MHz
Hardware Setup
To run and test this program you need an AVR MCU (ATmega16 or ATmega32)(ATmega8 won't work!). To keep the hardware simple we will use the MCU with internal 1MHz oscillator (this is default factory setting for new MCUs). We will add a good quality RED LED to output compare pin (OC0) of the MCU. This is PIN no 4 on ATmega16/32 Micros. Vcc PIN (pin 10) is connected to +5v and Gnd PIN(pin 11,31) is connected to gnd. This is not show in diagram.
![]() |
Fig. 1 - A PWM controlled LED |
|
You can program the chip using this simple avr programmer or buy a USB Programmer.
Video
The PWM controlled LED in Action !!!




using which software u draw the circuits.Pls recommmend a
good avr simulation software.
Hello John,
The best avr simulation software is VMLab
http://www.amctools.com/
Its little hard in the begining as there is no GUI circuit maker, you have to make circuit by writting netlist. But don’t get afraid you will quickly get it. And then it will be very powerful tool for you.
@Mitchell
Pls see ATTiny Datasheet for info on Registers. May be the ATtiny TIMER0 DOES NOT have PWM(pls confirm this by datasheet).
Many Modification may be needed to port it as this is for Mega series.
when simulating
in oshon’s software (AVR IDE)
i am not geting the PWM output…….
i am using atmega32
help ……………………
@ Nataraja.
Hello
Please, How can I know whats wrong with ur setup. Assuming that the code is 100% correct, proceed with debuging. Try to spot the problem urself.
Try moving this line to beginning of InitPWM() function
DDRB|=(1<
DDRB|=( 1 << PB3 );
Download Sample Program
the hex file after compiling and this file which u gave
Download Compiled HEX file
dont match !!!!!!!!
Hi, and thank you Avinash for these wonderful tutorials!
Attiny13 has two comparators on timer0, OC0A(PB0, pin 5 of the MCU) and OC0B(PB1, pin 6 of the MCU), in PDIP configuration.
So, you need to change
DDRB |= ( 1 << PB3 ); //PB3 means 3
to
DDRB |= ( 1 << PB0 ); //pin 0 of Port B
Hi Avinash
Fantastic tut.
Thanks for your time.
Sample code that works, wow. Cool
I have already recomended your tute to fellow students at uni.
Regards
microsys
Hi Avinash
Fantastic tut.
Thanks for your time.
Sample code that works, wow. Cool
I have already recomended your tute to fellow students at uni.
australia
Regards
microsys
Very Nice Tutorial on PWM. Thanks a lot.
Regards,
Sandeep
Hello Sandeep,
Thanks!
Dear sir,
I have downloaded VMLAB and installed it. But i don’t know how to use it with WinAVR. Currently i m working with ATMEGA16.
Please help me…
Thank You!
hi avinash
thanks for this great tutorial.
Can you make a programme for PWM at 38 Mhz so that i can use that with TSOP1738.
@sanjay
TSOP requires 38KHz (not MHz).Using PWM we can only generate certain values of frequencies(F_CPU,F_CPU/1024 etc)generally F_CPU is 16 Mhz,so we cant just produce any frequency we wish.
@avinash
is there some way to produce waveforms of desired frequency using avr mcu’s.Also,there is a small webpage error,the link “timer tutorial” under “clock select” points to serial comm tut page.(just a small error!!).
Hey Avinash,
Would like to thank you for the awesum tutorials you have put online for help with AVRs. I am studying in NZ and we are currently working on a path follower robot capable of solving a maze. It is using Atmega8. Was trying to get the PWM working for the robot but am a little confused about the use of timer/counter. Would TCNT2 ( counter 2) which has got both output compare and an 8 bit counter be useful for PWM? Is that the major change I have to do in this code (replacing the registers from TCNT0 to TCNT2) or am I forgettoing something else?
Would be grateful for your help
Cheers
Tanmay
@Tanmay
See datasheet of ATmega8. I recommend use the TIMER1 it has got 2 PWM outputs.
Wonderful tutorial.Just wanted to know how 2 PWM outputs would be more beneficial as explained above?
wll nutzlos i am also in same projct hlp me,in shortest path finding ,no idea how to wrt code for it ,using atmega 128
Thanks a lot sir.
I have no words to say my convenience. The datasheet was craking my head. It was redicules. This was so easy. And very understandable…
Is it possible to produce PWM out of any pin
@Prashanth
Answer: Nothing is Impossible !
y not ?
it is possible , 32 servo controller etc etc
use atmega series MCU’s to control servos at their I/O pins (PWM output)
.
but there are restriction , depends on the application and most of the case’s u have use another MCU,
master salve system kinda ….
.
i have used 30 pins of my ATmega32 lo control servo’s (30 of them)2 pins left for TX,RX
Thanks for the reply.this is exactly wat i have been waiting for
Hello! First of all! Bravo! Very nice job.
My problem is not really starting the PWM, it’s about stopping it.
Let’s say that when I press a button I wish that the PWM cycle to stop.
I tried to CLEAR bits COM1 and COM0 as the datasheet of ATmega16 says “Normal port operation, OC0 disconected”.
Maybe I am missing something. Thaks.
@Mircea,
To Stop PWM
1) Stop the timer by stoping its clock input.
2) Make “Normal port operation, OC0 disconected”
3) Make the PORT as INPUT by clearing the DDRx
hey, thanks for the tutorials, they are really helpful.
i have tried using the same above program example to program the timer2 so that i can produce a pwm signal at the pin 0C2 on the atmega16, i made the adjustments below but it doesn’t work..pliz help!!
TCCR2|=(1<<WGM20)|(1<<WGM21)|(1<<COM21)|(1<<CS20)
DDRD|=(1<<PD7)
OCR2=duty
well this helped me understanding very clearly but have one confusion that PWM channel gives us a benefit that it works at side no matter what happens in main code so what if i want to go like this i have to measure battery voltage and adjust PWM according to the voltage to keep the battery at 13.2 volts now how this should be established
secondly if i use 12 or 16 MHz crystal what i have to change in code or this will work
The compiled HEX file and program do not match because Avinash made some mistakes while setting the mode of TCCR0. Maybe he debugged it before hexing which is why both are different.
Check the mode settings table of TCCR0 and output mode with the program line where they have set the mode for TCCR0…….
I think this page has the same title as the first one on PWM.
Hello guys! Great tutorial here. Why you stopped the PDF versions I start to save PDFs for easy future references but after “AVRTutorial-TIMER0.pdf” all the articles don’t have one. I imagine it’s a arduous job, but is a nice resource for studies and for preserve the content. Anyway, thanks a lot by that great explanation!
Dear Avinash,
With regards to your code, I dont understand where the value in the variable ‘duty’ assigned to OCR0 will come from. However I understand that the value must lie between 0 – 255.
Are you saying that after setting up the code like you’ve done, I have the option of generating my value (decimal) between 0 – 255 and assign it to the variable ‘duty’?
@Jean,
I think you don’t understand about ‘functions’ in C language.
Dear Avinash,
I’m sorry I dont understand what you are saying
I’m trying to conect a Atmega8 with an dc motor and an LCD(to show forward or backward or fast or slow) and control the speed on the motor. Because I’m a beginer I don’t realy know how. So far I succeded in making a programer on paralel port that works for my atmega8 at 4Mh in hex. I’ve tyed some schematics but didn’t had any results.
I also have an L293D as shown in tutorial!!?!
PLS H E L P!
Hello Avinash.. cool tutorial… ekdum mast…
i was wondering how to control the speed of a dc motor using pwm technique… timer0 has only one output through the OC0 pin and hence cannot be used to control a motor. Can i use timer1 and timer2 to control them?? If yes, then how??
Thanks in advance!!
hi Avinash,
Ur avr turorial series is very much simple and easy to understand for the beginers like me and others also,GOD
bless u and reward for this great job done and hope so that u will continue this effort.i espacially find it very much worthy to step into the world of microcontroller.May Allah bless u and success u in ur efforts.once again thank u for this great tutorial series.
thanks
i want to make line follower using more than about 8 sensors.
ur tutorial for PWM helped alot.
i wish i could get a good tutorial for PID.
Hi,
I’m new to programming MC.
I need two PWM o/p, i.e one to enable 1 and another to enable 2 of motor controller!
From which pin can i get another pwm o/p??
Thanks in advance.
@Illuminator
Use OC1A and OC1B pins.
Timer1 is a 16bit timer with dual PWM outputs.
@avinash and @illuminator
we can also use OC0 (timer0) and OC2 (timer2) for that purpose. Though they are 8bit timers, but its sufficient for motor controller enable pin..
Thank you for clearing the concept of PMW by microcontroller.
Now I have some doubt for pericular type application. Suppose I am getting a digital output and convering it in to some value( like your Ultrasonic range finder application) where port B bit 3 is already engaged.(as data bit to LCD) how I get pwm output in pin OC1A or OC1B for the converted value(or unconverted value.!)should I write the converted value to OCR0 or how. Please reply
regards,
Uttam Dutta
@Uttam Dutta,
Use TIMER1 for PWM. The OC1A and OC1B are free in most of my design.
Hi
Is it possible to manually copy value of OC0 to specific pin..
If yes, how..
for wg. we want to value of OC0 to PORT C PIN 7…
@avr noob
You didn’t got the point at all!!!!!!!
The analog value generated on PWM pin is NOT real analog. Its pseudo analog. That means if you copy it to some other digital pin the value that is copied depends on when the OCx pin is sampled. It it was high at that moment the other digital pin where it is copied will become high and vice-versa.
@avinash what about the phase correct pwm….post something on that…i cant find it on ur site..thanx in advance
gr8 work avinash..keep it up..can u tel how to interface sensors to motors in pwm mode..i mean in case of a line follower robot??
thanks..
Hi, thanks for the tutorial.
However I had a doubt,
Is it possible to control the brightness of the led using ULN2003 IC ( using PWM output from the microcontroller, input to ULN2003)?
If not which IC can I use? I need to vary intensity of a group of LEDs instead of only one,hence I am using ULN2003(which can give about 30 volts)
Hoping for a reply,thanks in advance.
Nakul Javali
Nakul Javali: Look at the STLA02.
thank you very much avinash sir 4 your help…your tutorials are awesome,you are doing a very excellent work for us. i am just a beginner & hav just started learning AVR for my project…i need to generate a PWM signal with varying duty cycle using ADC to fire the PMOSFETS in dc-dc converters..would you plz send me code to email plzz…
thanking you in advance…
Krishna kant
@Krisha Kant,
First of All I am no “sir” !
Don’t ask me to do anything for. I don’t work for free !
Why will anyone mail you anything … we all have our life ?
can i generate 4 pwm in Atmega16 at the same time
thnx a lot for ur efforts
@Ahmed
Yes
Bravo! Bravo!!
dear sir,
I am having an problem regarding a c program.
mine program is
#include
#include
void InitPWM()
{
/*
TCCR0 – Timer Counter Control Register (TIMER0)
———————————————–
BITS DESCRIPTION
NO: NAME DESCRIPTION
————————–
BIT 7 : FOC0 Force Output Compare [Not used in this example]
BIT 6 : WGM00 Wave form generartion mode [SET to 1]
BIT 5 : COM01 Compare Output Mode [SET to 1]
BIT 4 : COM00 Compare Output Mode [SET to 0]
BIT 3 : WGM01 Wave form generartion mode [SET to 1]
BIT 2 : CS02 Clock Select [SET to 0]
BIT 1 : CS01 Clock Select [SET to 0]
BIT 0 : CS00 Clock Select [SET to 1]
The above settings are for
————————–
Timer Clock = CPU Clock (No Prescalling)
Mode = Fast PWM
PWM Output = Non Inverted
*/
TCCR0|=(1<<WGM00)|(1<<WGM01)|(1<<COM01)|(1<<CS00);
//Set OC0 PIN as output. It is PB3 on ATmega16 ATmega32
DDRB|=(1<<PB3);
}
/******************************************************************
Sets the duty cycle of output.
Arguments
———
duty: Between 0 – 255
0= 0%
255= 100%
The Function sets the duty cycle of pwm output generated on OC0 PIN
The average voltage on this output pin will be
duty
Vout= —— x 5v
255
This can be used to control the brightness of LED or Speed of Motor.
*********************************************************************/
void SetPWMOutput(uint8_t duty)
{
OCR0=duty;
}
/********************************************************************
Simple Wait Loop
*********************************************************************/
void Wait()
{
_delay_loop_2(3200);
}
void main()
{
uint8_t brightness=0;
//Initialize PWM Channel 0
InitPWM();
//Do this forever
while(1)
{
//Now Loop with increasing brightness
for(brightness=0;brightness0;brightness–)
{
//Now Set The Brighness using PWM
SetPWMOutput(brightness);
//Now Wait For Some Time
Wait();
}
}
}
i want that motor should run at its max speed for certain durartion after acheiving max pwm
so, would you please help me to sort out this problem
its a humble request
your sincerly
nitesh kotwal