Hey Everybody,
If you want to create PWM using a PIC, then this thread is for you. I contrived a PWM function that can drive motors, LEDs, and other hardware from 15.26 Hz to 1 MHz. I also put in a Comet lighting effect for 10 LEDs (RA0-RA3, RB0-RB5) on the PIC18F1320 just for a quick example program. Please note that the compiler is C18 and I am using the PIC18F1320. The code will not work with a different compiler or PIC. To understand how the code works, you need to grasp the concept of duty cycle and PWM itself. With PWM, you are turning on your hardware for a limited amount of time, and turning it off for a limited amount of time. That time differs with respect to your driving frequency, in which you subtract your frequency from the duty cycle to get the OFF delay. Therefore, the following equations apply:
\(D = \frac{t}{T}\)
Where:
D = Duty Cycle
t = ON Duration
T = Period of Frequency
\(V_O = D * V_{IN}\)
Where:
Vo = Output voltage from pin.
Vin = Standard voltage input, presumably 5V (What you are doing is switching that 5V on and off rapidly so you get a new output voltage).
So in the code, you see I have my on and off variables, which determine the on and off delay. The reason you see 65536 subtracting from the variables is due to Timer0, which uses the following equation to find frequency:
\(f = \frac{1}{(65536 - Delay)}\)
Please note that the (65536 - Delay) is in microseconds (μS). Here's a simple example of how it works:
Suppose hypothetically you wanted a frequency of 1 kHz. You simply put it in the PWM function and it does the rest. It begins in the code by subtracting 65536 from your intended frequency value:
Code Math:
\((65536 - 1000) = 65436\)
\(f = \frac{1}{[(65536 - 65436) * 0.5uS] * 2} = 1 kHz\)
The showPat function simply combines LATA and LATB together, otherwise my LED combination wouldn't be consecutive.
Here is the code:
Informative Links:
Duty cycle - Wikipedia, the free encyclopedia
Pulse-width modulation - Wikipedia, the free encyclopedia
If anyone has questions, I would encourage you to ask them! Comments and suggestions are also welcomed.
Enjoy!
If you want to create PWM using a PIC, then this thread is for you. I contrived a PWM function that can drive motors, LEDs, and other hardware from 15.26 Hz to 1 MHz. I also put in a Comet lighting effect for 10 LEDs (RA0-RA3, RB0-RB5) on the PIC18F1320 just for a quick example program. Please note that the compiler is C18 and I am using the PIC18F1320. The code will not work with a different compiler or PIC. To understand how the code works, you need to grasp the concept of duty cycle and PWM itself. With PWM, you are turning on your hardware for a limited amount of time, and turning it off for a limited amount of time. That time differs with respect to your driving frequency, in which you subtract your frequency from the duty cycle to get the OFF delay. Therefore, the following equations apply:
\(D = \frac{t}{T}\)
Where:
D = Duty Cycle
t = ON Duration
T = Period of Frequency
\(V_O = D * V_{IN}\)
Where:
Vo = Output voltage from pin.
Vin = Standard voltage input, presumably 5V (What you are doing is switching that 5V on and off rapidly so you get a new output voltage).
So in the code, you see I have my on and off variables, which determine the on and off delay. The reason you see 65536 subtracting from the variables is due to Timer0, which uses the following equation to find frequency:
\(f = \frac{1}{(65536 - Delay)}\)
Please note that the (65536 - Delay) is in microseconds (μS). Here's a simple example of how it works:
Suppose hypothetically you wanted a frequency of 1 kHz. You simply put it in the PWM function and it does the rest. It begins in the code by subtracting 65536 from your intended frequency value:
Code Math:
\((65536 - 1000) = 65436\)
\(f = \frac{1}{[(65536 - 65436) * 0.5uS] * 2} = 1 kHz\)
The showPat function simply combines LATA and LATB together, otherwise my LED combination wouldn't be consecutive.
Here is the code:
Rich (BB code):
//
// Comet Tails.C
//
#include <p18f1320.h>
#include <delays.h>
#include <stdlib.h>
#pragma config OSC=INTIO2, WDT=OFF, LVP=OFF, DEBUG=ON
#define PAUSE Delay1KTCYx(10);
#define FREQ 500
#define TIME 100
void showPat(unsigned int myPat)
{
unsigned int patstopBits;
patstopBits = myPat>>4;
LATA = myPat;
LATB = patstopBits;
}
void showPatN(unsigned int patN)
{
unsigned int patstopN;
patstopN = patN>>4;
LATA = ~patN;
LATB = ~patstopN;
}
void pwm(unsigned int pins, unsigned int duty, unsigned int freq, unsigned int timer) // PWM Function
{
unsigned int times, on, off, pat;
TRISA = ~(pins & 0xFF);
TRISB = ~(pins>>4 & 0xFF);
pat = pins;
on = (65536 - duty);
off = (65536 - freq) - on;
INTCONbits.TMR0IF = 0; // Clear OVF Flag
showPat(pat); // Initialize LATA
T0CON|=0x80; // Set Timer0 Bits
for(times=timer;times>0;times--) // Duration of playing
{
if(freq<=duty) // If duty cycle is greater than or equal to the frequency
{
showPat(pat);
}
else
{
TMR0H = (on >> 8) & 0xFF; //Load TMR0H byte first
TMR0L = on & 0xFF; // Load TMR0L byte next
while(!INTCONbits.TMR0IF); // Wait for timer
INTCONbits.TMR0IF = 0; // Clear OVF Flag
showPatN(pat); // Invert output
TMR0H = (off >> 8) & 0xFF;
TMR0L = off & 0xFF;
while(!INTCONbits.TMR0IF);
showPat(pat);
}
}
}
void main()
{
int a,b,c,d,e,f;
OSCCONbits.IRCF0=1;
OSCCONbits.IRCF1=1;
OSCCONbits.IRCF2=1;
T0CONbits.TMR0ON = 0; // Don't turn timer on yet
T0CONbits.T08BIT = 0; // Timer0 is configured as 16-bit timer
T0CONbits.T0CS = 0; // Use internal clock
T0CONbits.PSA = 1; // Prescaler is not assigned
T0CONbits.T0PS2 = 0;
T0CONbits.T0PS1 = 0;
T0CONbits.T0PS0 = 0;
OSCCONbits.IRCF0=1;
OSCCONbits.IRCF1=1;
OSCCONbits.IRCF2=1;
while(!OSCCONbits.IOFS);
while(1)
{
a = 0x01;
b = 0x02;
c = 0x04;
d = 0x08;
f = 0x10;
while(a<500)
{
pwm(a, 1, FREQ, TIME);
PAUSE;
a=a<<1;
pwm(b, 25, FREQ, TIME);
PAUSE;
b=b<<1;
pwm(c, 50, FREQ, TIME);
PAUSE;
c=c<<1;
pwm(d, 150, FREQ, TIME);
PAUSE;
d=d<<1;
pwm(e, 350, FREQ, TIME);
PAUSE;
e=e<<1;
pwm(f, 500, FREQ, TIME);
PAUSE;
f=f<<1;
}
}
}
Duty cycle - Wikipedia, the free encyclopedia
Pulse-width modulation - Wikipedia, the free encyclopedia
If anyone has questions, I would encourage you to ask them! Comments and suggestions are also welcomed.
Enjoy!
Last edited by a moderator: