Generate PWM Wave With PIC Microcontroller

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

Be the First to Share


    • CNC and 3D Printing Contest

      CNC and 3D Printing Contest
    • Puzzles Challenge

      Puzzles Challenge
    • Lamps Challenge

      Lamps Challenge



    2 years ago

    Hi Bro,
    could you plz define the function of 'Delay Function' in PWM Generation?


    Reply 2 years ago

    sorry for the delay
    the delay function which i have used is simply a for loop which makes the controller busy. here i just made the controller to spend some part of its time executing the for loop so i can get a delay.

    i recommend you to use inbuilt delay functions which are supported by the header file
    i wrote this program when i was learning and my mentor clearly said i can not use any inbuilt function so i can up with this for loop.
    sorry if my program confuses you.


    Question 2 years ago on Step 3

    how to know the value of *count in the frequency formula?


    Answer 2 years ago

    Refer page numbers 67 of pic16f877a datasheet
    PWM period =1/f so
    f= PWM period
    PWM period = [(PR2)+1]*4*Tosc*(TMR2 prescale value)

    In step 3 the formula which I mentioned is not available in datasheet I wrote this 6 months ago I was trying to rewrite the formula in there's of frequency and that's what it's shown
    Frequency = clock frequency/(4*prescaler*(PR2-TMR2)*Postscaler*count)

    I don't remember from where I refered things as far as I remember This formula belongs to some other microcontroller of pic family probably for 16,32 bit.
    Frequency = 1000000/(4*1*(100-0)*1*1)
    Frequency = 2.5k Hz
    As far as pic16f877a we will not use postscaler ,count well I tried with simulation it don't gives any change
    Count is something like loop how may times the pr2 will overflow well the postscaler also does the same
    I can't explain much detail unless I find the exact source from where I refered This formula
    It's better to refer the formula which is available in datasheet I did this in protius simulation even though I add the proper values based on formula I wount get the appropriate frequency but this formula worked fine

    But according to page numbers 67 in pic datasheet iam getting 2.475k Hz and that's the actual frequency which we will get so follow datasheet and the about formula at step 3 gives correct frequency with protius simulation I don't do this with pic board practically so I cannot assure that u
    will get accurate frequency there will always 1-5% inaccuracy
    Always follow datasheet