You are on page 1of 8

Pulse Width Modulation (PWM): Introduction

Introduction
Pulse width Modulation or PWM is one of the powerful techniques used in control
systems today. They are not only employed in wide range of control application which
includes: speed control, power control, measurement and communication. This tutorial
will take you through the PWM basics and implementation of PWM on 8051 and AVR
microcontrollers.

Basic Principal of PWM


Pulse-width Modulation is achived with the help of a square wave whose duty cycle is
changed to get a varying voltage output as a result of average value of waveform. A
mathematical explaination of this is given below.

Consider a square wave shown in the figure above.


Ton is the time for which the output is high and Toff is time for which output is low. Let
Ttotal be time period of the wave such that,

Duty cycle of a square wave is defined as

The output voltage varies with duty cycle as...

So you can see from the final equation the output voltage can be
directly varied by varying the Ton value.
If Ton is 0, Vout is also 0.
if Ton is Ttotal then Vout is Vin or say maximum.
This was all about theory behind PWM. Now lets take a look at the
practical implementation of PWM on microcontrollers.
Pulse Width Modulation (PWM): 8051 Code example

Idea Behind Implementation


The basic idea behind PWM implementation on 8051 is using timers and switching port
pin high/low at defined intervals. As we have discussed in the introduction of PWM that
by changing the Ton time, we can vary the width of square wave keeping same time
period of the square wave.
We will be using 8051 Timer0 in Mode 0. Values for high and low level will be loaded in
such a way that total delay remains same. If for high level we load a value X in TH0 then
for low level TH0 will be loaded with 255-X so that total remains as 255.

Assembly Code Example


Timer setup for PWM
CODE:
PWMPIN EQU P1.0
; PWM output pin
PWM_SETUP:
MOV TMOD,#00H
; Timer0 in Mode 0
MOV R7, #160
; Set pulse width control
; The value loaded in R7 is value X as
; discussed above.
SETB EA
; Enable Interrupts
SETB ET0
; Enable Timer 0 Interrupt
SETB TR0
; Start Timer
RET

Interrupt Service Routine


CODE:
TIMER_0_INTERRUPT:
JB F0, HIGH_DONE
just finished
LOW_DONE:
HIGH_DONE
SETB F0
start of high section
SETB PWMPIN
MOV TH0, R7
with R7

; If F0 flag is set then we


; the high section of the
; cycle so Jump to
; Make F0=1 to indicate
; Make PWM output pin High
; Load high byte of timer
; (pulse width control

value)
CLR TF0
interrupt flag
RETI
where

; Clear the Timer 0


; Return from Interrupt to
; the program came

from
HIGH_DONE:
CLR F0
start of low section
CLR PWMPIN
MOV A, #0FFH
CLR C
so it does

; Make F0=0 to indicate


; Make PWM output pin low
; Move FFH (255) to A
; Clear C (the carry bit)
; not affect the

subtraction
SUBB A, R7
255 - R7.
MOV TH0, A
TH0 + R7 = 255
CLR TF0
interrupt flag
RETI
where

; Subtract R7 from A. A =
; so the value loaded into
; Clear the Timer 0
; Return from Interrupt to
; the program came from

In your main program you need to call this PWM_SETUP routine and your controller
will have a PWM output. Timer Interrupt service routine will take care of PWM in the
background. The width of PWM can be changed by changing the value of R7 register. In
above example I am using 160, you can choose any value from 0 to 255. R7 = 0 will give
you o/p 0V approx and R7 = 255 will give you 5V approx.
You can also make use of Timer1 if you want. And the output pin can be changed to
whatever pin you want.

C Code Example
Timer setup for PWM in C
CODE:
//Global variables and definition
#define PWMPIN P1_0
unsigned char pwm_width;
bit pwm_flag = 0;
void pwm_setup(){
TMOD = 0;
pwm_width = 160;
EA = 1;
ET0 = 1;
TR0 = 1;
}

Interrupt Service Routine


