Author: singularengineer

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