View Full Version : Fading LEDs using a PWM signal from the Edubot
For quick subject indexing purposes, this thread is turning into a discussion on timers and the use of custom PWM signals on the PIC18F8520
A while ago, some of you may remember this thread (http://www.chiefdelphi.com/forums/showthread.php?t=21915) where I presented an idea for a neat little car tachometer hack. I never really got around to finishing this, but for my high tech class, the opportunity has come up to make a demonstration of microcontrollers. I decided that it would be interesting to use the Edubot (both because of simplicity and familiarity) to create the tachometer hack mentioned in that thread.
Writing the code to gather the input signal and find the frequency (and thus, the RPM) is no problem for me. As for driving the LEDs, it was mentioned that the proper way is to use a PWM signal, just like was done for the IR beacons this year. Eventually I'm going to ask for help about using perhaps this IC (http://www.semiconductors.philips.com/pip/PCA9532.html) (again, mentioned in the previous thread), but I don't really have time to learn about all the I2C bus stuff for this project. Instead, I have some questions about the PWM code used in this year's IR beacons.
First, can the Edubot generate a PWM signal with a frequency fast enough for the blink not to be 'detected' by the human eye? When I attached a status LED to this year's IR beacon, a flicker was recognized, much like some people can detect the 70-75Hz flicker of computer monitor.
Second, has there been a writeup explaining the custom PWM code used for the IR beacons? Specifically, I'd like to know how to adjust the duty cycle and frequency to create the best 'fade' effect possible.
Any of you advanced programming gurus have any suggestions?
Astronouth7303
23-03-2004, 11:37
Check User_Initialization(), step 5. there is an option (at least in the FRC) to set some pins up as custom.
CrashZero
23-03-2004, 13:08
I will gladly help but I am not sure just what you are trying to do. Are you trying to make the LED's blink fast enough that human eyes cannot detect it or do you want it to be slower so that it can be detected? :confused:
Andrew Rudolph
23-03-2004, 14:06
He wants to use the EDU bot to dim the leds, a common way to dim leds is to have them blink. so he wants it to blink fast enough so it just appears as the led is dim.
CrashZero
23-03-2004, 15:25
Ok i think that I understand what you want now, and I don;t think that I know a way to get it to do that. Sorry.
Kevin Watson
23-03-2004, 15:40
Dan,
This can be done using the PIC's dedicated PWM hardware. Have a look at the beacon code and note where the 40KHz duty cycle is set to 50%. You can get the effect you want by changing this value. The beacon drive circuit can be used to drive an array of LEDs too. If this isn't clear, I'll write some example code and post it.
-Kevin
Alan Anderson
23-03-2004, 15:52
First, can the Edubot generate a PWM signal with a frequency fast enough for the blink not to be 'detected' by the human eye? When I attached a status LED to this year's IR beacon, a flicker was recognized, much like some people can detect the 70-75Hz flicker of computer monitor.
Why not measure it and see?
The IR beacons aren't simple PWM signals. They are driven with short bursts of high-frequency pulses. The bursts repeat at a rate low enough that you can perceive as a flicker.
I don't know what the PWM frequency is, but I'd be very surprised if it were slow enough to detect with your eyes.
NoRemorse
23-03-2004, 17:03
PWM = pulse width modulation
its a serious of I's ans O's, and the higher the number, thr more of accurance of I's
the duty cycle is the total length between 2 leading edges
FotoPlasma
23-03-2004, 17:12
PWM = pulse width modulation
its a serious of I's ans O's, and the higher the number, thr more of accurance of I's
the duty cycle is the total length between 2 leading edges
The duty cycle is measured as a percentage of the total period of the square wave. You can also describe this as time between the rising edge and the falling edge of the square wave. I don't think that "the total length between 2 leading edges" was concise enough.
I'm sure there're other threads that explain the fundamentals of PWM, PPM, and whatever else.
NoRemorse
23-03-2004, 17:39
Your right, that was a typo on my part.
Kevin Watson
23-03-2004, 17:41
...the duty cycle is the total length between 2 leading edgesActually, the amount of time between successive edges of the same type (i.e., rising or falling) is the period. One divided by the period is the frequency. Duty cycle, usually expressed as a percentage, is the amount of time the pulse is high divided by the total period.
-Kevin
I don't know what the PWM frequency is, but I'd be very surprised if it were slow enough to detect with your eyes.
You can't detect it precisely (the human eye notices flashes of light only to about 25Hz-30Hz - coincidentally the framerate of television). However, some people can observe a flicker. Take your computer CRT - those are usually 70-75Hz. The problem with CRTs is this flicker can be detected and the subconcious detection of this flicker is one of the reasons prolonged exposure to a monitor leads to eye strain. The flicker is especially noticable from the corner of your eyes because the light detecting cells on the edges of the human eye are more sensitive to light vs. dark while the cells in the middle of the human eye are more sensitive to color. Proof: ever been stargazing and see a dim star in the corner of your vision but when you center your vision on it, it disapears? The corner of your vision is more sensitive to contrast while the center is more sensitive to color (if you think about this from an evolutionary standpoint, this also makes sense - our ancestors would have benefited from detecting moving objects in the corners of their vision). Anyways, the point of this extended tangent is that yes, the blinking is too fast to detect outright, but some people can observe the flicker much like the flicker of a computer monitor is observed.
Dan,
This can be done using the PIC's dedicated PWM hardware. Have a look at the beacon code and note where the 40KHz duty cycle is set to 50%. You can get the effect you want by changing this value. The beacon drive circuit can be used to drive an array of LEDs too. If this isn't clear, I'll write some example code and post it.
-Kevin
Okay, so I've examined the use of timers with the help of your beacon code and interrupt template from kevin.org... however, I still have some questions
// initialize timer 2, which generates the 40KHz IR carrier frequency
PR2 = PWM_TOTAL_PERIOD; // set PWM frequency (defined in beacon.h) [154]
TMR2 = 0; // clear timer2 register [142]
T2CONbits.T2OUTPS0 = 0; // setup 1:1 postscale [141]
T2CONbits.T2OUTPS1 = 0;
T2CONbits.T2OUTPS2 = 0;
T2CONbits.T2OUTPS3 = 0;
T2CONbits.T2CKPS0 = 0; // setup 1:1 prescale [141]
T2CONbits.T2CKPS1 = 0;
T2CONbits.TMR2ON = 1; // start timer 2 [141]
So, with a 1:1 prescale, one timer tick is 1e-7 seconds, 100 ns. Assuming PWM_TOTAL_PERIOD is 250, that means the timer rollover handler is called every 25e-6 seconds, or 25 microseconds. 1 / 25e-6 results in the 40KHz frequency described in the comment. I can now see how to use a timer to generate the interrupt frequency needed. However, I don't see how this is used to generate the PWM signal
beacon.h:
// This sets the PWM high period, which should be
// half of PWM_TOTAL_PERIOD for a 50% duty cycle.
// Set to 10000000*desired_high_period.
#define PWM_HIGH_PERIOD 125
beacon.c:
// initialize PWM 1, which generates type 0 beacon waveforms
TRISCbits.TRISC1 = 0; // make sure CCP2/PWM1 is setup as an output [110]
CCPR2L = PWM_HIGH_PERIOD; // set CCP2/PWM 1 duty cycle (defined in beacon.h) [
I don't see any information about what CCPR2L is, or what timer 2 is used for. My problem is I found where you initialized timer 2 to create a 40KHz pulse, but I'm not seeing how it goes about creating the signal. What does timer 2 do (I don't see any interrupt handling routine)? What is CCPR2L and how does that relate to a duty cycle?
steven114
23-03-2004, 21:44
There is some information in the IFI default code about how to enable a user PWM, along with assigning a duty cycle, etc. The rest of the information is in the PIC datasheet on Microchip's website.
There is some information in the IFI default code about how to enable a user PWM, along with assigning a duty cycle, etc. ...
Any hints on where? ;-)
steven114
23-03-2004, 22:46
http://www.microchip.com/download/lit/pline/picmicro/families/18fxx20/39609b.pdf
http://www.microchip.com/download/lit/pline/picmicro/families/18fxx20/39609b.pdf
er, what I really need is for someone to point out what timer 2 actually does in the beacon code. I can see that it counts at 40KHz, but where is the code that does something with that 40KHz count? What happens once the timer counts its 250 ticks and where is the code for that?
Kevin Watson
24-03-2004, 01:21
er, what I really need is for someone to point out what timer 2 actually does in the beacon code. I can see that it counts at 40KHz, but where is the code that does something with that 40KHz count? What happens once the timer counts its 250 ticks and where is the code for that?It's all done automatically in hardware. See page 154 of the data sheet. Here (http://kevin.org/frc/edu_led_pwm.zip) is example code that does what you need. It simulates a light dimmer by reading the voltage on analog input 1 and adjusts the LED brightness proportionally to the voltage read.
-Kevin
Astronouth7303
24-03-2004, 07:32
User_Initialization, step 5 (see previous post)
Kevin Watson
24-03-2004, 16:44
It occured to me that you should be able to try the code (posted above) without an external driver because IFI has built in the current limiting resistors on the PWM outputs. Just attach the LED cathode (shorter of the two leads) to the ground pin and the anode to the PWM 1 or 2 outputs. If you don't have a potentiometer to hang on analog input 1, alter the code in user_routines.c to just ramp up the value in CCPR2L (or CCPR3L) from 0 to 255 and you'll notice the LED's brightness change from off to full brightness. Hopefully someone will take this code and come up with some really cool lighting effects for their 'bot. One idea that comes to mind is to have multiple arrays of different color LEDs underneath the 'bot providing a light show during the competition.
-Kevin
It's all done automatically in hardware. See page 154 of the data sheet. Here (http://kevin.org/frc/edu_led_pwm.zip) is example code that does what you need. It simulates a light dimmer by reading the voltage on analog input 1 and adjusts the LED brightness proportionally to the voltage read.
-Kevin
Just got back from the Philly regional, so I can dedicate some time back to this project now. I've spent some time looking at this stuff, and lemme see if I have the basic theory right...
-------
In one of the whitepapers or the example codes about timers, I read something about each timer having being slightly different and having its own idiosyncrasies... one of timer2's idiosyncrasies is this is the only timer that controls custom PWMs - if you set an output to a user pwm timed by the internal microchip hardware (i.e. no external oscillator or something like that), timer2 is what determines the timing. One period of the PWM signal is the amount of time it takes for timer2 to reach its rollover value and can be changed by either changing the duration of one timer2 clock tick or by changing the PR2, or Timer2 Period Register, value.
The duty cycle of the PWM signal is programmed through the CCPR2L/CCPR3L byte, or the Capture/Compare/PWM Register 1/2 Low Byte. When the timer value is below this register's value, the output pin is high, and when the timer value is above this register's value, the output pin is low. Thus, to create a pwm signal with a 50% duty cycle, you set the CCPRxL value to 1/2 the PR2 value, and to create a signal with a 25% duty cycle, you set the CCPRxL value to 1/4 the PR2 value.
----
Is this basic theory explanation right, or am I missing some part of it?
Also, what is the relationship between CCPRxL and CCPRxH? I didn't really understand that part of the datasheet.
And lastly, there is only CCPR1L, CCPR2L, and CCPR3L, so that means that the pic is capable of generating only three PWM signals (each with the same period, though - timer2's period), right? If this is the case, how do you select which PWM output on the edu uses which custom PWM signal, or does each custom PWM signal control only one PWM output pin? Also, the comments in the description of Mr. Watson's Initialize_LED_PWM function read:
This function initializes the PIC18F8520 CCP2 & CCP3 modules to generate a free running 40KHz pulse train on the EDU-RC's PWM1 & PWM2 output pins. Once running, the duty cycle of the PWM outputs can the altered on-the-fly by updating the CCPR2L and CCPR3L registers.
This kinda implies that CCPR2L is bound to PWM1 and CCPR3L is bound to PWM2. What is CCPR1L used for then, or is the CCPR1L pwm not accessable on the edu?
Kevin Watson
29-03-2004, 01:49
...one of timer2's idiosyncrasies is this is the only timer that controls custom PWMs - if you set an output to a user pwm timed by the internal microchip hardware (i.e. no external oscillator or something like that), timer2 is what determines the timing. One period of the PWM signal is the amount of time it takes for timer2 to reach its rollover value and can be changed by either changing the duration of one timer2 clock tick or by changing the PR2, or Timer2 Period Register, value.This is mostly correct. Timer 4 can also be used to generate the PWM frequency. Bits T3CCP1 and T3CCP2 of T3CON control how the timers are assigned (see the illustration on page 150 of the data sheet). I didn't bother to set these bits in my example because I knew that by default timer 2 is used to derive the PWM frequency for CCP2/3. I guess I should add this information to the example code.
The duty cycle of the PWM signal is programmed through the CCPR2L/CCPR3L byte, or the Capture/Compare/PWM Register 1/2 Low Byte. When the timer value is below this register's value, the output pin is high, and when the timer value is above this register's value, the output pin is low. Thus, to create a pwm signal with a 50% duty cycle, you set the CCPRxL value to 1/2 the PR2 value, and to create a signal with a 25% duty cycle, you set the CCPRxL value to 1/4 the PR2 value.Yes, this is true.
Also, what is the relationship between CCPRxL and CCPRxH? I didn't really understand that part of the datasheet.CCPRxH is a double-buffered version of CCPRxL. To prevent PWM output glitching, CCPRxL is transferred to CCPRxH only when it's safe to do so at the low to high transition of the PWM output.
And lastly, there is only CCPR1L, CCPR2L, and CCPR3L, so that means that the pic is capable of generating only three PWM signals (each with the same period, though - timer2's period), right? If this is the case, how do you select which PWM output on the edu uses which custom PWM signal, or does each custom PWM signal control only one PWM output pin?No, the PIC18F8520 has five CCP modules, four of which are available for use (see below).
This kinda implies that CCPR2L is bound to PWM1 and CCPR3L is bound to PWM2. What is CCPR1L used for then, or is the CCPR1L pwm not accessable on the edu?CCP1 doesn't seem to be available for use on the EDU-RC and FRC-RC. On the EDU-RC, CCP2 through CCP5 are available on pins PWM1-4. On the FRC-RC, CCP2 through CCP5 are available on pins PWM13-16. This is documented in IFI's latest version of ifi_aliases.h.
-Kevin
Okay, thanks for your help so far - I've gotten it to work more or less. Some things, however, are still bugging me.
To drive my LED's, I'm using a BS107P FET. The LED lights up and 'dims' as according to the potentiometer position, but its bugging me that I can still detect the flicker. I don't think I should be detecting any flicker - I set timer2 up with a 1:1 prescaler, so each tick is 100ns (10Mhz). The period register is set at 0x40 (64), so one period of my PWM signal should be 64 * 100ns, or .0064 seconds. This means the period repeats itself 156.25 times in a second... if you think of the period as one "frame", that would be 156.25 frames per second - about 5 times faster than television's 30fps. If television seems smooth at 30fps, how come 156 flashes per second results in a flicker?
If my reasoning is wrong and 156Hz does in fact produce a noticible flicker, is there anyway I can do to reduce this flicker? For example, would adding a capacitor to smoothen the square wave work?
Kevin Watson
30-03-2004, 00:07
Okay, thanks for your help so far - I've gotten it to work more or less. Some things, however, are still bugging me.
To drive my LED's, I'm using a BS107P FET. The LED lights up and 'dims' as according to the potentiometer position, but its bugging me that I can still detect the flicker. I don't think I should be detecting any flicker - I set timer2 up with a 1:1 prescaler, so each tick is 100ns (10Mhz). The period register is set at 0x40 (64), so one period of my PWM signal should be 64 * 100ns, or .0064 seconds. This means the period repeats itself 156.25 times in a second... if you think of the period as one "frame", that would be 156.25 frames per second - about 5 times faster than television's 30fps. If television seems smooth at 30fps, how come 156 flashes per second results in a flicker?
If my reasoning is wrong and 156Hz does in fact produce a noticible flicker, is there anyway I can do to reduce this flicker? For example, would adding a capacitor to smoothen the square wave work?Actually, 64 * 100ns = 0.0000064 seconds or 156.25KHz. I'd be more inclined to say that you're seeing (literally) A/D noise. Set the duty cycle to a constant and see if the effect goes away.
Edit: Another thing to look at is your FET. The gate of a FET is generally highly capacitive. The PIC18F8520 may have trouble driving the gate at these frequencies given that there is a 330 ohm resistor between the two. Try lowering the frequency to a few hundred hertz and see what happens.
-Kevin
vBulletin® v3.6.4, Copyright ©2000-2017, Jelsoft Enterprises Ltd.