CODE:
void timer0() interrupt 1 {
if(!pwm_flag) { //Start of High level
pwm_flag = 1;
//Set flag
PWMPIN = 1;
//Set PWM o/p pin
TH0 = pwm_width;
//Load timer
TF0 = 0;
//Clear interrupt
flag
return;
//Return
}
else { //Start of Low level
pwm_flag = 0;
//Clear flag
PWMPIN = 0;
//Clear PWM o/p pin
TH0 = 255 - pwm_width; //Load timer
TF0 = 0;
//Clear Interrupt flag
return;
//return
}

Now your normal 8051 is capable of PWM output.

`1PWM with microcontroller 8051 for SCR or triac power control


The project "PWM with microcontroller 8051 for SCR or triac power control" can be
used for two applications.
1. To control AC load's power with SCR or triac by controlling the firing angle or duty
cycle for two channels.
2. The project as it is can be used as digital to analog converter "DAC" for two channels.
This project is currently output two PWM signals but can be extended to many PWM
signals very easy. The input to the microcontroller is 100HZ pulses as zero crossing.
The project can be used to control the heating of AC heater also.
currently it is build for two channel DAC, the input at port1 and port2 of microcontroller
is converted to 0 - 5v accordingly. But if it is desired to control the SCR, then OP-AMP
circuit will be removed and optocoupler moc3020 will be used for interfacing SCR or
triac.
The circuit diagram of PWM with microcontroller 8051 for SCR or triac power control is
as under:

The code of program for PWM with microcontroller 8051 for SCR or triac power control
is written c lanuage using keil compiler. The c-code for PWM is as follows.
/* This project is develop to generate two seperate channel PWM signals at 50HZ
frequency

The duty cycle of the pulses is variable subject to the input on Port1 and port2.
The output PWM signal can be used to drive SCR or triacs to control the phase angle and
power of any load with suitable hardware interface.
Please not that in this project the OPAMP are used to convert the pulses to 0 - 5 V, means
you can use it in as two channel DAC also.
But for triac or SCR interface the OPAMP circuit will be re-placed with proper
optocoupler like moc3020 and scrs.89c51 as pwm controller
*/
#include<at89x52.h>
unsigned char ch_count[2];// two channel counts array
unsigned char ch_duty_level[2];// level of the duty cycle
bit int_10ms;// this is a flag wich is set every 10msec time period
sbit PWM1 = P3^6;
sbit PWM2 = P3^7;
sbit indicator = P3^5;
void external_interrupt (void) interrupt 0
// external interrupt for zero crossing dectection
{
ch_count[0]=ch_duty_level[0];
// on zero crossing detection, counts are updated for both PWM channels
ch_count[1]=ch_duty_level[1];
PWM1=0; // the output is active low
PWM2 =0;//89c51 as pwm controller
int_10ms = 1; // 10msec flag is set
}
void timer_interrupt (void) interrupt 1
// The timer 0 is used for the duty cycle adjustement of two channel PWM
{
TL0 = 0XE2; //reset timer LSB
if(--ch_count[0]==0) PWM1 = 1;
// each time the timer interrupt occur the counts are decreased by one
and on reaching zero
if(--ch_count[1]==0) PWM2 = 1;
// the outputs are turned off, as the out put is active low
}
void main (void)
{
ET0 = 1; // enables the Timer 0 interrupt of 8051
TMOD = 0x02;
// timer mode register, timer 0 is used in mode 2
TL0 = 0XE2; // Initialize timer0 LSB
TR0 = 1; // timer 0 is activated
EX0 = 1; // external inturpt is activated
IT0 = 1;
EA = 1;
ch_duty_level[0] = 30; // dummy value for duty cycle for PWM 1
ch_duty_level[1] = 60; // dummy value for duty cycle for PWM 2
while (1) // endless loop
{
if( int_10ms){
int_10ms = 0;

ch_duty_level[0] = P1;
// take the input value of duty cycle for PWM 1 fromport1 of the 8051
ch_duty_level[1] = P2;
// take the input value of duty cycle for PWM 2 fromport1 of the 8051
indicator =~ indicator;
}
}
}

solenoid valve atmel dc control triac,dimmer bt138,uln2003 microcontroleur interfacing a


microprocessor to a power thyristor microcontrol based level mesurement 89c51 as pwm
controller,at89c2051 sine wave pwm

You might also like