PIC18F4550 PWM - PIC Controllers
PIC18F4550 PWM - PIC Controllers
Introduction
Pulse Width Modulation (PWM) is a technique by which the width of a pulse is varied while keeping the frequency of the wave
constant.
PWM Generation
A period of a pulse consists of an ON cycle (5V) and an OFF cycle (0V). The fraction for which the signal is ON over a period is
known as a duty cycle.
E.g. A pulse with a period of 10ms will remain ON (high) for 2ms.Therefore, the duty cycle will be
Through the PWM technique, we can control the power delivered to the load by using the ON-OFF signal. The PWM signals can be
used to control the speed of DC motors and to change the intensity of the LED. Moreover, it can also be used to generate sine
signals.
Pulse Width Modulated signals with different duty cycle are shown below
PWM Duty Cycle
PIC18F4550 controller has an in-built 10-bit PWM module known as the CCP module. The pin CCP1 (RC2) is used for generating
PWM signals. It needs to be configured as an output.
In PIC18F4550, only Timer2 can be used for PWM generation. TMR2 is a 16-bit Timer2 register which is used to hold the count.
Note: Here, we are using a CCP1 module. If we want to use the CCP2 module then we need to modify the register name
as CCPR1L to CCPR2L, CCP1CON to CCP2CON.
In the CCP module, there is a 16-bit register which is split into two 8-bit registers - CCPR1H and CCPR1L.
CCPR1 Register
Only CCPR1L is used to decide the duty cycle of the PWM. CCPR1H is not user-accessible for the PWM mode.
As the PIC18F4550 generates a 10-bit PWM pulse, to set the duty cycle it uses a 10-bit register. The higher 8 bits
(MSBs) DC1B9: DC1B2 of this register are in CCPR1L register (8-bit) and lower 2 bits(LSBs) DC1B1: DC1B0, which
are used for a decimal portion in duty cycle, are in CCP1CON register at bit 5 and 4 respectively.
So the 10-bit value for duty cycle is represented by CCPR1L: CCP1CON<5: 4>
PR2 register
It is an 8-bit register that is used to load a count for a period of the pulse (TPWM).
1. Load the period value in a PR2 register and the duty cycle value in CCPR1L: CCP1CON<5: 4> registers and initialize the
CCP1 pin as an output.
2. Configure the T2CON register and set the TMR2 register to 0. Also, start the Timer2.
3. Now when a match occurs between registers PR2 and TMR2, pin CCP1 is pulled high and TMR2 is cleared.
4. The value of CCPR1L along with the CCP1CON<5: 4> which is a count for duty cycle is moved to the CCPR1H.
5. Finally, TMR2 is compared with the CCPR1H along with two lower bits of a duty cycle. When matched, the pin CCP1goes
low.
CCP1CON Register
DC1B1: DC1B0
These two bits are LSBs which are used for defining the decimal value of a duty cycle.
Calculations
Now how to set value for the PR2 register which defines the period value of a pulse.
where,
Now, let us see how to set a value for the CCPR1L which decides the duty cycle of a pulse. We know that a duty cycle is some % of
the PR2 (period) register. For example, if PR2 is 199 then a 20% duty cycle of the 199 is given by,
e.g.
So, load MSB 8-bits of the above result to the CCPR1L and 2 LSB bits in CCP1CON <5:4>.
Note: CCPR1L (duty cycle) value should be always less than or equal to the PR2 (period) value. If the CCPR1L value is greater
than the PR2 value, the pin CCP1 will not be cleared. This allows a duty cycle of 100% and gives the output.
Note: But, if a PR2 value is exceeding 8-bit value i.e. 255 then we have to increase Timer2 pre-scale value.
bits
The PWM duty cycle must be a value between 0 and (2 ^ PWM Resolution) - 1.
Application 1
Let us generate 10KHz PWM with a 20% duty cycle.
/*
Generating 10KHz PWM with 20% duty cycle
www.electronicwings.com
*/
#include "osc_config.h"
#include <pic18f4550.h>
void main()
while(1);
Application 2
Now, let us control the intensity of LED by generating PWM with different duty cycles using PIC18F4550.
/*
* www.electronicwings.com
*
*/
#include "osc_config.h"
#include <p18f4550.h>
void main()
TMR2=0;
while(1)
for(duty_cycle=1;duty_cycle<199;duty_cycle++)
MSdelay(20);
MSdelay(500);
for(duty_cycle=199;duty_cycle>1;duty_cycle--)
MSdelay(20);
MSdelay(500);
for(i=0;i<=val;i++)