Sunday 15 July 2018

PWM in 8051 Microcontroller

Aim:

In this tutorial how to generate PWM in 8051 Microcontroller. PWM is an abbreviation of Pulse Width Modulation and is used in many engineering projects. It is used in those engineering projects where you want an analog output. For example, you want to control the speed of your DC motor then you need PWM pulse. Using PWM signal you can move your motor at any speed from 0 to its max speed. Similarly suppose you wanna dim your LED light, again you are gonna use PWM pulse. So, in short it has numerous uses.

Description:


Pulse width modulation is basically a square wave with a varying high and low time. A basic PWM signal is shown in the figure below.
center
Pulse width modulation wave
There are various terms associated with PWM:
  1. On-Time: Duration of time signal is high
  2. Off-Time: Duration of time signal is low
  3. Period: It is represented as the sum of on-time and off-time of PWM signal
  4. Duty cycle: It is represented as percentage of time signal remains on during the period of the PWM signal

Period

As shown in the the figure, Ton denotes the on-time and Toff denotes the off time of signal. Period is the sum of both on and off times and is calculated as shown in the equation below:
PWM Period

Duty Cycle

Duty cycle is calculated as on-time to the period of time. Using the period calculated above, duty cycle is calculated as:
PWM Duty cycle equation

PWM: Voltage Regulation

PWM signal when used at a different duty cycles gives a varying voltage at the output. This method is used in various areas of application like:
  • Switching regulators
  • LED dimmers
  • Audio
  • Analog signal generation
  • and many more…
Voltage regulation is done by averaging the PWM signal. Output voltage is represented by the following equation:
PWM Voltage regulation PWM Voltage regulation
As you can see from the 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.

Implementing PWM on 8051

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.

Block Diagram

pwm

Schematic

pwm

Code

// ***********************************************
// Project: Interfacing PWM to 8051
// Author: Code Bloges
// Module description: Operate array of LED's
// ***********************************************
#include<reg51.h>
// PWM_Pin
sbit PWM_Pin = P2^0;                      // Pin P2.0 is named as PWM_Pin
// Function declarations
void cct_init(void);
void InitTimer0(void);
void InitPWM(void);
// Global variables
unsigned char PWM = 0;                 // It can have a value from 0 (0% duty cycle) to 255 (100% duty cycle)
unsigned int temp = 0;    // Used inside Timer0 ISR
// PWM frequency selector
/* PWM_Freq_Num can have values in between 1 to 257            only
 * When PWM_Freq_Num is equal to 1, then it means highest PWM frequency
 * which is approximately 1000000/(1*255) = 3.9kHz
 * When PWM_Freq_Num is equal to 257, then it means lowest PWM frequency
 * which is approximately 1000000/(257*255) = 15Hz
 *
 * So, in general you can calculate PWM frequency by using the formula
 *     PWM Frequency = 1000000/(PWM_Freq_Num*255)
 */
#define PWM_Freq_Num   1      // Highest possible PWM Frequency
// Main Function
int main(void)
{
   cct_init();                 // Make all ports zero
   InitPWM();              // Start PWM
   PWM = 127;              // Make 50% duty cycle of PWM
   while(1)                // Rest is done in Timer0 interrupt
   {}
}
// Init CCT function
void cct_init(void)
{
                P0 = 0x00;  
                P1 = 0x00;  
                P2 = 0x00;  
                P3 = 0x00; 
}
// Timer0 initialize
void InitTimer0(void)
{
                TMOD &= 0xF0;    // Clear 4bit field for timer0
                TMOD |= 0x01;    // Set timer0 in mode 1 = 16bit mode
                TH0 = 0x00;      // First time value
                TL0 = 0x00;      // Set arbitrarily zero
                ET0 = 1;         // Enable Timer0 interrupts
                EA  = 1;         // Global interrupt enable
                TR0 = 1;         // Start Timer 0
}
// PWM initialize
void InitPWM(void)
{
                PWM = 0;         // Initialize with 0% duty cycle
                InitTimer0();    // Initialize timer0 to start generating interrupts
}
// Timer0 ISR
void Timer0_ISR (void) interrupt 1  
{
                TR0 = 0;    // Stop Timer 0
                if(PWM_Pin)      // if PWM_Pin is high
                {
                                PWM_Pin = 0;
                                temp = (255-PWM)*PWM_Freq_Num;
                                TH0  = 0xFF - (temp>>8)&0xFF;
                                TL0  = 0xFF - temp&0xFF;             
                }
                else             // if PWM_Pin is low
                {
                                PWM_Pin = 1;
                                temp = PWM*PWM_Freq_Num;
                                TH0  = 0xFF - (temp>>8)&0xFF;
                                TL0  = 0xFF - temp&0xFF;
                }
                TF0 = 0;     // Clear the interrupt flag
                TR0 = 1;     // Start Timer 0
}

Downloads:

The code was compiled in Keil uvision4 and simulation was made in Proteus v7.7.
To download code and proteus simulation click here.

Further Reading suggestions:

No comments:

Post a Comment