Home > Electronics > Programming PIC 18 using XC8 (MPLAB X) : PWM (using pwm.h)

Programming PIC 18 using XC8 (MPLAB X) : PWM (using pwm.h)

Pulse Width Modulation (PWM) is used everywhere from motors to communication! It uses timer as its foundation to toggle the pins high-low at a defined period (1/frequency) and duty cycle (10 bit resolution – 210 = 1024 steps). If you use high frequency, then you won’t get the 10 bit resolution. Read the document bellow to find more information.

Read this document and you’ll know a lot about PWM : http://ww1.microchip.com/downloads/en/devicedoc/31014a.pdf

So in previous tutorial we saw about using a timer. Now my task is to make a LED do the heart beat effect (gradually increase/decrease the brightness of an LED using PWM).

To set a PWM:

  • Setup the timer (to the frequency/period)
  • Set the duty cycle (you will be using the functions from pwm.h)

    So I am going to set the PWM frequency to 2KHz (since using 8MHz as clock source and prescale of 16, getting less than 2KHz is difficult), so the formula according to the datasheet will be  (we are going to find PR2)

PWM period = [(PR2) + 1] • 4 • TOSC • (TMR2 prescale value)

where PWM period = 1/ Frequency (that will be 1/2000 = .0005)

.0005 = [PR2 + 1] • [1 / 8000000] • 16

PR2 + 1 = [.0005 • 8000000] / 16

PR2 + 1 =  250

PR2 = 249

PR2 = 0xF9 ( 249 in hex)


Note : Read the datasheet and peripheral library document. PWM1 uses Timer 2. You can use other timers as source for your PWM, but read and make sure if you can or can’t in the datasheet of the device you are using.

To set timer2 for PWM, we just need to set the presale value

unsigned char Timer2Config = T2_PS_1_16; OpenTimer2(Timer2Config);

And then open the PWM

OpenPWM1(0xF9); //2KHz

So here is the whole sample PWM program and the video below it

#define _XTAL_FREQ 8000000 //The speed of your internal(or)external oscillator #define USE_AND_MASKS #include <xc.h> #include "config.h" #include <plib/timers.h> #include <plib/pwm.h> int i = 0; int countup = 1; //our flag to set up/down dutycycle int DutyCycle = 0; unsigned char Timer2Config; //PWM clock source void SetupClock(void); void main(int argc, char** argv) { SetupClock(); // Internal Clock to 8MHz TRISCbits.RC2 = 0; //PWM pin set as output Timer2Config = T2_PS_1_16; //prescale 16 OpenTimer2(Timer2Config); OpenPWM1(0xF9); //Open pwm at 2KHz while(1) //infinite loop { if(countup == 1) { SetDCPWM1(DutyCycle); //Change duty cycle DutyCycle++; if(DutyCycle == 1024) countup = 0; } else { SetDCPWM1(DutyCycle); //Change duty cycle DutyCycle--; if(DutyCycle == 0) countup = 1; } __delay_ms(1); } } void SetupClock() { OSCCONbits.IRCF0 = 1; OSCCONbits.IRCF1 = 1; OSCCONbits.IRCF2 = 1; }

