Blinking LED using PWM - PIC18f4520

Status
Not open for further replies.

Ecappp

New Member
Specifications:
Microcontroller: PIC18f4520
Crystal: 4 MHz
Language: C Programming (not assembly codes)

Basically I'm trying to blink a LED using PWM to enable the on-time to be variable. However, I can't seem to blink the LED without using the LED toggle and delay functions. By using the toggle function, I have found that the on-time cannot be changed.

May anyone give me an idea on what I can do to go around this?

Last edited:

blueroomelectronics

Well-Known Member
Post your code, and compiler version.

At 4MHz the PWM is going to be pretty fast. How slow do you want it to blink?

Ecappp

New Member
Compiler: MPLAB C18 C Compiler (MCC18)

I don't exactly have a specific speed that I want the LED to blink (duty cycle interchangeable). I just need to be able to see the speed of the blinking clearly on the hardware. The crystal can't be changed because it is built-in into the hardware.

Code:

#include <p18f4520.h>

void main ( )
{

TRISB = 0;
TRISC = 0b11111011; // RC2 as output
T2CON = 0b00000101; // Timer 2 On, postscale = 1:1, prescale = 1:4
PR2 = 64; // Set PR2 = 64 for 52 ?s
CCPR1L = 0b00001101; // CCPR1L:CCP1CON<5:4> = 52
CCP1CON = 0b00001111; // DC1B1 & DC1B0 = 0, PWM mode
PORTBbits.RB1 = PORTCbits.RC2; //blinking LED according to PWM
while(1);

}

blueroomelectronics

Well-Known Member
What do you figure your PWM speed is? Anything faster than 30Hz may be impossible to see as a flash.

Code:
PORTBbits.RB1 = PORTCbits.RC2;     //blinking LED according to PWM
while(1);
Do you see anything wrong here? How will RB1 change?

Last edited:

Ecappp

New Member
Well, regarding the code you quoted, I do know there is something wrong there. I was trying to link the LED to the PWM but it obviously failed.

If I were to try configuring the speed as less than 30Hz, how may I get the PR2 value to be less than 255? I don't know of a way to bring it lower than that.

be80be

Well-Known Member
Internal oscillator support - 31 kHz to 8 MHz, up to 32 MHz with 4X PLL
looks like you could set that for any thing you would want

Ecappp

New Member
If the oscillator used is big, does the PR2 value increase as well? Is the crystal oscillator and the internal oscillator support two different things?

