Introduction: Generate PWM Wave With PIC Microcontroller

About: hi keep learning keep supporting.


PWM STANDS FOR PULSE WIDTH MODULATION is a technique by which width of the pulse is varied.

To understand this concept clearly consider a clock pulse or any square wave signal it has 50% duty cycle that means Ton and Toff period is same, The total duration for which the signal was high and the duration for which the signal was low is called total time period.

For the image shown above this wave has a duty cycle of 50%

Duty cycle = (ON time / Total Time)*100

ON time - time for which signal was high

OFF time - time foe which signal was low Total time -Total time period of the pulse(both ON and OFF time)

Step 1: Selecting Microcontroller

Selecting appropriate microcontroller for the project this is the essential part of the project PWM signals can be generated in microcontrollers with PWM channels(CCP registers).For this project I am planing to stick with pic16f877. you can download the datasheet link is given below

PIC16F877a data sheet click here

CCP module is responsible for producing PWM signal.
CCP1 and CCP2 are multiplexed with PORTC. PORTC is an 8-bit wide bidirectional port. The corresponding data direction register is TRISC. Setting TRISC bit (=1) will make take the corresponding PORTC pin as an input. Clearing a TRISC bit(=0) will make the corresponding PORTC pin an output.

TRISC = 0; //Clearing this bit will make PORTC as output.



Each Capture/Compare/PWM (CCP) module contains a 16-bit register which can operate as a:

• 16-bit Capture register

• 16-bit Compare register

• PWM Master/Slave Duty Cycle register

Configure CCP1CON register to PWM mode.

Register Description

CCPxCON This register is used to Configure the CCP module for Capture/Compare/PWM opertaion.

CCPRxL This register holds the 8-Msb bits of PWM, lower 2-bits will be part of CCPxCON register.

TMR2 Free running counter which will be compared with CCPR1L and PR2 for generating the PWM output.

Now I will use binary to represent the bits to configure CCP1CON register.

refer the image above.

CCP1CON = 0b00001111;

You can also you hex format

CCP1CON = 0x0F; //configuring CCP1CON register for PWM mode

Step 3: Configuring Timer2 Module (TMR2 Register)

Timer2 is an 8-bit timer with a prescaler and a postscaler. It can be used as the PWM time base for the PWM mode of the CCP module(s). The TMR2 register is readable and writable and is cleared on any device Reset.

T2CON register is shown

The prescale and postscale will adjust the output frequency of the generated PWM wave.

Frequency = clock frequency/(4*prescaler*(PR2-TMR2)*Postscaler*count)

Where Tout = 1/frequency

T2CON = 0b00000100;

This will generate 2.5 KHz @ 1Mhz or 100KHz @ 4MHz crystal (practically there is a limitation for this PWM frequency refer particular datasheet for more details)

hex representation

T2CON = 0x04; // enable T2CON without Prescaler and postscale configuration.

Step 4: Configuring PR2 (Timer2 Period Register)

The Timer2 module has an 8-bit period register, PR2. Timer2 increments from 00h until it matches PR2 and then resets to 00h on the next increment cycle. PR2 is a readable and writable register. The PR2 register is initialized to FFh upon Reset.

Setting an appropriate range for PR2 will allow use to change the duty cycle of the generated PWM wave

PR2 = 100; // Set the Cycle time to 100 for varying the duty cycle from 0-100

For simplicity I am using PR2=100 by making CCPR1L = 80; 80% duty cycle can be Achieved.

Step 5: Configure CCPR1l Module

Since PR2 = 100 CCPR1l can be configured anywhere between 0-100 to get the desired duty cycle.

Step 6: Write the Sketch on You MPLAB X IDE the Code Is Given Bellow

void delay(int a)  //function to generate delay
for(int i=0; i<a;i++)
for(int j=0;j<144;j++);
void main()
TRISC = 0; //Clearing this bit will make PORTC as output.
CCP1CON = 0x0F;  //configuring CCP1CON register for PWM mode
T2CON = 0x04;  // enable T2CON without Prescaler and postscale configuration.
PR2 = 100;  // Set the Cycle time to 100 for varying the duty cycle from 0-100
CCPR1L = 75;  //generated 75% duty cycle

I have also made a little modification to the code so that the frequency of the generated PWM wave

This is code is simulated in proteus and the output PWM wave is shown below To upload this on your pic development boards use #include with suitable configuration bits.

Thank you