And here is the video

  1. December 23rd, 2017 at 13:03 | #1

    Thanks for finally talking about >Singular Engineer > Programming PIC 18 using XC8
    (MPLAB X) : PWM (using pwm.h) <Loved it!

  2. December 23rd, 2017 at 10:07 | #2

    Pretty! This has been an extremely wonderful article.
    Thank you for supplying this information.

  3. December 21st, 2017 at 14:02 | #3

    There are plenty of concerns about how credible the state numbers are shown some evidence
    of the moving of expenditure from the books and also other assorted statistical manipulation that may occured to get Greece into the
    European Monetary Union in the first place. If you
    are the form of individual who desires to arrange for his future, then it’s
    quite possible that you want ahead whilst yourrrre still young.
    Mutual fund ratings operate on the actual as well as the
    past only, without relation to its the longer term performance associated with
    a particular fund.

  4. December 20th, 2017 at 03:47 | #4

    The project of Siddha Pine Woods comes with the flamboyant options of
    2 BHK in addition to 3 BHK units, all designed with the maximum
    care and developed in order to ensure the residents the
    pleasure to dwell within the most comfy lifestyle. At the conclusion of January as well as in our year end
    review, we noted that this macro conditions argued
    for rising volatility inside the major averages with sideways to lower prices throughout February.
    The job is not as easy as it sounds; firstly, they’ll inspect
    your premises and measure the price it is possible to quote within the market.

  5. December 19th, 2017 at 16:10 | #5

    When people consider self build homes they often times envision the grand designs they
    may have seen constructed on recent television programmes.
    Sometimes owners from the ransom strips are unknown or it might be a
    development company which includes gone into administration. African investment opportunities companies in Sierra
    Leone found that the investments are not just philanthropic investment, alternatively, it
    offers a superior great returns due to the effort linked to developing projects.

  6. December 15th, 2017 at 13:10 | #6

    You need to understand stop loss orders when you start investing
    your hard earned dollars inside the stock market.
    It competed with the New York Stock Exchange and Nasdaq’s with the worlds.

    While venture capital angel investors are likely to be forced to invest at the least
    R 300 000 in funds per year, the concept is the network’s individuals collectively invest to get
    businesses going and in the end make a profit by selling their holdings within three to five years.

  7. November 11th, 2017 at 05:03 | #7

    Find Out If They Offer A Guarantee – Some of the best roofers around
    will offer you a guarantee on his or her work, this also is
    essential prefer a repair or if something goes wrong.

    Business is among the links that ties each of the people into a fancy system that are governed
    from the laws of taxes. This also ensures that the fuel
    usage to haul away shingles is just not shared by metal roofs.

  8. October 21st, 2017 at 21:31 | #8

    Have you ever considered creating an ebook or guest authoring on other blogs?
    I have a blog based upon on the same topics you discuss and would really
    like to have you share some stories/information. I know my viewers would
    enjoy your work. If you’re even remotely interested, feel
    free to send me an e-mail.

  9. October 4th, 2017 at 08:20 | #9

    Good day! Would you mind if I share your blog with my
    facebook group? There’s a lot of folks that I think would really appreciate your content.
    Please let me know. Cheers

  10. fabm
    August 3rd, 2015 at 16:35 | #10

    I use PIC18F8722 mcu.
    but i can’t find the library with the functions as putsUSART, openUSART, etc. are they included in the compilers? Please send me the link to let me use these functions in my code of USART, thank you.


    • August 3rd, 2015 at 16:37 | #11

      Yes, included with your compiler installation. You can find the documentation file in C:\Program Files (x86)\Microchip\xc8\{compiler-version}\docs\MPLAB_XC8_Peripheral_Libraries.pdf

    • August 3rd, 2015 at 16:40 | #12

      Ok.. now I understand your question. Your part has two UART ports. So you have to use puts1USART and puts2USART for which one you are trying to use. Similarly Open1USART to open USART1 and Open2USART to open USART2. It is all mentioned in the post.

  11. ionutu
    January 10th, 2015 at 13:56 | #13

    salve a tutti
    come si fa a creare il file config.h e dove devo meterlo?

  12. Jose
    May 7th, 2014 at 10:51 | #15

    I can’t find config.h
    When I compile, the error message is shown “plib / pwm.h: 32: error: (141) can not open include file” pconfig.h “: No such file or directory”.
    What library is this?

    • May 19th, 2014 at 13:41 | #16

      You got to create your own config.h. This link will help you to create your config.h file

      plib/pwm.h –> plib is a folder where you got a bunch of microchip’s library header files. Use angular bracket.

  13. February 26th, 2014 at 08:24 | #17

    Hi, very nice post and explanation.
    One thing I’m not too clear on: When you used OpenTimer2(), you passed it an argument of Timer2Config, which you set to be the defined macro containing the prescale settings.

    When I look at the Xc8 standard peripheral library documentation however, the bit about OpenTimer2 (page 1124) says that the arugment to that function should be all of the a number of configuration settings ORed or ANDed together. If you scroll down to the input parameter bit it says these should be not only Prescale Value, but also postscale value and Enable Timer2 Interrupt.

    In addition. in the example they provide in that same document (page 1147), OpenTimer1() (which I appreciate is a different function with, but still works in the same way in relation to how its input parameter is defined), is written like
    config1 = T1_8BIT_RW | T1_SOURCE_EXT | T1_PS_1_8

    So my question is, how and why can you get away with only using the prescaler value as the input to ur OpenTimer2 function, without anding/oring it with the other configuration setting values? Or am I misunderstanding it?

    Thanks in advanced 🙂

    • March 15th, 2014 at 01:26 | #18

      Sorry about the delayed response.

      I’m not sure if I understood your question, but let me guess. Why am I not using all the parameters? By default they all have 1:1 on scale value. Unless you want it to be changed there is no need to add that parameter. In simple words, just AND/OR only the parameters you use/change.

      Hope I answered your question.

  14. Ruben
    November 9th, 2013 at 16:48 | #19

    Could it be because you’re using plibs? I would recommend you not to use plibs. They can be an easy way for programming, but they come with a lot of trouble when you can’t use them. I think it is due to “ifdefs”. Try looking at the plib document and change the code to write/read the registers instead of using the plibs.
    Please, give your feedback.

  15. mihaistoica
    November 9th, 2013 at 14:27 | #20


    Let me be more accurate. I tried with MPLABX 1.95 and XC8 1.21
    Your code compiled successfully with PIC18F4550, with error with PIC18F45K50 (same error “:0: error: undefined symbols:”
    Try. It takes 5 minutes

    • November 11th, 2013 at 01:02 | #21

      Well, please read the datasheet.

      18F4550 – has CCP1 and CCP2
      18F45k50 – has ECCP1 and CCP2

      Ref : Chapter 15 in both the datasheets. and read C:\Program Files (x86)\Microchip\xc8\v1.21\docs\MPLAB_XC8_Peripheral_Libraries.pdf on how to use ECCP

  16. mihaistoica
    November 5th, 2013 at 04:06 | #22


    I tried your code using MPLABX for PIC18F4550. It compiles fine
    With PIC18F45K50 it does not. I receive an error : “:0: error: undefined symbols:”
    Why am I telling you this ? Because I am working with PIC18F45K80 and I am receiving the same error
    How can I fix it ?

    Thanks in advance

    • November 7th, 2013 at 00:19 | #23

      Hmm.. very limited information has been presented. Need more info (complete compiler output) and your code. Will take ages for me to check back in the comments section. Microchip forum is a place where you will get solution in few hours. If you already found a solution, please reply so that it will be useful for others.


  17. October 24th, 2013 at 15:26 | #24

    You are right. I missed it. Editing a post is difficult since the format messes up. Will make sure wont’ happen again. Thanks for looking in.

  18. Dave
    October 24th, 2013 at 12:02 | #25

    Looks like you dropped the 4 in the equation.
    0.0005 = [PR2 + 1] * 4 * [1/8000000] * 16
    so PR2 = 61.5

  19. Ruben
    August 30th, 2013 at 05:50 | #26

    Hahaha. Sorry, i forgot to write the rest of the code. I wanted to say the code line “Timer2Config T2_PS_1_16”. It doesn’t accept the T2_PS_1_16 because timer2 isn’t enabled in timers.h plib. The code it’s in grey unlike the timer0 that is in blue and black.

  20. August 30th, 2013 at 00:45 | #27

    Timer2Config is a variable (look above the main function where a bunch of variables are declared)

    unsigned char Timer2Config;

  21. Ruben
    August 29th, 2013 at 19:38 | #28

    Hi. I can’t use/access the code “Timer2Config”. I opened the library and i found that the corresponding code to timer2 is written in grey and don’t have that comment trace and asterisk /*. Do you possibly know why that is and how i can enable the timer2 plib easy coding?

    Thanks in advance.

  1. No trackbacks yet.