PDA

View Full Version : RGB Fading Using 3 LEDs and PWM



Tissy
- 14th February 2005, 20:13
Has anyone designed any PIC Basic code which will allow 3 seperate LEDs (Red, Green and Blue) to produce full spectrum fading using a PIC. I have read many posts and PWM seems the most obvious route, but no example code seems to be available.

I want automatic colour fading through each of the LEDs to produce a full colour spectrum and then loop again.

From this i might then be able to produce different effects etc.

Has anyone done this and is willing to assist / share code?

Many thanks.

Steve.

NavMicroSystems
- 14th February 2005, 20:27
Tissy,

See: here (http://www.picbasic.co.uk/forum/showthread.php?s=&threadid=622&highlight=Fade)

Tissy
- 14th February 2005, 20:42
Thanks for your reply Ralph. I have the PWM of an LED fade effect working well, ie on a single LED.

It's the rainbow type effect i'm now looking at doing using 3 LEDs, which start to fade in a set point to get the colour mixing effect of RGB.

I am aware you can now get an single LED in a 5mm package that once it is powered up, starts the sequence of colour changing. I want this effect but using 3 seperate LEDs and a PIC.

Thanks.

Steve

mister_e
- 14th February 2005, 22:00
if you're looking for an easy solution, some PIC have up to 4 internal PWM.

BUT everything can also be done with a simple 8 pins PIC too using Internal TIMERs to generate PWM and fade delay... a bit much complicated.

Srigopal007
- 15th February 2005, 00:05
Hi Tiss,

1)Are you using a PIC with 3 or more internal pwm??
2)Do you want the PWM to work in the background?


if your answer to the questions were YES then I suggest you use PIC16F777. REASON for this is 16f777 has 3 internal pwm and it;s very simple to implement. even a little kid can do it.

MISTER_E was/is an excellent tutor at this. Very useful person


if your answer to one of the two questions was no. then I suggest just doing it all in software. that is also very simple.

MISTER_E is again a very useful person at this.
==============================================

I can help you out if mister_e is busy..... let me konw tissy



srig

Tissy
- 15th February 2005, 00:22
Thanks Srig,

This section is part of a bigger program, which i am perhaps three quarters of the way through.

I am looking at using the simplest PIC which is the 16F84. At the moment i am using a 16F876 for development purposes.

The project at the moment has three RGB LEDs on PortC 0-2. When you push a switch, each of the LEDs lights as a solid colour.

For example, the first switch push lights Red, Second push lights Green and then the third lights Blue. The forth switch push Fades Red up and down continously, fifth push, fades green up and down continously, etc etc.

All this code has now been completed.

I then want the seventh button push to then create the spectrum effect. ie the colours of the rainbow start at an aqua colour then finish at white. Then cycles back down again, white through to acqua.

As i say, ideally i would like to do it using software PWM, but am struggling a bit.

I have found some code here http://www.electronic-projects.net/Schematics/RainbowVoltmeter/Rainbow.htm

If i am right, using this sample code, if the value of x was to vary from 0 to 255, then you will get the spectrum using the 3 LEDs. But is this piece of code using Hardware PWM? If so, how would i change it to Software PWM.

All i really need at the moment is a stand alone routine which performs this RGB effect. Once this is working right, i can then introduce it into the rest of my code.

Any help is always welcome along with recommendatiosn etc. I am new to this, but loving every minute of it to see a finalised working idea !!

Thanks again,

Steve.

Srigopal007
- 15th February 2005, 00:41
Okay just a rough sketch of the ramping up and down is performed like this


ramping up of an LED is performed like this:

RAMPINGUP:

for Counter = 0 to 255
PortC = %00000000 'LEDS connected to PortC.0, C.1, C.2 are all off
Pauseus 255 - counter
PortC = %00000111 'LEDS are all on
Pauseus Counter

Goto RAMPINGUP

'reverse this order and you will make the LEDS ramp down

RAMPINGDOWN:

for Counter = 255 to 0 Step -1
PortC = %00000111
Pauseus Counter
PortC = %00000000
Pauseus 255 - counter

Goto RAMPINGDOWN
============================================


remember this is just a rough sketch of what I think you're trying to do. I just busted this out from atop of my head. you might need to mess around with the timing sequence depending on your design. let me know if this works. this is only one way of doing this...


srig

