## Simple PWM example for the PIC18F4620

The PIC18F4620 includes a hardware pulse width modulation feature which is really useful for generating periodic pulse sequences with different frequencies and duty cycles. Applications include motor speed control, servo control, and varying the brightness of an LED. This simple example program generates a 1kHz PWM (pulse width modulation) signal on pin 17 (RC2 / CCP1). The program is written in C for Microchip’s XC8 C compiler.

NB The PIC18F4620 provides 10-bit resolution in setting the PWM pulse width. However, to keep things simple, I’m disregarding the 2 least significant bits, which reside in a different register to the 8 most significant bits. Unless you really need the extra resolution, I recommend ignoring the 2 least significant bits and treating both the PWM period and pulse width as 8-bit values. Because I’m making this simplification, the calculations I present below are a bit simpler than those described in the PIC18F4620 datasheet.

### Setting the PWM period and duty cycle

In this example, the clock oscillator frequency of the 18F4620 is left at the default value of Fosc = 1MHz. The oscillator period is therefore Tosc = 1us.

The PIC18F4620 performs one machine code instruction every four clock cycles, so the instruction cycle in this example is Tcy = 4us. This is an important figure because Tcy is really the fundamental unit of time when measuring time in PIC programs.

The period of the PWM waveform is determined by the value written to a special function register called PR2 (short for Period Register for Timer 2). The formula for calculating PWM period is:

PWM period = (PR2+1) * Timer 2 prescaler value * Tcy

In this example, PR2 = 249, the Timer 2 prescaler = 1 and Tcy = 4us. Therefore,

PWM period = 250 * 1 * 4us = 1ms

The pulse width of the PWM waveform is determined by the value written to a special function register called CCPR1L (short for Capture/Compare/PWM channel 1 Register, low byte). The formula for calculating PWM pulse width is:

PWM pulse width = CCPR1L * Timer 2 presacler value * Tcy

Initially, CCPR1L = 125, the Timer 2 prescaler = 1 and Tcy = 4us. Initially therefore,

PWM period = 125 * 1 * 4us = 0.5ms

The values of PR2 and CCPR1L can be changed at any time, which will change the period or pulse width of the waveform. In this example, the period is constant at 1ms, giving a frequency of 1kHz. However, the value of CCPR1L changes every half a seconds, causing the duty cycle of the waveform to cycle through the values 50%, 10%, 0% repeatedly.

### C code and build script

This is the full C code for the XC8 compiler.

```//
// PIC18F4620 1kHz PWM example program
// Written by Ted Burke (http://batchloaf.com)
// Last updated 4-4-2013
//
// To compile with XC8:
//     xc8 --chip=18F4620 main.c
//

#include <xc.h>

#pragma config OSC=INTIO67,MCLRE=OFF,WDT=OFF,LVP=OFF,BOREN=OFF

int main(void)
{
// Set up PWM (see section 15.4 of the PIC18F4620 datasheet)
CCP1CON = 0b00001100;   // Enable PWM on CCP1
TRISC = 0b11111001;     // Make pin 17 (RC1/CCP2) an output
T2CON = 0b00000100;     // Enable TMR2 with prescaler = 1
PR2 = 249;   // PWM period = (PR2+1) * prescaler * Tcy = 1ms
CCPR1L = 25; // pulse width = CCPR1L * prescaler * Tcy = 100us

while(1)
{
// 50% duty cycle for 500ms
CCPR1L = 125;
_delay(125000);

// 10% duty cycle for 500ms
CCPR1L = 25;
_delay(125000);

// 0% duty cycle for 500ms
CCPR1L = 0;
_delay(125000);
}
}
```

I don’t use MPLAB; I just write my C code in a text editor, compile it with XC8 in a command window, then use the PICkit 2 application to transfer the hex file to the PIC. The build script I use (which contains just one command) is shown below. I save the C code as “main.c” and the build script in the same folder as “build.bat”.

```xc8 --chip=18F4620 main.c
```

Here’s how it looked when I compiled the program on my laptop:

### Measuring the waveform period and pulse width

I used the PICkit2 Logic Analyzer to take the following snapshot of the waveform when the duty cycle was 50% (when CCPR1L = 125). The signal was connected to channel 3 of the logic analyzer (pin 6 of the PICkit 2):

Here, the logic analyzer cursors are measuring the period of the waveform:

Here, the logic analyzer cursors are measuring the pulse width of the waveform:

Finally, here’s the waveform when the duty cycle is set to 10% (i.e. when CCPR1L = 25):

This entry was posted in Uncategorized. Bookmark the permalink.

### 47 Responses to Simple PWM example for the PIC18F4620

1. Geoffry says:

I’m currently doing a similar project with a pic18f14k50 on the new XC8 the only difference is I am using a dual latch relay as two different inputs into the pic, one latch(swithch) turns the relay 90 degrees when triggered, the other latch turns it back to 0 when triggered. How different would my program be from yours?

• batchloaf says:

Hi Geoffry,

Sorry, I don’t fully understand your question. You say the relay provides input to the PIC. What is the PWM controlling?

Maybe you mean that you are using two switches as inputs to the PIC and that the PIC is controlling a servo motor that turns back and forth through a 90 degree angle? I’m imagining that the servo should rotate to one position when the first button is pressed, and rotate to the other position when the second button is pressed. If so, I can modify the example above to show you how it would look.

Ted

• Geoffry says:

Yes, that what I mean. Sorry, that I wasn’t more clear. I’m using a relay as an input to switch back and forth instead of a push button. I want the relay to go to 90 degrees when the relay is switched on and back to 0 degrees when the relay is switched off.

2. Geoffry says:

I know also my pic has less pins and but uses the same type of registers, so there would be some changes to the code.

• batchloaf says:

Hi Geoffry,

I’m afraid I’m still a bit confused! Do you mean that you want a servo to go back and forth between 0 and 90 degrees as the relay switches on and off? If so, perhaps the following code would do it…?

```//
// PIC18F14K50 50Hz PWM example program
// Written by Ted Burke (http://batchloaf.com)
// Last updated 22-4-2013
//
// To compile with XC8:
//     xc8 --chip=18F14K50 main.c
//

#include

#pragma config FOSC=IRC,MCLRE=OFF,WDTEN=0,LVP=OFF,BOREN=OFF

int main(void)
{
// Set clock frequency to 500kHz, therefore Tcy = 8us
OSCCONbits.IRCF = 0b010;

// Set up PWM
CCP1CON = 0b00001100;   // Enable PWM on CCP1
TRISC = 0b11011111;		// Make CCP1 an output
T2CON = 0b00000110;     // Enable TMR2 with prescaler = 16
PR2 = 156;	// PWM period = (PR2+1) * prescaler * Tcy = 19.968ms
CCPR1L = 8;	// pulse width = CCPR1L * prescaler * Tcy = 1.024ms

while(1)
{
if (PORTCbits.RC4) CCPR1L = 12;	// 1.536ms pulses, i.e. 90 degrees
else CCPR1L = 8;				// 1.024ms pulses, i.e. 0 degrees
}
}
```

The PWM signal to control the servo is outputted on CCP1 (pin 5). The PWM period is 20ms, which is correct for most of the servos I use. The pulse width is either 1ms or 1.5ms (approx) depending on whether RC4 (pin 6) is high or low. That’s the pin you should connect your relay to. I estimated the pulse widths for 0 and 90 degrees based on the typical properties of servos I’ve used, but you may need to adjust the values for CCP1RL (I used 8 and 12).

I don’t have a PIC18F14K50 to try this program with, but I’ve run it in the MPLAB simulator and it seems to work. Let me know if that’s what you need or not.

Ted

• Geoffry says:

I tested on my pic and a servo and everything works great when the switch is turned on. When I turn it off however, the servo will not go back to 0. Do I need to try a different values for CCP1RL?

• batchloaf says:

Hi Geoffry,

It’s possible that you’re just missing a pull-up or pull-down resistor on RC4 (pin 6), so that the input voltage is not changing reliably when you switch the relay. This is by far the most common reason that students in my classes fail to get switch inputs working reliably.

Try disconnecting the relay from the input. Instead, use a piece of wire to connect pin RC4 to Vdd (pin 1) and Vss (pin 20) one after another (definitely not at the same time!). Connecting to Vdd will make the digital input (RC4) high. Connecting to Vss will make the digital input low. You should see the servo moving back and forth.

Exactly what model of servo and relay are you using by the way?

Ted

3. Geoffry says:

I’m using a S05NF Hobby servo, it only moves in 180 degree motion. Also, what type of pull down or pull up resistor should I use?

• batchloaf says:

Hi Geoffry,

Did you try connecting RC4 to Vss and Vdd one after another as I suggested?

For a pull-up or pull-down resistor on a switch input, I would normally use a 10kOhm resistor. Let’s assume you were going to use a pull-down… The basic idea is that the pull-down resistor is connected between RC4 and ground (Vss = 0V). Under normal circumstances, this causes the pin voltage (RC4) to remain at 0V. However, a switch (or relay) can be connected between RC4 and Vdd (5V) so that when the switch is pressed (or the relay is activated) the pin is short circuited to 5V.

Ted

• Geoffry says:

Thank you for everything. The resistor worked perfectly, I still have some minor adjustments to make but I’m on my way. Thanks again!

• batchloaf says:

You’re welcome! Well done on getting it working and best of luck getting the rest of your system finished.

Ted

4. none says:

From datasheet : PWM Period = [(PR2) + 1] • 4 • TOSC • (TMR2 Prescale Value)

Hi,
why you formula did not have “4” in this calculation?

• batchloaf says:

The PIC18F4620 (and maybe all PIC18F chips) performs one machine instruction every four clock cycles. Tosc is the clock period (the time taken for one complete cycle of the clock oscillator). The default clock frequency for the PIC18F4620 is 1MHz, so the default clock period is 1us. Therefore, by default (unless you change the clock frequency), the PIC18F4620 performs one machine instruction every 4us. This is what we call the “instruction cycle”, usually written as “Tcy”. All delays, counter periods, pulse widths, etc are specified relative to the instruction cycle.

• The Seeker says:

OK, I understand that PWM period formula, but the datasheet also says the PWM pulse width = CCPR1L * Timer2 prescaler value * Tosc (not Tcy as you wrote). Why is that?

• batchloaf says:

Tosc is the period of the clock oscillator. Tcy is the time taken to execute each machine code instruction. Since this PIC performs one machine code instruction every four clock cycles, the relationship between Tosc and Tcy is just

`Tcy = 4 * Tosc`

The version of the formula given in the datasheet just expresses the PWM period in terms of Tosc, rather than Tcy, so there’s an extra factor of 4 included.

5. help says:

i follow your way to write a code for 16f1829, but i no get a correct Hz 😦
i want 50Hz PWM with 50% duty cycle, can u help?

• batchloaf says:

Hi “help”,

I’ve just posted an example of a 50Hz square wave (i.e. 50% duty cycle) for the PIC16F1829. Here’s the link:

https://batchloaf.wordpress.com/2013/06/05/50hz-square-wave-example-for-pic16f1829/

Have a look and see if that will solve your problem. I’ve done it the lazy way – just bit-banging in a while loop with a delay to set the frequency. Is that enough for what you’re doing or do you need to do it using the PIC’s dedicated PWM facility? If so, I can have a look at adding a second example that does that.

Ted

6. help says:

Hello,
i try coding 16f1829 for generate the 50Hz PWM but no success.
i want 50Hz and 50% duty cycle, can you help and guide?

7. franco attolini says:

Ted,
Great example!
Im new to pic programming and now im trying to program a 10f322 in C to get a PWM do you have an example, im geting crazy.

Thank you .

Franco

8. mnoufalc says:

could you explain something more about PWM resolution. How does it get limited depending on the value of PR2 ?

• batchloaf says:

In this example, the generation of the PWM output is driven by Timer 2, which is basically just a register (well, a special function register) called TMR2 that counts up automatically in the background driven by the system clock. Depending on how you configure it, it can increment (increase its value by 1) every single instruction cycle, or every 16 instruction cycles, or every 64 instruction cycles or every 256 instruction cycles.

Another special function register called PR2 (Period Register for Timer 2) controls the maximum value for TMR2. Whenever TMR2 reaches the same value as PR2, it resets back to zero and then continues counting. If a PWM signal is generated based on TMR2, a pulse will normally start whenever TMR2 resets to zero and it will end when TMR2 reaches another value (e.g. CCPR1) which should be less than PR2. So the value of CCPRx controls the pulse width.

