Pulse-width modulation (PWM) is a modulation process or technique used in most communication systems. The PWM signal we can use to control the speed of DC motor or to control the intensity. It is also used to control the Analog Devices. And mainly the power which is delivered to the Analog device is controlled using this technique. Now, because of its high-efficiency low power loss and its ability to precisely control the power this technique is used in many applications. In this article, we will discuss PWM in PIC16F877A.
Pulse Width Modulation (PWM) is a method of changing the duration of a pulse with respect to the analog input. The duty cycle of a square wave is modulated to encode a specific analog signal level. The PWM signal is digital because, at any given instant of time, the full DC supply is either ON or OFF completely. PWM method is commonly used for speed controlling of fans, motors, lights in varies intensities, pulse width modulation controller, etc. These signals may also be used for approximate time-varying of analog signals. PWM is employed in a wide range of applications, ranging from measurement and communications to power control and conversion.
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.
There are various terms associated with PWM:
The first step to create a PWM signal is to define the period of a single PWM cycle. The next step is to define the period of time within the PWM cycle. Let us see how to implement this in the PIC16F877A peripheral. In PIC16F877A, only Timer 2 can be used for PWM generation. TMR2 is a 16-bit Timer 2 register which is used to hold the count.
PIC16F877A microcontroller has two independent CCP(Capture/Compare/PWM) modules, named as CCP1 and CCP2. Each CCP module has two 8-bit resistors(CCPxH, CCPxL) that can be used as:
PIC16F877A has two PWM module with a resolution of 10-bits. The 8-MSB bits are stored in CCPRxL and the remaining 2-bits in the CCPxCON register. The below tables shows the PWM module of PIC.
The below table shows the registers associated with PIC16F877A PWM.
Unimplemented(bit 7-6): Read as ‘0’
CCPxX:CCPxY(bit 5-4): PWM Least Significant bits,
Capture Mode
Unused
Compare Mode
Unused
PWM Mode
These bits are the two LSbs of the PWM duty cycle. The eight MSBs are found in CCPRxL.
CCPxM3:CCPxM0(bit 3-0): CCPx Mode Select bits
0000 – Capture/Compare/PWM disabled (resets CCPx module)
0100 – Capture mode, every falling edge
0101 – Capture mode, every rising edge
0110 – Capture mode, every 4th rising edge
0111 – Capture mode, every 16th rising edge
1000 – Compare mode, set output on match (CCPxIF bit is set)
1001 – Compare mode, clear output on match (CCPxIF bit is set)
1010 – Compare mode, generate software interrupt on match (CCPxIF bit is set, CCPx pin is unaffected)
1011 – Compare mode, trigger special event (CCPxIF bit is set, CCPx pin is unaffected);
11xx – PWM mode
PWM period = [(PR2) + 1] x 4 x Tosc x (TMR2 prescale value)
Example: We use 20 MHz clock and the O/P frequency required is 5KHz
Here PWM period = 1/ Frequency (that will be 1/5000 = 0.0002)
0 .0002 = (PR2 + 1) x (1 / 20000000) x 16
PR2 + 1 = (0.0002 x 20000000) / 16 =250
PR2 = 249
PR2 = 0xF9
These are the necessary steps required to generate a PWM signal in a single channel. You might want to update the cycle period and vary the duty cycle. For this, create a function where you can enter your required PWM Pulse Period.
Program to demonstrates the LED fading using PWM signals.
#include <pic.h> #include "Config.h" void delay(int d); void main() { int i; TRISC = 0X00; //Configure PORTC as output CCP1CON = 0X0F; // Select the PWM Mode PR2 = 0xF9; //Set the Cycle time for varying the duty cycle CCPR1L = 50; // By default set the dutyCycle to 50 TMR2ON = 1; //Start the Timer for PWM generation while(1) { for(i=0;i<100;i++) { CCPR1L=i; // Keep increasing the dutyCyle to increase the brightness of LED delay(3000); } for(i=100;i>0;i--) { CCPR1L=i; // Keep reducing the dutyCyle to decrease the brightness of LED delay(3000); } } } void delay(int d) { int i,j; for(i=0;i<d;i++); }