You are on page 1of 3

PWM generation using 8051 microcontroller 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 w hich 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 cycl e is changed to get a varying voltage output as a result of average value of wav eform. 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 i s 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 impl ementation of PWM on microcontrollers. Idea Behind Implementation The basic idea behind PWM implementation on 8051 is using timers and switching p ort 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 keepi ng same time period of the square wave. We will be using 8051 Timer0 in Mode 0. Values for high and low level will be lo aded in such a way that total delay remains same. If for high level we load a va lue X in TH0 then for low level TH0 will be loaded with 255-X so that total rema ins as 255. Assembly Code Example Timer setup for PWM CODE: PWMPIN EQU P1.0 PWM_SETUP:

; PWM output pin

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 LOW_DONE: SETB F0 SETB PWMPIN MOV TH0, R7 CLR TF0 RETI HIGH_DONE: CLR CLR MOV CLR F0 PWMPIN A, #0FFH C

; ; ; ; ; ; ; ; ;

If F0 flag is set then we just finished the high section of the cycle so Jump to HIGH_DONE Make F0=1 to indicate start of high section Make PWM output pin High Load high byte of timer with R7 (pulse width control value) Clear the Timer 0 interrupt flag Return from Interrupt to where ; the program came from

SUBB A, R7 MOV TH0, A CLR TF0 RETI

; Make F0=0 to indicate start of low section ; Make PWM output pin low ; Move FFH (255) to A ; Clear C (the carry bit) so it does ; not affect the subtraction ; Subtract R7 from A. A = 255 - R7. ; so the value loaded into TH0 + R7 = 255 ; Clear the Timer 0 interrupt flag ; Return from Interrupt to where ; 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 i n the background. The width of PWM can be changed by changing the value of R7 re gister. 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 t o 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 } }