The range of possible values for CCPR1 ranges from 0 to PR2, which means there you can select from a total of (PR2+1) different pulse width settings. Therefore, the higher PR2 is, the more different values you can select for the pulse width. In many applications, the actual individual pulses will subsequently be filtered out, either using an actual filter, or because the thing being controlled cannot respond fast enough to reveal the individual pulses, so that all that is important is the average level. In such a situation, if PR2 is bigger, the number of possible pulse widths is greater and therefore the average level can be controlled with higher resolution.

Ted

9. Karthik says:

Hi TED!! i am new to PiC controller what are the basic books i have to refer to learn about the basics and can u suggest me an easy way to make inroads into my project.. i just need my PIC to trigger IGBTs used as inverters..

• batchloaf says:

Hi Karthik,

I’m sure there are lots of good introductory PIC books out there, but I’m afraid I can’t recommend a specific one because I haven’t read any of them.

If you’re planning to use the PIC18F4620, you might find the following page useful. It’s from an undergraduate module I teach where students use PIC microcontrollers to design a sumo robot.

http://robosumo.wordpress.com/pic18f4620/

You will definitely also want to download several PDF documents from Microchip for the exact chip you’re using. If you tell me which one, I might be able to suggest which documents to download. Not all the information you need will be in the datasheet – there are other documents that you’ll find useful, but unfortunately it’s not that obvious which ones you need.

The PIC18F4620 should be ideal for the purpose you want (triggering IGBTs in an inverter). There are actually several examples in my previous posts on this blog that address similar problems. I get a lot of questions about it from other readers.

Ted

10. VVSKUMAR says:

Hello , Im trying to generate 3 pulses with100khz using PIC18F2520. Anybody please help in this regards with any example program in C

• batchloaf says:

Hi VVSKUMAR,

Do you mean just three pulses, each of 5us duration, separated by gaps of 5us?
Or do you mean three continuous 100kHz signals coming out of three different pins?

You’ll need to provide more explanation.

Ted

11. Nathan says:

Hi Ted, i’m new to microchip programming. Right now, i’m supposed to generate a simple PWM signal by using dspic30f4011. Can you just give me some clues and examples on that? Thanks a lot!
Nathan

• batchloaf says:

Hi Nathan,