Code:
PORTBbits.RB1 = PORTCbits.RC2;     //blinking LED according to PWM
while(1);
By the way, can anyone tell me what is wrong (I know it's wrong) with this statement and how do I rewrite it?

Last edited:

tresca

Member
You need to toggle that bit

It should be more like
Code:
PORTBbits.RB1 ^= 1;     //blinking LED according to PWM
while(1);
This will toggle the RB1 each time this line is executed.

tresca

Member
If the oscillator used is big, does the PR2 value increase as well? Is the crystal oscillator and the internal oscillator support two different things?
The value does not increase but the time it takes to overflow does. Each clock cycle, the value of PR2 increases. Thats all the timer does. But if you clock is at 4MHz, then each increment of PR2 occurs in 1us. If you change your clock frequency to say 8Mhz, then each increment of PR2 occurs 500ns. So if you are looking for a specific PWM frequency, your PR2 value needs to be updated to account for the clock frequency.

Make sense ?

be80be

Well-Known Member
I'm not good with C but the osc can be change the Internal oscillator clock from 8mhz 4mhz 2mhz 1 mhz and lower down to 32khz which would give you real slow pwm and if your using a CRYSTAL/CERAMIC RESONATOR your can turn it off and use Internal oscillator

arhi

Member
Code:
  [b]while(1);[/b]

What is the intention of this?! while(1); does "loop in one spot" it will never change / set / do anything .. the app will just "stand still" at that position....

disregarding the config bits etc ..
Code:
#include <p18f4520.h>

void main ( )
{
TRISB = 0;
TRISC = 0b11111011; // RC2 as output
T2CON = 0b00000101; // Timer 2 On, postscale = 1:1, prescale = 1:4
PR2 = 64; // Set PR2 = 64 for 52 us
CCPR1L = 0b00001101; // CCPR1L:CCP1CON<5:4> = 52
CCP1CON = 0b00001111; // DC1B1 & DC1B0 = 0, PWM mode
while(1){
PORTBbits.RB1 = PORTCbits.RC2; //blinking LED according to PWM
}
}
In theory this will blink B1 almost the same time as RC2
RC2 is "blinked" by hardware ccp (pwm) module.

if you only need to blink the RC2 then you do not need the b1 part
Code:
#include <p18f4520.h>

void main ( )
{
TRISB = 0;
TRISC = 0b11111011; // RC2 as output
T2CON = 0b00000101; // Timer 2 On, postscale = 1:1, prescale = 1:4
PR2 = 64; // Set PR2 = 64 for 52 us
CCPR1L = 0b00001101; // CCPR1L:CCP1CON<5:4> = 52
CCP1CON = 0b00001111; // DC1B1 & DC1B0 = 0, PWM mode
while(1); // DO NOTHING - hw pwm module will blink led
}

I do not see the config here but if you are running it at 4MHz the speed of the pwm will be too fast and there is no way you can see the blinking with naked eye .. if you want blinking that you can see, you have to forget about pwm as you cannot make pwm go that slow (max that you can notice is about 100Hz and even that is almost impossible to tell ... the 15Hz is kinda max for "noticeable" blink) and PWM usually do not go under few KHz because:

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

your TOSC is 1/4000000, max TMR2 prescale is 16, max PR2 is 255 so max period is

256 * 4 * (1/4000000) * 16 = 0.004096 => 1/0.004096 = 244.14Hz

So with 4MHz the lowest you can go is 244Hz - there is NO WAY you can see that with naked eye. not to mention that you are using 1:4 prescale and not 1:16 so your led is blinking at almost 1KHz

If you need to be able to see the led blink, use the delay function

Code:
#include <p18f4520.h>

void main ( )
{
TRISB = 0;
TRISC = 0b11111011; // RC2 as output
LATBbits.LATB1 = 0;
LATCbits.LATC2 = 0;

while(1){
LATBbits.LATB1 ^= 1;
LATCbits.LATC2 ^= 1;
Delay10KTCYx(200); //wait 2000000 cycles
}
}

Last edited:

arhi

Member
btw, you are probably trying:

Code:
#include <p18f4520.h>

void main ( )
{
unsigned char dcycle;
TRISB = 0;
TRISC = 0b11111011; // RC2 as output
T2CON = 0b00000101; // Timer 2 On, postscale = 1:1, prescale = 1:4
PR2 = 64; // Set PR2 = 64 for 52 us
CCPR1L = 0b00001101; // CCPR1L:CCP1CON<5:4> = 52
CCP1CON = 0b00001111; // DC1B1 & DC1B0 = 0, PWM mode

// the led is now pwm'd with 1KHz on RC2

dcycle = 0;
while(1){ // loop forever
// change the brightness of the LED by changing PWM DC
// PWM Duty Cycle = (CCPRXL:CCPXCON<5:4>) • TOSC • (TMR2 Prescale Value)
CCPR1L = dcycle++;
Delay10KTCYx(20); //wait 200000 cycles
}
}
this will change the brightness of your led on RC2 every 200ms (only 8bit resolution - 10 bit resolution is possible but not needed for this example) 256 times and then will start from scratch

Last edited:

arhi

Member
and .. if you want to blink and not to smoothly light more :

Code:
#include <p18f4520.h>

void main ( )
{
TRISB = 0;
TRISC = 0b11111011; // RC2 as output
T2CON = 0b00000101; // Timer 2 On, postscale = 1:1, prescale = 1:4
PR2 = 64; // Set PR2 = 64 for 52 us
CCPR1L = 0b00001101; // CCPR1L:CCP1CON<5:4> = 52
CCP1CON = 0b00001111; // DC1B1 & DC1B0 = 0, PWM mode
// the led is now pwm'd with 1KHz on RC2

while(1){ // loop forever
//LED ON
CCPR1L = 0xFF;
Delay10KTCYx(20); //wait 200000 cycles
//LED OFF
CCPR1L = 0;
Delay10KTCYx(20); //wait 200000 cycles
}
}

arhi

Member
and .. for the end of mine involvement .. if you are using C18 why don't you use available libraries ... there's pwm library .. :

Function prototypes
#include <pwm.h>
void OpenPWMx ( char PR2 ); // Configure PWM channel x.
void SetDCPWMx ( unsigned int dutycycle ); // Write a new duty cycle value to PWM channel x.
void ClosePWMx ( void ); // Disable PWM channel x.

Notes:

1. PR2 can be any value from 0x00 to 0xff. This value determines the PWM frequency by using the following formula:
PWM period =[(PR2) + 1] x 4 x TOSC x TMR2 prescaler

2. The value of dutycycle can be any 10-bit number. Only the lower 10-bits of dutycycle are written into the duty cycle registers. The duty cycle determines the high time of the PWM waveform.

3. PWM uses TIMER2 for time base. In addition to opening the PWM, TIMER2 must also be opened with an OpenTimer2(...) statement before the PWM will operate. See the other manual for the timer functions.

4. TIMER2 postscaler is not used in the determination of the PWM frequency. TIMER2 postscaler could be used to generate TMR2 interrupts at a different frequency than the PWM output.

Ecappp

New Member
and .. if you want to blink and not to smoothly light more :

Code:
  while(1){ // loop forever
//LED ON
CCPR1L = 0xFF;
Delay10KTCYx(20); //wait 200000 cycles
//LED OFF
CCPR1L = 0;
Delay10KTCYx(20); //wait 200000 cycles
}
May i know why is CCPR1L = 0xFF instead of my desired CCPR1L value?

I've tried changing the value of CCPR1L to different values and i noticed that has effect for buzzer tone. However, the blinking of the LED looks the same. How do I know if PWM has any effect on the LED?

Last edited:

blueroomelectronics

Well-Known Member
I would run it through MPLAB's simulator, you can watch any I/O pin including PWM waveforms.

arhi

Member
attach a scope and look at the signal. That is the easiest way if you own a scope. If not then some simulator (MPLAB, ISIS, OshonSoft ..)

the CCPRXL is there to change duty cycle ... the duty cycle defines the ratio between on and off cycle so if DC is 100% the signal is effectively 100% ON, if DC is 0% the signal is effectively OFF, and if DC is 50% the signal is effectively half time on and half time off ...

Check figure 15-4 on page 144 of the datasheet....

Ecappp

New Member
Thanks for all the replies. They have been very helpful.

fightstar

New Member
hi everyone, im adam from france im 20
im in an internship now ,

im working on an interactive panel of monochrom leds, i have done the scheme on the electronic board using a pic18F4520 via TLC 5940 for driving 16 leds plus 2 IR leds "one transmits the signal while the second receives it" in order to blink leds just by moving one's hand upon the panel, i have beeen inspired by the schemes with "arduino" micros already done on the web by other people , and i tried to do the same with the pic , i think im ready for the next level by programming the 16 leds ,I HAVE TO DO IT WITH c language, but as im not that good with C , i hope you could give me some help through this study,

i have done the same with my pic http://students.washington.edu/acleone/codes/tlc5940arduino/img/breadboard-arduino-tlc5940_close.png

YouTube - Interactive LED Panels: New version, white LEDs its the concept but that is analogic , im using microcontroler so as to be programmed in a digital way

blueroomelectronics

Well-Known Member
Give Swordfish BASIC a try. Very easy to learn & use.

Status
Not open for further replies.