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 !!!



hey Avinash ur tutorial is d best one i hav seen yet…it make me understand very easily…thanx a lot for dem!!! i need ur help since i m a newbie in microcontroller i dont know how to put this knowledge and get the desiered result…i use CODEVISIONAVR and ATMEGA16 so can u plz tel me step by step method to reduce the speed of motor…i wil b highly thankful to u …i m searching and trying for it for about 10 days but not getting it…u r my last hope plzzzzz HELP!!!
I’m using the following code for PWM in ATMEGA8, to control the speed of a DC Motor using L293D. It works perfectly in Proteous simulation . But it doesn’t work on hardware, the motor moves in a constant speed. Please help.
#define F_CPU 1000000
#include
#include
void pwm(uint8_t x)
{
OCR2 = x;
TCCR2 |= (1 << COM21);
// set none-inverting mode
TCCR2 |= (1 << WGM21) | (1 << WGM20)|(1 << CS21);
}
void delay(int dur)
{
for (int x=0;x<dur;x++)
{
_delay_ms(100);
}
}
int main()
{
int i=0;
DDRB |= (1 << DDB3)|(1 << DDB0)|(1 << DDB1);
PORTB|=1<<PB0;
PORTB&=~(1<<PB1);
while(1)
{
pwm(254);
delay(5);
pwm(170);
delay(5);
pwm(100);
delay(5);
pwm(0);
delay(50);
}
return 0;
}
Regards
Bikash
Bikash, we can understand what you are trying to made.For your convenience,we will suggest you to try our Line Following
Robot Kit product. It gives you a platform on which you can make any kind of LINE FOLLOWING ROBOT. In this kit “ATmega8″
mcu is connected with a L293D motor driver IC which drives two DC gear motors. Along with this kit you will get a library
and examples. With the help of these examlpes you can control the speed of a DC motor using L293D. Thank you .
For more information http://store.extremeelectronics.co.in/LFR-Kit.html
hello Gaurav,
I am not trying to make the line following robot. I am just trying to implement pwm in a dc motor.
the code seems correct in simulation but when attached with a motor , it doesnt works in the hardware. please help me understand what i am missing.
thanks in advance.
Regards
Bikash
Bikash, i am getting your point.This is a comman problem. We have already made a code for this problem and also checked it.A tested hardware is also available with this for the smoothly running the code. So you please use it.Because from sitting here we can not find what’s wrong with your hardware. So it’s better to use a trusted and tested product. For more information http://store.extremeelectronics.co.in/LFR-Kit.html
Thank you.
hey bikash,
are you using a flyback diode parallel to the dc motor?
sometimes its just such simple things that are missing.
regards
tommie
As stated by you,the program runs flawlessly and when u put all the things in place the motor starts to its full speed,
So Try this check points,
Remove the motor and check the pwm voltage at the input pin of l293d and check the voltage at the op of the l293d in adjacent to change in your pwm cycle,
Always use a flywheeling diode with a inductive load since the mosfets tends to get damaged due to the noise spiked that are present when inductive load is turned off.
Sir, can u suggest me on generating 40 KHz square wave with 50% duty cycle?
@Sreejit
Cost will be US$100
Thank u for prompt reply.
But what i meant was generating the wave using atmega16/32.
Ya for that program only the cost is US$100
Hello Avinash,
Thanks for your AVR tutorials! They are very informative and well illustrated. I am clear with the concept of using PWM modes to generate variable duty cycles. But I am confused with the frequency varying part. I want to vary the frequency of the PWM signal from 2Hz to 2.5KHz in steps of 1Hz. How do I do that?
Regards,
Ashish
Outstanding tutorial, made my job so much easier! The manual for the ATmega part is way too busy with a dozen options such as interrupt that are not needed in my application. Kudos!
@Sam,
Thank you very much !
Hi
Ashish
What is the PWM frequency?
IS the frequency remains constant with duty cycle changes?
Thanks
The table COM – Compare Output Mode is wrong.The values on the middle are inverted. Check the datasheet of Atmega32.