As it happens, we use the dsPIC30F4011 in my final year Robotics module (see http://roboted.wordpress.com), so I already have a few PWM examples online. I have an introductory information page for the dsPIC30F4011, which includes an example of PWM output using the hardware PWM module:

http://roboted.wordpress.com/dspic/

This year (last semester) I actually recommended to my Robotics students that they use the “Output Compare” module to generate PWM, which is very similar to using the PWM module, but slightly simpler in some respects. I wrote a few posts about PWM using Output Compare, including the following:

Have a look at those examples and see if they at least get you off the starting blocks. If you need me to explain anything, just leave another message on whichever post you’re looking at.

Ted

12. Nathan says:

Hi Ted,
I’ve looked at the examples you have offered to me. But what i need to do is just to generate a simple pwm signal for the mosfet switch. And i’ve got a part of code for pwm generation, can you help me take a look at it to check it whether it can be used to generate a pwm signal for me?

#include

_FOSC(CSW_FSCM_OFF & FRC_PLL16); //Fosc=16×7.37MHz, Fcy=30MHz
_FWDT(WDT_OFF); //watchdog timer off
_FBORPOR(MCLR_DIS); //disable reset pin

#define MILLISEC 29480 // 1 msec delay constant

//function declarations//
int main (void);
void ini(void);
void DelayNmSec(unsigned int N);

//variable declarations//

//main program begins here//
int main()
{

_TRISB0 = 0; // make RBO a digital output

while (1) // blink led on RB0
{
_LATB0 = 1;
DelayNmSec(15000000);
_LATB0 = 0;
DelayNmSec(15000000);
}

init(); // program initialization
while(1)
{
DelayNmSec(100); // for 100ms
ADCON1bits.SAMP = 0; // start converting
// if not the program will be trapped

}
return 0;
}

//initialization//
void init (void)
{
ADPCFG = 0xFFFB; // all portB = digital, RB2 = analog
ADCON1 = 0x0000; // SAMP bit = 0 ends sampling

// and starts converting
ADCHS = 0x0002; // connect RB2/AN2 as CH0 input
ADCSSL = 0; // channeling scanning is disabled

// set up PWM module//
PWMCON1 = 0x0011; // enable pwm pins and enable complementary mode
PTCON =0x8002;
PTPER = 736;
PDC1 = 736;
PTMR = 0;
}

void DelayNmSec(unsigned int N) // redundant N loop
{
unsigned int j;
while(N–)
for (j=0; j<MILLISEC;j++);
}

13. Nathan says:

Dear Ted,
The above message is i left. And now i got several stuff to mention. The method i’m going to used to generate pwm signal is ‘Motor Control PWM module’. And the switching frequency i’ve set is 20kHz. Therefore, the PTPER value can be calculated as shown:
Tpwm = Tcy * prescale * PTPER
(1/20^103) = 33.92ns * 64 * PTPER
PTPER = 23
Where i set pre scale is 64, Fcy = 29.48MHz, Tcy = 33.92ns, MIPs = 29.48.
The source oscillator frequency = 7.37MHz
PLL Multiplier = 16

Can you check whether the PTPER value that i have calculated is correct or not please?
I’m confused in that part.
Thanks!
Nathan

• batchloaf says:

Hi Nathan,

Yes, if the chip is running at 30 MIPS and the prescaler is set to 64, then PTPER=23 seems like is should give you 20kHz PWM.

However, you might consider setting the prescaler to a lower value than 64 so that you have more precise control of the duty cycle.

Also, remember that there is a factor of 2 difference in the PDC values (compared to PTPER). So, for example, if you set PDC1 to 23, that will give you a 50% duty cycle.

Ted

• Nathan says:

Hi Ted,
Thanks for your reply. Can you help me to take a look at the code i have upload which is on March 8, i’m not sure whether these code can be used to generate a simple pwm signal. I’m waiting for your reply.
Nathan

• batchloaf says:

Hi Nathan,

The structure looks reasonable to me and I can see that it’s closely modeled on the example 17-2 from the dsPIC30F Family Reference Manual, so hopefully that means it will work. I’ve modified one or two things, as you’ll see below, but it’s mostly just what you had before. Unfortunately, I don’t have a dsPIC here, so I haven’t been able to try out my version for real.

Some things I changed:

1. When you posted your code in the comment above, the header file included at the top was removed because WordPress thought the angle brackets around the header file name was a HTML tag. I put it back as “xc.h” – hopefully that’s what you had in there? I’m assuming you’re using the XC16 compiler?
2. I changed your millisecond delay function so that it uses the function __delay32(n) which delays by n instruction cycles. For example, when running at 30 MIPS, I would normally do “__delay32(30000)” to get a 1ms delay. The “32” in the function name is there because the argument you pass into the function can be a 32 bit value (i.e. you can use this for long delays).
3. I changed the value written into ADCON3 so that Tad is a bigger multiple of Tcy (the instruction cycle). I think the example you were looking at in the Family Reference Manual assumed that the chip was running at a lower clock rate and that Tad (the ADC clock cycle) would be long enough even if it was only a couple of times longer than Tcy. However, your example has the chip running at top speed (30 MIPS), which is what I normally do too. With the chip running this fast, Tcy is very short (33.33ns) so I think Tad needs to be a bigger multiple to be as long as they require. I haven’t actually gone through this calculation rigorously for ages, so if you’ve already calculated this and 3*Tcy really is long enough, then change it back!
4. I modified the PTCON value so that the PWM time base is in free running mode with the prescaler set to 1:1. This means PTMR counts from 0 up to PTPER over and over again. It increments once every instruction cycle. I set PTPER to 1500, which gives a PWM period of 1500 * Tcy = 50us. This corresponds to 20kHz PWM.

I might have changed one or two other small things, but I think that’s about it. Ok, here’s the modified code:

```//
// switching frequency i’ve set is 20kHz.
//

#include <xc.h>

_FOSC(CSW_FSCM_OFF & FRC_PLL16); // Fosc=16×7.37MHz, Fcy=30MHz
_FWDT(WDT_OFF);                  // watchdog timer off
_FBORPOR(MCLR_DIS);              // disable reset pin

#define MILLISEC 29480 // 1 msec delay constant

// function declarations
int main(void);
void init(void);
void DelayNmSec(unsigned int N);

// variable declarations

// main program begins here
int main()
{
_TRISB0 = 0; // make RBO a digital output

while (1) // blink led on RB0
{
_LATB0 = 1;
DelayNmSec(500);
_LATB0 = 0;
DelayNmSec(500);
}

init(); // program initialization

while(1)
{
ADCON1bits.SAMP = 1;      // starting sampling
DelayNmSec(100);          // for 100ms (NB This is much longer than necessary for sampling)
ADCON1bits.SAMP = 0;      // start converting
}

return 0;
}

// initialization
void init(void)
{
ADPCFG = 0xFFFB; // all portB = digital except RB2 = analog
ADCON1 = 0x0000; // SAMP bit = 0 ends sampling and starts converting
ADCHS = 0x0002;  // connect RB2/AN2 as CH0 input
ADCSSL = 0;      // channeling scanning is disabled

// set up PWM module
PWMCON1 = 0x0011; // enable pins PWM1H and PWM1L in complementary mode
PTCON = 0x8000;   // enable PWM time base, free running mode, prescaler = 1:1
PTPER = 1500;     // Tpwm = 1500 * Tcy = 1500 / 30e6 = 50us, i.e. Fpwm = 20kHz
PDC1 = 1500;      // Set duty cycle to 50% initially
PTMR = 0;
}

void DelayNmSec(unsigned int N) // redundant N loop
{
while(N--) __delay32(MILLISEC);
}
```

Please give it a try and let me know how you get on.

Ted

Hi!
I use p18f45k20 microcontroller and I need to output sounds to the speaker or headphones.
All I found is a code that outputs continuous tone with one of eight frequencies(8Mhz Fosc, 4Mhz, 1Mhz etc…) But how I can change code to make musical notes and produce some simple melody?
I use MPLABX and the C code I found is attached on this website http://www.microchip.com/forums/m705595.aspx

Hi again. Don’t need help anymore. Did it nice. Now it plays any melody with any duration and pauses.

• batchloaf says:

Great! Glad to hear you got it working.

Ted

15. prakash says:

is it possible to run the stepper motor at 10m/s..?

• batchloaf says:

Hi Prakash,

It depends what you mean by “10m/s”. If you mean “metres per second”, then I’m not quite sure which metres you’re talking about. Maybe you mean the speed of something driven by the stepper motor? If so, it depends on what the motor is mechanically connected to (gearing, wheel size, etc).

However, if you actually meant “ms” as in milliseconds, then maybe you mean the time delay between steps of the motor? A 10ms step time would be equivalent to 100 steps per second, which would be fine with most of the stepper motors I’ve used, but you’ll need to check the specification of your own stepper motor to be sure.

As far as using the ATxmega256A3BU, generating the digital waveforms to drive a stepper motor at 100 steps per second should be no problem at all. However, you’ll presumably need some interface electronics between the ATxmega microcontroller and the windings of the stepper motor. If it’s a small stepper, then something like a SN754410NE driver chip (or L293D which is more or less equivalent) would probably do the trick. I have very little experience with ATxmega microcontrollers, but I normally use an SN754410NE if I’m controlling a stepper using a PIC or MSP430 microcontroller.

Ted

16. prakash says:

uaing ATXMEGA 256A3BU…

17. zaw win myat says:

Hi!
I want to get PWM output for speaker from ADC. I don’t know how to convert ADC’s 10bits to PWM. I use 18F452. Please can you help me?

• batchloaf says:

Hi Zaw Win Myat,

What have you got working so far? Do you already have ADC and/or PWM working separately?

Also, what sampling frequency do you need to achieve? For a given oscillator frequency, there will be an upper limit on the sampling frequency that’s achievable at 10-bit resolution.

Ted

18. omar says:

hello

19. bindu says:

Hi,
I am fresher ,i need PWM GENERATION OF 1KHZ WHENEVER OUTPUT RELAY IS ON.. PIC12F675. GPIO2 IS THE OUTPUT

• bindu says:

HI TED

20. HAMZAH BIN ZAINUDDIN says:

hi sir, may i get circuit for servo motor. im doing this kind project by using servo motor, then i was follow all your instruction. then i was success by compiler the code. now i have a problem, the problem is circuit for servo motor. may i know, how to established the circuit by te proper way? can u give the example, how to create te circuit for pic18f4620?
tq sir bcause reading.. hope u can reply as soon as possible..

• Ebuka says:

Hi ted, keep the good work up, thanks, please can you help me to write two phase interleave complimentary pwm with 18f26k22, I mean 180 degree out of phase. or 3 phase shifted pwm with 120degree with 18f26k22.

21. firefly says:

Hi,
I have strange problem with my pic18f46k22 pwm, I am using ccp5 as standard pwm I am able to set it up and it is working. PR2 = 254 and CCPR2L = 127 it is working. now I decided to generate some clock signals (NOT PWM operation) by changing PR2 and CCPR2L, I kept CCPR2L = 0.5*PR2 for 50% duty cycle. Now i decreased PR2 from 254 to 10 in steps of 10 Upto PR2 = 200 it is working, then it failed to give an o/p on the pin.
now again I used a for loop to reduce PR2 in steps of 1 up to around 190 it is working. by that time the pin voltage increases from 2.57v to 5v and the pulses stopped, pin o/p is just 5v why does this happen where did I went wrong? can any body help me
code & settings is attached

#define _XTAL_FREQ 64000000
#include
#include “PIC18F46K22.h”

int tm,m,p;
unsigned int n;

void delay(unsigned int len)
{
for(int i = 0; i 100)
{
n=0;
PR2 = PR2 – 1;
p = PR2*.4;
CCPR2L = p;
if(PR2 > 8);
CCPR3L = 1000;
TRISB5 = 1;//digital i/p is enabled for tmr3 i/p
ANSB5 = 0;//analog i/o is disabled

// CCP1CON = 0b00001100;//PWM mode is selected
// PSTR1CON = 0b00010001;
// ECCP1AS = 0b00000000;
// PWM1CON = 0b10000000;
// //CCP5 setup
CCPTMRS1 = 0b00000011;//TMR2 selected for ccp5
PR2 = 254;//0b11111111;//PR2 is loaded with 255
CCP5CON = 0b00001100;//PWM mode is selected
CCPR2L = 127;//half of PR2 is loaded
//
// //TMR2 setup
T2CON = 0b00000100;//1:1 post scaler, tmr2on,1:1 prescaler
delay(10);
// TRISC2 = 0;//digital o/p is enabled for ccp5
// ANSC2 = 0;//analog i/o is disabled
// TRISD5 = 0;//digital o/p is enabled for ccp5
// ANSD5 = 0;//analog i/o is disabled
// TRISD6 = 0;//digital o/p is enabled for ccp5
// ANSD6 = 0;//analog i/o is disabled
// TRISD7 = 0;//digital o/p is enabled for ccp5
// ANSD7 = 0;//analog i/o is disabled
TRISE2 = 0;//digital o/p is enabled for ccp5
ANSE2 = 0;//analog i/o is disabled
// //TRISD1 = 0;//digital o/p is enabled for ccp4
// //ANSD1 = 0;//analog i/o is disabled
TMR3H = 0;
TMR3L = 0;

CCP3IE = 1;//interrupt enabled
while(1)
{
// tm = TMR2;
// m = LATC2;
// LATC2 = 0;
n++;
if(n>60000)
{
n=0;
m++;
if(m>=30)
{
m=0;
PR2 = PR2 – 1;
p = PR2*.5;
CCPR2L = p;
}
if(PR2 <= 100)
{
PR2 = PR2;//used just to add a break point
}
}
}
}

// CONFIG1H change it also
#pragma config FOSC = INTIO67 // Oscillator Selection bits (Internal oscillator block)
#pragma config PLLCFG = ON // 4X PLL Enable (Oscillator used directly)
#pragma config PRICLKEN = ON // Primary clock enable bit (Primary clock is always enabled)
#pragma config FCMEN = OFF // Fail-Safe Clock Monitor Enable bit (Fail-Safe Clock Monitor disabled)
#pragma config IESO = OFF // Internal/External Oscillator Switchover bit (Oscillator Switchover mode disabled)

// CONFIG2L
#pragma config PWRTEN = ON // Power-up Timer Enable bit (Power up timer enabled)
#pragma config BOREN = OFF // Brown-out Reset Enable bits (Brown-out Reset disabled in hardware and software)
#pragma config BORV = 190 // Brown Out Reset Voltage bits (VBOR set to 1.90 V nominal)

// CONFIG2H
#pragma config WDTEN = OFF // Watchdog Timer Enable bits (Watch dog timer is always disabled. SWDTEN has no effect.)
#pragma config WDTPS = 32768 // Watchdog Timer Postscale Select bits (1:32768)

// CONFIG3H
//#pragma config CCP2MX = PORTC1 // CCP2 MUX bit (CCP2 input/output is multiplexed with RC1)
#pragma config CCP2MX = PORTB3 // CCP2 MUX bit (CCP2 input/output is multiplexed with RB3)
#pragma config PBADEN = ON // PORTB A/D Enable bit (PORTB pins are configured as analog input channels on Reset)
//#pragma config CCP3MX = PORTB5 // P3A/CCP3 Mux bit (P3A/CCP3 input/output is multiplexed with RB5)
#pragma config CCP3MX = PORTE0 // P3A/CCP3 Mux bit (P3A/CCP3 input/output is multiplexed with RE0)
#pragma config HFOFST = OFF // HFINTOSC Fast Start-up (HFINTOSC output and ready status are delayed by the oscillator stable status)
//#pragma config T3CMX = PORTC0 // Timer3 Clock input mux bit (T3CKI is on RC0)
#pragma config T3CMX = PORTB5 // Timer3 Clock input mux bit (T3CKI is on RB5)
#pragma config P2BMX = PORTD2 // ECCP2 B output mux bit (P2B is on RD2)
#pragma config MCLRE = INTMCLR // MCLR Pin Enable bit (RE3 input pin enabled; MCLR disabled)

// CONFIG4L
#pragma config STVREN = ON // Stack Full/Underflow Reset Enable bit (Stack full/underflow will cause Reset)
#pragma config LVP = OFF // Single-Supply ICSP Enable bit (Single-Supply ICSP disabled)
#pragma config XINST = OFF // Extended Instruction Set Enable bit (Instruction set extension and Indexed Addressing mode disabled (Legacy mode))

// CONFIG5L
#pragma config CP0 = OFF // Code Protection Block 0 (Block 0 (000800-003FFFh) not code-protected)
#pragma config CP1 = OFF // Code Protection Block 1 (Block 1 (004000-007FFFh) not code-protected)
#pragma config CP2 = OFF // Code Protection Block 2 (Block 2 (008000-00BFFFh) not code-protected)
#pragma config CP3 = OFF // Code Protection Block 3 (Block 3 (00C000-00FFFFh) not code-protected)

// CONFIG5H
#pragma config CPB = OFF // Boot Block Code Protection bit (Boot block (000000-0007FFh) not code-protected)
#pragma config CPD = OFF // Data EEPROM Code Protection bit (Data EEPROM not code-protected)

// CONFIG6L
#pragma config WRT0 = OFF // Write Protection Block 0 (Block 0 (000800-003FFFh) not write-protected)
#pragma config WRT1 = OFF // Write Protection Block 1 (Block 1 (004000-007FFFh) not write-protected)
#pragma config WRT2 = OFF // Write Protection Block 2 (Block 2 (008000-00BFFFh) not write-protected)
#pragma config WRT3 = OFF // Write Protection Block 3 (Block 3 (00C000-00FFFFh) not write-protected)

// CONFIG6H
#pragma config WRTC = OFF // Configuration Register Write Protection bit (Configuration registers (300000-3000FFh) not write-protected)
#pragma config WRTB = OFF // Boot Block Write Protection bit (Boot Block (000000-0007FFh) not write-protected)
#pragma config WRTD = OFF // Data EEPROM Write Protection bit (Data EEPROM not write-protected)

// CONFIG7L
#pragma config EBTR0 = OFF // Table Read Protection Block 0 (Block 0 (000800-003FFFh) not protected from table reads executed in other blocks)
#pragma config EBTR1 = OFF // Table Read Protection Block 1 (Block 1 (004000-007FFFh) not protected from table reads executed in other blocks)
#pragma config EBTR2 = OFF // Table Read Protection Block 2 (Block 2 (008000-00BFFFh) not protected from table reads executed in other blocks)
#pragma config EBTR3 = OFF // Table Read Protection Block 3 (Block 3 (00C000-00FFFFh) not protected from table reads executed in other blocks)

// CONFIG7H
#pragma config EBTRB = OFF // Boot Block Table Read Protection bit (Boot Block (000000-0007FFh) not protected from table reads executed in other blocks)

// #pragma config statements should precede project file includes.
// Use project enums instead of #define for ON and OFF.