NavMicroSystems
- 15th February 2005, 00:45
Tissy,

the Rainboow example does not use any Hardware PWM,
(not even PBPs Software PWM)

The Advantage of Hardware PWM is it runs in Background
while the Main program is doing other things.

With Software PWM you have got to keep your code small and you don't have much MCU time spare to do other things if you want to avoid "flickering" effects.

As you are developing on an 16F876 (which has HPWM)
you can easily find out the difference by simply trying it,

see PBP Manual "PWM" (Section. 5.61)
and "HPWM" (Section. 5.29)"
for reference.

Tissy
- 17th February 2005, 18:59
I have found this piece of code, which i think may do what i need. How do i change the outputs so that it fades the LEDs on RC0 - RC2 and not RB5 through to RB7?

Is there anything else that'll need modifiying if i am using a PIC16F876.

Many thanks.


' PicBasic Pro program for fading RGB LED's.
' Note that this program uses the
' Basic Stamp-equivalent pin numbers, 5 through 7.
' These correspond to pins RB5 through RB7.

include "modedefs.bas"

DEFINE OSC 4
DEFINE ADC_BITS 8
DEFINE ADC_CLOCK 3
DEFINE SAMPLEUS 50


TRISB = %00000000
TRISA = %11111111
TRISD = %00000000

ADCON1 = %00000010

rbgArray var byte[3] ' holds the rgb values in this case the led is rbg


x var byte
y var byte
adcVar var byte
rbg var byte 'which value we are changing in the rbg array
rainbowVal var byte 'the current value to produce rainbow
Delta var byte ' find the size of each section in the 6stage rainbow
Section var byte 'which section it is in

maxValue con 255 'the maximum input value for generating rainbow

delta = maxValue/6

y = 0


for x = 5 to 7

high x
pause 1000
low x

next
main:



adcin 0, rainbowval
'serout2 portc.6, 16468, ["rainbow val: ", dec rainbowval, 13, 10]


gosub rbgrainbow



goto main


rbgrainbow:

for rbg = 0 to 2
section = ((rainbowval + ((rbg * 2)*delta))/ delta) // 6 ' this gives what section it is in
'serout2 portc.6, 16468, ["rbg: ", dec rbg, 13,10,"section: ", dec section, 13, 10]
select case section
case 0
rbgarray[rbg] = (rainbowval // delta)*6 'this is how far it has gone in its section
case 1
rbgarray[rbg] = 255
case 2
rbgarray[rbg] = 255
case 3
rbgarray[rbg] = 255 - ((rainbowval //delta)*6)
case 4
rbgarray[rbg] = 0
case 5
rbgarray[rbg] = 0
case 6 'this one is for pics bad math
rbgarray[rbg] = 0
end select
next

gosub ledpwm

return

ledPWM:
for y = 0 to 2
pwm 5 + y, rbgarray[y], 1
'serout2 portc.6, 16468, ["color",dec y, ": ", dec rbgarray[y], 13, 10]
next

return

mister_e
- 18th February 2005, 00:59
ledPWM:
for y = 0 to 2
pwm PORTC.0[y], rbgarray[y], 1
next

Tissy
- 18th February 2005, 11:33
Thanks Steve,

There was also the variable in the middle of the code which states:

x = 5 to 7

I have changed this to x = 0 to 2 along with your recommendation of

ledPWM:
for y = 0 to 2
pwm PORTC.0[y], rbgarray[y], 1
next

However, still no ouptut at all. Is there anything else set, which says the Output is on PORTB and not PORTC as required.

Cheers.

Steve

mister_e
- 18th February 2005, 17:56
mmm looks like pwm don't accept ident...
try this


ledPWM:
For y = 0 to 2
Select Case y
Case 0
pwm PORTC.0, rbgarray[y], 1
case 1
pwm PORTC.1, rbgarray[y], 1
case 2
pwm PORTC.2, rbgarray[y], 1
end select
next

Tissy
- 18th February 2005, 18:24
With the ammended code, the LED on PORTC.2 lights for a second or 2, then the one on PORTC.1 lights for a flash and then everything stops.

Definately something strange going on !!! But it doesn't do what i expected, any other ideas ?

I can post the full code if that helps?

Cheers,

Steve

mister_e
- 18th February 2005, 18:51
if it's different than the previous one... yes case not let us know. Don't forget it wait for analog variant on channel 0.

what about now if you skip this a/d stuff and do this change



main:
for rainbowval = 0 to 255
gosub rbgrainbow
next
for rainbowval=255 to 0 step - 1
gosub rbgrainbow
next

goto main

Tissy
- 18th February 2005, 19:30
Unfortunately still nothing.

I would like to remove the ADV all together and just have the FOR...NEXT loop to generate the number of 0 - 255. And then the LEDs changing there PWM to emulate the colours of the spectrum. Here is what the code looks like at the moment with all the recommended changes.

TRISA = %11111111
TRISC = %00000000


rbgArray var byte[3] ' holds the rgb values in this case the led is rbg


x var byte
y var byte
adcVar var byte
rbg var byte ' which value we are changing in the rbg array
rainbowVal var byte ' the current value to produce rainbow
Delta var byte ' find the size of each section in the 6stage rainbow
Section var byte ' which section it is in

maxValue con 255 'the maximum input value for generating rainbow

delta = maxValue/6

y = 0

for x = 0 to 2
high x
pause 1000
low x
next

main:
for rainbowval = 0 to 255
gosub rbgrainbow
next
for rainbowval=255 to 0 step - 1
gosub rbgrainbow
next
goto main


rbgrainbow:
for rbg = 0 to 2
section = ((rainbowval + ((rbg * 2)*delta))/ delta) // 6 ' this gives what section it is in
'serout2 portc.6, 16468, ["rbg: ", dec rbg, 13,10,"section: ", dec section, 13, 10]

select case section
case 0
rbgarray[rbg] = (rainbowval // delta)*6 'this is how far it has gone in its section
case 1
rbgarray[rbg] = 255
case 2
rbgarray[rbg] = 255
case 3
rbgarray[rbg] = 255 - ((rainbowval //delta)*6)
case 4
rbgarray[rbg] = 0
case 5
rbgarray[rbg] = 0
case 6 'this one is for pics bad math
rbgarray[rbg] = 0
end select
next

gosub ledpwm

return

ledPWM:
For y = 0 to 2
Select Case y
Case 0
pwm PORTC.0, rbgarray[y], 1
case 1
pwm PORTC.1, rbgarray[y], 1
case 2
pwm PORTC.2, rbgarray[y], 1
end select
next

mister_e
- 18th February 2005, 19:43
i don't want to broke you nuts but this is tested and working.


TRISC = 0

rbgArray var byte[3] ' holds the rgb values in this case the led is rbg
x var byte
y var byte
adcVar var byte
rbg var byte ' which value we are changing in the rbg array
rainbowVal var byte ' the current value to produce rainbow
Delta var byte ' find the size of each section in the 6stage rainbow
Section var byte ' which section it is in

maxValue con 255 'the maximum input value for generating rainbow

delta = maxValue/6

y = 0

main:
for rainbowval = 0 to 255
gosub rbgrainbow
next
for rainbowval=255 to 0 step - 1
gosub rbgrainbow
next
goto main


rbgrainbow:
for rbg = 0 to 2
section = ((rainbowval + ((rbg * 2)*delta))/ delta) // 6 ' this gives what section it is in

select case section
case 0
rbgarray[rbg] = (rainbowval // delta)*6 'this is how far it has gone in its section
case 1
rbgarray[rbg] = 255
case 2
rbgarray[rbg] = 255
case 3
rbgarray[rbg] = 255 - ((rainbowval //delta)*6)
case 4
rbgarray[rbg] = 0
case 5
rbgarray[rbg] = 0
case 6 'this one is for pics bad math
rbgarray[rbg] = 0
end select
next

gosub ledpwm

return

ledPWM:
For y = 0 to 2
Select Case y
Case 0
pwm PORTC.0, rbgarray[y], 1
case 1
pwm PORTC.1, rbgarray[y], 1
case 2
pwm PORTC.2, rbgarray[y], 1
end select
next
return


1. Are your LEDs connected between PORTC and gnd via resistor?
2. Is your MCLR pin tie to VCC with a 10K resistor?
3. Have you place 0.1uf cap close to your PIC?
4. is your supply line 5V and neat, un-noisy?
5. Is your crystal match to your DEFINE OSC setting?
6. Case you're using 8MHZ or higher, did you set HS oscillator in your Programmer program before programming your PIC?

Tissy
- 18th February 2005, 19:55
Fantastic, that now works as you say. It is on a development board at the moment where all the LEDs are RED. So the next thing to do is knock it up on a strip board using the RGB LEDs to see the full effect.

Thanks again, i'll let you know what the finished article is like.

Cheers,

Steve.

mister_e
- 18th February 2005, 19:57
Great ! good luck!

JDM160
- 6th March 2005, 08:49
i don't want to broke you nuts but this is tested and working.


TRISC = 0

rbgArray var byte[3] ' holds the rgb values in this case the led is rbg
x var byte
y var byte
adcVar var byte
rbg var byte ' which value we are changing in the rbg array
rainbowVal var byte ' the current value to produce rainbow
Delta var byte ' find the size of each section in the 6stage rainbow
Section var byte ' which section it is in

maxValue con 255 'the maximum input value for generating rainbow

delta = maxValue/6

y = 0

main:
for rainbowval = 0 to 255
gosub rbgrainbow
next
for rainbowval=255 to 0 step - 1
gosub rbgrainbow
next
goto main


rbgrainbow:
for rbg = 0 to 2
section = ((rainbowval + ((rbg * 2)*delta))/ delta) // 6 ' this gives what section it is in

select case section
case 0
rbgarray[rbg] = (rainbowval // delta)*6 'this is how far it has gone in its section
case 1
rbgarray[rbg] = 255
case 2
rbgarray[rbg] = 255
case 3
rbgarray[rbg] = 255 - ((rainbowval //delta)*6)
case 4
rbgarray[rbg] = 0
case 5
rbgarray[rbg] = 0
case 6 'this one is for pics bad math
rbgarray[rbg] = 0
end select
next

gosub ledpwm

return

ledPWM:
For y = 0 to 2
Select Case y
Case 0
pwm PORTC.0, rbgarray[y], 1
case 1
pwm PORTC.1, rbgarray[y], 1
case 2
pwm PORTC.2, rbgarray[y], 1
end select
next
return


1. Are your LEDs connected between PORTC and gnd via resistor?
2. Is your MCLR pin tie to VCC with a 10K resistor?
3. Have you place 0.1uf cap close to your PIC?
4. is your supply line 5V and neat, un-noisy?
5. Is your crystal match to your DEFINE OSC setting?
6. Case you're using 8MHZ or higher, did you set HS oscillator in your Programmer program before programming your PIC?


This code is brilliant.. well, I'm sure it is but I don't totally understand it. I'm only three days into micro controllers and PBP, but I'm a pretty fast learner with an engineering background - so I'm eating this stuff up.

I'm trying to figure out this code, but I keep getting stumped at two parts - mostly because I'm not totally fluent in BASIC I suppose.

Can somebody explain what "rbgarray[rbg]" does? I don't quite understand what the content of [] is doing to rbgarray and how it effects the program...

Thanks in advance for your time!

mister_e
- 6th March 2005, 09:38
[] mean an array.

what's an array? roughly it's a variable with multiple value... well not really

let's say we define HELLO VAR BYTE[10] Hello can contain 10 different value.

Hello[0]=1
hello[1]=2
hello[2]=3

and blah blah blah... so if you recall hello[1] you'll get 2.

JDM160
- 7th March 2005, 03:58
Thanks very much for the reply... unfortunately I'm still lost :-(

The part I'm having trouble with is:

------------------------------------------
ledPWM:
For y = 0 to 2
Select Case y
Case 0
pwm red, rbgarray[y], 1
case 1
pwm green, rbgarray[y], 1
case 2
pwm blue, rbgarray[y], 1
end select
------------------------------------------

I'm under the impression that this program will cycle through the different colors of the rainbow using three different LEDs (ports) - naturally red, green and blue, and varying the duty cycle to each to create the dimming and cycling effect.

I don't see how this part of the code (which calls the PWM of the individual ports) varies the duty cycle differently for each color. Can anybody explain how this works? Or am I misunderstanding the purpose of this program?

Oh, by the way, I have defined the ports "red, green, and blue" as you can see in the code above..

Thanks again!

mister_e
- 7th March 2005, 04:40
The best way to learn, is to place the program on a PIC and see what's happen with. Try to modify it and see how it affect different parts. You can't blow anything. The worst situation will be 'syntax error' or something like that.

JDM160
- 7th March 2005, 05:54
The best way to learn, is to place the program on a PIC and see what's happen with. Try to modify it and see how it affect different parts. You can't blow anything. The worst situation will be 'syntax error' or something like that.

Yea, I know! My stuff is in the mail though.. doh! And I really am trying to understand how this program works. It does independantly vary the duty cycle of the different colors right? HOW!?!

I really appreciate your time - I can't wait to get my PICs.

JDM160
- 7th March 2005, 06:35
Eureka!

I got it!

------------------------------------------
ledPWM:
For y = 0 to 2
Select Case y
Case 0
pwm red, rbgarray[y], 1
case 1
pwm green, rbgarray[y], 1
case 2
pwm blue, rbgarray[y], 1
end select
------------------------------------------

I was having trouble realizing that the nested Case statement in the For statement was hitting "red" with rbgarray[1], "green" with rbgarray[2] and "blue" with rbgarray[3] - which are each different values between 1-256!

It's like the sun rising, in my mind..

Tissy
- 8th March 2005, 00:16
Although this sequence works reasonably well. Why do the LEDs when they have faded to OFF remain slightly lit when realy they should be OFF?

Also, during the sequence, one LED jumps quickly to another, I have it when BLUE goes OFF, it jumps to RED quickly, then goes OFF again. Are others getting the same, it is quite quick.

Is there any other RGB sequences out there that perform a similar task??

Cheers,

Steve

mister_e
- 8th March 2005, 03:44
i think it's more a math calculation overflow... try to do some simple calculation when 'rainbowval' is reaching something like 200,230,240... or lower. if you have ICD capability it's easy to see whats happen. MicroCode free version have ICD for 16F628.

See Bruce's website Here for the ICD explanation (http://www.rentron.com/PicBasic/MCS_X3.htm)

Here to buy full version or to download free version Of MicroCode Studio (http://www.rentron.com/PicBasic/products/MicroCode_Studio.htm)

it's worth every $ you'll place on this program.

emavil
- 20th February 2007, 02:53
i don't want to broke you nuts but this is tested and working.

Hi Mr. E

I have a couple of Common Cathode RGB Leds and tried fading one color only using PWM. It worked well. I saw your fantastic code and tried it. It only blinks and no brightness at all.

I just would like to very if my configurations are correct.
I'm using PIC16F628A
Internal RC oscillator enabled
MCLR disabled
Red, Gree, Blue pins are driven by BC557 PNP transistors. The bases of these transistors are connected to RB0-RB2 respectively.
Do i have to specify the DEFINE OSC

Plz.

mister_e
- 20th February 2007, 15:53
Using your setup, but led are directly connected to the PIC and gnd (i uses an EasyPic 4 board ), you'll use this version


@ __CONFIG _INTRC_OSC_NOCLKOUT & _MCLRE_OFF & _LVP_OFF & _WDT_OFF & _PWRTE_ON & _BODEN_ON
TRISB = 0

rbgArray var byte[3] ' holds the rgb values in this case the led is rbg
x var byte
y var byte
adcVar var byte
rbg var byte ' which value we are changing in the rbg array
rainbowVal var byte ' the current value to produce rainbow
Delta var byte ' find the size of each section in the 6stage rainbow
Section var byte ' which section it is in

maxValue con 255 'the maximum input value for generating rainbow

delta = maxValue/6

y = 0

main:
for rainbowval = 0 to 255
gosub rbgrainbow
next
for rainbowval=255 to 0 step - 1
gosub rbgrainbow
next
goto main


rbgrainbow:
for rbg = 0 to 2
section = ((rainbowval + ((rbg * 2)*delta))/ delta) // 6 ' this gives what section it is in

select case section
case 0
rbgarray[rbg] = (rainbowval // delta)*6 'this is how far it has gone in its section
case 1
rbgarray[rbg] = 255
case 2
rbgarray[rbg] = 255
case 3
rbgarray[rbg] = 255 - ((rainbowval //delta)*6)
case 4
rbgarray[rbg] = 0
case 5
rbgarray[rbg] = 0
case 6 'this one is for pics bad math
rbgarray[rbg] = 0
end select
next

gosub ledpwm

return

ledPWM:
For y = 0 to 2
Select Case y
Case 0
pwm PORTB.0, rbgarray[y], 1
case 1
pwm PORTB.1, rbgarray[y], 1
case 2
pwm PORTB.2, rbgarray[y], 1
end select
next
return