Shop OBEX P1 Docs P2 Docs Learn Events
RGB LED SX/B Example — Parallax Forums

RGB LED SX/B Example

PLJackPLJack Posts: 398
edited 2009-04-05 05:29 in General Discussion
This is something I have been wanting to do for some time now. Mixing colors with an RGB LED.

So lets start at the beginning, The object is to vary the color of each red, green and blue LED to produce a different color. You can think of it as a standard 8 bit color palette.
So lets say you wanted to produce the color purple. That would be full red, full blue and no green. Easy enough. But what if you wanted to produce a dark purple. This can be done by reducing the intensity of the blue LED.
But how?
The answer is in PWM (pulse width modulation).

If you are new to PWM, then lets get one thing straight. You DO NOT control the color of an LED by blinking it at different speeds. Blinking is a byproduct of PWM. Controlling the color is a function of reducing the voltage that the LED sees. By reducing the voltage, you decrease the brightness.

I will provide two examples. One I will just type at the end of this paragraph, the other is an attached file that will also be pasted to the end of this post.

A simple example.
The Red LED is connected to RB.0. Green connected to RB.1 and Blue connected to RB.2.

Place the OUTPUT and PWM commands below into your SX/B Template:

Start:
' initialization code here
OUTPUT RB.0
OUTPUT RB.1
OUTPUT RB.2

Main:
pwm RB.0, 255, 1
pwm RB.1, 0, 1
pwm RB.2, 255, 1

GOTO Main


Please note that the color intensity comes from changing the DUTY cycle, not the duration.
To create a dark purple you would set RB.2 (blue) to something like 180.

There are a couple issues with the above approach. The first is that the duration of the PWM is too long. This destroys the POV (persistence of vision) effect. You can see this by looking at the LED and the quickly look up, or down or anywhere for that matter. You will see red, green and blue streaks coming from the LED. Very distracting to say the least. Bump up the duration from 1 to 5 to see the full effect.

Another issue is that you are applying PWM to each LED one after the other. In other words the above code takes 3 milliseconds to PWM all three LEDs. You really need to PWM all three at the same time.

The final issue is that pausing at a certain color is very problematic with the above method.

The sample code provided solves all these issues. The code is pretty heavily commented so I will not reproduce it here.
Basically it uses an INTERRUPT and some helper functions to produce some really pleasing results.

Enjoy and have some fun this weekend.


A more advanced method:



' =========================================================================
'
' Purpose... RBG LED Example
' Author.... PLJack
' E-mail.... kellylabs@fastmail.fm
'
' =========================================================================

' -------------------------------------------------------------------------
' Program Description:
' 
' -------------------------------------------------------------------------


'--- Don't Forget: Zero is full brightness and 255 is off.

'--- This example demonstrates the mixing of colors
'--- using a RGB LED.
'--- CAUTION: Be careful with bright LEDs while using
'--- this code, staring at a bright LED for most of
'--- the day can have undesirable results for your
'--- eyes.
'--- I find that surface mount LEDs work best for
'--- color mixing. Most 5mm LEDs seem to have the
'--- three LEDs too far apart for proper convergence
'--- (mixing).
'--- 
'--- General:
'--- Basically there are several components to this
'--- example. The first is an INTERRUPT that is
'--- constantly monitoring the PWM lines for RGB.
'--- There are three variables for the LED, RedVal,
'--- GreenVal and BlueVal. You can change these
'--- variables at any time. The interrupt will
'--- automatically change the LED to the new value.
'--- Because we are using an interrupt you can use the
'--- PAUSE command and the LED will continue to emit
'--- light. This makes it very easy to display a color
'--- for a certain amount of time.
'--- 
'--- Operation:
'--- 
'--- Not much to it really. There are three main
'--- functions for you to use.
'--- 
'--- Diag:
'--- 
'--- Used at startup. It will display the red, green
'--- and blue LEDs in that order. This is useful to
'--- determine that your LED is correctly connected to
'--- the SX.
'--- 
'--- 
'--- TransitColor [noparse][[/noparse]Num]:
'--- 
'--- This function creates a random color. Then makes
'--- a transition from the current LED color over to
'--- the new color. It performs this transition in
'--- 255 steps. You can provide and optional parameter
'--- to pause for [noparse][[/noparse]Num]
'--- milliseconds per step.
'--- The max transition time is 255 steps X 255ms = 65
'--- seconds.
'--- 
'--- 
'--- RandomPulse [noparse][[/noparse]Num]:
'--- 
'--- This function actually creates some beautiful
'--- results. It turns off the LED, creates a random
'--- color then slowly raises the led to full
'--- brightness and finally fades to off.
'--- The great results come from the fact that it
'--- increments the RGB colors by one. So if the color
'--- has a lot of blue in it (strongest color) as it
'--- fades blue will be the last led to fade. Thus
'--- mixing with the red and green as those colors are
'--- reduced.
'--- This also has an optional parameter to pause for
'--- [noparse][[/noparse]Num] milliseconds per step. Although the total
'--- number of steps is unknown. It depends on the
'--- value of the strongest color.
'---
'--- And remember to have fun.



'--- Please forgive my breaking of the Uppercase keyword convention.
'--- After years of coding in PC languages, I just can't take
'--- all those uppercase words.


' -------------------------------------------------------------------------
' Device Settings
' -------------------------------------------------------------------------

DEVICE          SX28, OSC4MHZ, TURBO, STACKX, OPTIONX
FREQ            4_000_000
ID              "SXB 1.50"


' -------------------------------------------------------------------------
' IO Pins
' -------------------------------------------------------------------------

RedLED          var     RB.0
GreenLED        var     RB.1
BlueLED         var     RB.2

' -------------------------------------------------------------------------
' Constants
' -------------------------------------------------------------------------


'--- LED TYPE
'--- Common anode       - SX pins sink to ground.
'--- Common Cathode     - SX pins source the voltage.
'--- Un-comment the correct type for your LED.

'--- Common Anode
        'LEDOn                  con     0
        'LEDOff                 con     1

'--- Common Cathode
        LEDOn                   con     1
        LEDOff                  con     0


'--- Color Clip
'--- If your LED has a color that is over powering the others you can
'--- clip its brightness here. Keep in mind this is not a global clip
'--- because the color reduction is not proportional to the others.
'--- But it will prevent a color from becoming too bright.
'--- Zero is full strength. Increase number to reduce total brightness.
'--- To do this properly you would need a variable resistor
'--- on each LED. Run them at full brightness, then adjust
'--- each VR for a perfect white.
'--- You might have some luck performing a proportional adjust on 
'--- the fly via code, but I think rounding errors might cause more
'--- trouble than it is worth.

        C_RedClip               con     0
        C_GreenClip             con     0
        C_BlueClip              con     0
        
        '--- Defaults if no parameter is provided 
        C_DefaultTransitSpeed   con     5
        C_DefaultPulseSpeed     con     15

        '--- Just substitutes for 0 and 255 incase you should
        '--- ever want to change them.
        C_PwmMin                con     0
        C_PwmMax                con     255


' -------------------------------------------------------------------------
' Variables
' -------------------------------------------------------------------------

        '--- This is the value (duty cycle) given to each LED at each INTERRUPT.
        RedVal          var     Byte
        GreenVal        var     Byte
        BlueVal         var     Byte

        '--- Sometimes handy to store the above variables.
        RedValCopy      var     Byte
        GreenValCopy    var     Byte
        BlueValCopy     var     Byte

        '--- Used for the duty cycle inside the INTERRUPT.
        RpwmCounter     var     Byte
        GpwmCounter     var     Byte
        BpwmCounter     var     Byte
        
        '--- For use constructing loops.
        LoopIdx         var     Byte

        '--- Used to increase the time a loop takes to finish.
        FadeSpeed       var     Byte

        '--- For functions that return a Byte variable.
        ReturnVar       var     Byte

        '--- Always nice to have a few around. Always assume as volatile.
        UtilVar1        var     Byte
        UtilVar2        var     Byte
        UtilVar3        var     Byte


' -------------------------------------------------------------------------
INTERRUPT  30000
ISR_Start:

        '--- Add one to pwm counters.
        '--- Note they will roll over to zero after 255.
        Inc RpwmCounter
        Inc GpwmCounter
        Inc BpwmCounter



        '--- Red LED PWM
        if RpwmCounter > RedVal then
                RedLED = LEDOn
        else
                RedLED = LEDOff 
        endif

        '--- Green LED PWM
        if GpwmCounter > GreenVal then
                GreenLED = LEDOn
        else
                GreenLED = LEDOff
        endif

        '--- Blue LED PWM
        if BpwmCounter > BlueVal then
                BlueLED = LEDOn
        else
                BlueLED = LEDOff
        endif

ISR_Exit:
  RETURNINT                                


' =========================================================================
  PROGRAM Start
' =========================================================================

' -------------------------------------------------------------------------
' Subroutine Declarations
' -------------------------------------------------------------------------

TransitColor            sub     0, 1
RandomPulse             sub     0, 1
Diag                    sub     0
SeedVars                sub     0
RandomColor             sub     0
RandomUtilVar           sub     0
RaiseStrongest          sub     1
FadeStrongest           sub     1
StoreColor              sub     0
RestoreColor            sub     0
GetStrongestColor       sub     0

' -------------------------------------------------------------------------
' Program Code
' -------------------------------------------------------------------------

Start:
        '--- Set LEDs as outputs.
        OUTPUT RedLED
        OUTPUT GreenLED
        OUTPUT BlueLED

        '--- Un-comment to perform a quick diagnostic at start up.
        Diag

        'Seed anything that the RANDOM command will use.
        SeedVars

Main:

        TransitColor 
'       RandomPulse 

Goto Main



' -------------------------------------------------------------------------
' Subroutine Code
' -------------------------------------------------------------------------

' -------------------------------------------------------------------------
RandomPulse:
        '--- Too few parameters, set to default.
        if  __PARAMCNT <> 1 then
                FadeSpeed = C_DefaultPulseSpeed
        else
                FadeSpeed = __PARAM1
        endif

        RandomColor
        '--- Bring color to full brightness.
        RaiseStrongest FadeSpeed
        '--- Now fade until off.
        FadeStrongest  FadeSpeed
return

' -------------------------------------------------------------------------
TransitColor:
        '--- Too few parameters, set to default.
        if  __PARAMCNT <> 1 then
                FadeSpeed = C_DefaultTransitSpeed
        else
                FadeSpeed = __PARAM1
        endif

        '--- Create a random color, only with the util vars this time.
        RandomUtilVar
        '--- Now bring the current LED values towards the new values.
        for loopIdx = C_PwmMin to C_PwmMax
                if RedVal <> UtilVar1 then
                        if RedVal < UtilVar1 then
                                inc RedVal      
                        else
                                dec RedVal
                        endif
                endif
                if GreenVal <> UtilVar2 then
                        if GreenVal < UtilVar2 then
                                inc GreenVal    
                        else
                                dec GreenVal
                        endif
                endif
                if BlueVal <> UtilVar3 then     
                        if BlueVal < UtilVar3 then
                                inc BlueVal     
                        else
                                dec BlueVal
                        endif
                endif

        pause FadeSpeed
        next
return


' -------------------------------------------------------------------------
FadeStrongest:

        FadeSpeed = __PARAM1
        StoreColor
        UtilVar1 = GetStrongestColor
        '--- Find number of loops required to turn off color
        UtilVar2 = C_PwmMax - UtilVar1
        '--- Bring down all colors.
        for loopIdx = C_PwmMin to  UtilVar2
                if RedVal < C_PwmMax then
                        inc RedVal      
                endif
                if GreenVal < C_PwmMax then
                        inc GreenVal
                endif
                if BlueVal < C_PwmMax then      
                        inc BlueVal
                endif

        pause FadeSpeed
        next

        RestoreColor
return


' -------------------------------------------------------------------------
RaiseStrongest:

        FadeSpeed = __PARAM1
        UtilVar1 = GetStrongestColor
        UtilVar2 = C_PwmMax - UtilVar1
        StoreColor
        '--- Set LEDs to off.
        RedVal          = C_PwmMax
        GreenVal        = C_PwmMax
        BlueVal         = C_PwmMax

        '--- Bring up all colors.
        for loopIdx = C_PwmMin to  UtilVar2
                if RedVal > RedValCopy then
                        dec RedVal      
                endif
                if GreenVal > GreenValCopy then
                        dec GreenVal
                endif
                if BlueVal > BlueValCopy then   
                        dec BlueVal
                endif

        pause FadeSpeed
        next

        RestoreColor
return




' -------------------------------------------------------------------------
StoreColor:

        RedValCopy      = RedVal
        GreenValCopy    = GreenVal
        BlueValCopy     = BlueVal
return

' -------------------------------------------------------------------------
RestoreColor:

        RedVal          = RedValCopy
        GreenVal        = GreenValCopy
        BlueVal         = BlueValCopy
return

' -------------------------------------------------------------------------
RandomColor:

        random RedVal 
        random GreenVal
        random BlueVal
        
        '--- If a color clip is set, honor it.
        if RedVal < C_RedClip then
                RedVal = C_RedClip
        endif
        if GreenVal < C_GreenClip then
                GreenVal = C_GreenClip
        endif
        if BlueVal < C_BlueClip then
                BlueVal = C_BlueClip
        endif

return

' -------------------------------------------------------------------------
RandomUtilVar:

        '--- This is a bit of an odd ball function.
        '--- To perform the transition for the TransitColor function
        '--- we need a few random numbers. Here we just use the UtilVars
        '--- instead of wasting RAM for three one off variables.

        '--- 
        random UtilVar1
        random UtilVAr2
        random UtilVar3

        '--- If a color clip is set, honor it.
        if UtilVar1 < C_RedClip then
                UtilVar1 = C_RedClip
        endif
        if UtilVar2 < C_GreenClip then
                UtilVar2 = C_GreenClip
        endif
        if UtilVar3 < C_BlueClip then
                UtilVar3 = C_BlueClip
        endif

return

' -------------------------------------------------------------------------
GetStrongestColor:

        '--- Assign strongest (low val) color to ReturnVal.
        if RedVal < GreenVal then
                ReturnVar = RedVal
        else
                ReturnVar = GreenVal
        endif

        if ReturnVar > BlueVal then
                ReturnVar = BlueVal
        endif

return ReturnVar



' -------------------------------------------------------------------------
SeedVars:
        'Seed anything that the RANDOM command will use.
        RedVal          = 50
        GreenVal        = 100
        BlueVal         = 150
        UtilVar1        = 150
        UtilVar2        = 100
        UtilVar3        = 50
return

' -------------------------------------------------------------------------
Diag:

        '--- A simple diagnostic to confirm that the LED is
        '--- connected to the SX correctly and is working properly.

        RedVal          = C_PwmMax
        GreenVal        = C_PwmMax
        BlueVal         = C_PwmMax

        RedVal          = C_PwmMin
        Pause 500
        RedVal          = C_PwmMax

        GreenVal        = C_PwmMin
        Pause 500
        GreenVal        = C_PwmMax

        BlueVal         = C_PwmMin
        Pause 500
        BlueVal         = C_PwmMax


        for loopIdx = C_PwmMin to C_PwmMax
                RedVal = LoopIdx
                pause 2
        next

        for loopIdx = C_PwmMin to C_PwmMax
                GreenVal = LoopIdx
                pause 2
        next

        for loopIdx = C_PwmMin to C_PwmMax
                BlueVal = LoopIdx
                pause 2
        next


        for loopIdx = C_PwmMin to C_PwmMax
                RedVal   = LoopIdx
                BlueVal  = LoopIdx
                GreenVal = LoopIdx
                pause 4
        next


return

' -------------------------------------------------------------------------

' =========================================================================
' User Data
' =========================================================================

Pgm_ID:
  DATA  "SX/B RGB LED Example", 0
' 


▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
- - - PLJack - - -



Perfection in design is not achieved when there is nothing left to add.
It is achieved when there is nothing left to take away.

Post Edited (PLJack) : 11/24/2006 9:09:35 PM GMT

Comments

  • BeanBean Posts: 8,129
    edited 2006-11-25 00:11
    PLJack,

    Very nice.

    Just a couple notes though:
    · You only need 1 PWMCounter because all three will always be the same value anyway.
    · Check the assembly listing, and if it doesn't use any __PARAMx variables, then add NOPRESERVE to the INTERRUPT line. That will save a bunch of cycles in the interrupt.
    · 30000 interrupts per second is a refresh rate of 117Hz. 60Hz is plenty fast, which would be 15360.
    · I would add the second parameter to FREQ (to account for time spent in the interrupt).·You can use SX-Sim·to see how many clocks are spent in the interrupt.
    ·
    When you are ready for a challenge, make the interrupt routine adjust the brightness (like your TransitColor routine does).

    Bean.

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    Cheap used 4-digit LED display with driver IC·www.hc4led.com

    Low power SD Data Logger www.sddatalogger.com
    SX-Video Display Modules www.sxvm.com
    Stuff I'm selling on ebay http://search.ebay.com/_W0QQsassZhittconsultingQQhtZ-1

    "People who are willing to trade their freedom for·security deserve neither and will lose both." Benjamin Franklin


    Post Edited (Bean (Hitt Consulting)) : 11/25/2006 12:21:38 AM GMT
  • PLJackPLJack Posts: 398
    edited 2006-11-25 00:26
    Hi Bean.
    Yes there are optimizations that can be had, wanted to make it more of an example.
    Got me on the PWMCounter though. Doh! smile.gif

    I found 30000 gave the best results. I meant to get back to that number, forgot.

    Thanks for the feedback.

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    - - - PLJack - - -



    Perfection in design is not achieved when there is nothing left to add.
    It is achieved when there is nothing left to take away.
  • danny270danny270 Posts: 13
    edited 2009-03-23 18:13
    Hello PLJack,
    I hope you still remember this project after 2.5 years.
    I worked on it last night and enjoyed it. Need to experiment more on the different options on PAUSES.
    On a simpler note, can you give some guidelines if I just want to simply do the following:
    A fade time (preferably with speed adjust) and a scene time (LEDOn for a certain amount of time via a PAUSE) for each color where I can control the time for each fade time and scene time.
    Also a transistion time where one LED fades out and the next LED fades in so that there is no complete blackout at transition but a slight mixing of the two interacting colors.
    Thanks.
    Danny
  • PLJackPLJack Posts: 398
    edited 2009-03-27 23:27
    danny270 said...
    Hello PLJack,
    I hope you still remember this project after 2.5 years.
    I worked on it last night and enjoyed it. Need to experiment more on the different options on PAUSES.
    On a simpler note, can you give some guidelines if I just want to simply do the following:
    A fade time (preferably with speed adjust) and a scene time (LEDOn for a certain amount of time via a PAUSE) for each color where I can control the time for each fade time and scene time.
    Also a transistion time where one LED fades out and the next LED fades in so that there is no complete blackout at transition but a slight mixing of the two interacting colors.
    Thanks.
    Danny


    2 1/2 years! Holy C##P.
    I'm really happy you enjoyed it. That's exactly why I wrote it.

    Actually I remember this article well.
    I just re-read it. Pretty rough code.

    Since then I have done allot of RGB code. I've made night lights, counter lights.
    Currently I have a white globe attached to the wall that pulses different colors depending on what is in my email inbox.

    If you don't mind being patient I will fire up the SX computer and see what I have for code that can help.
    Patient being the key word there. Could take a handful of days.

    BTW, I did another write up on RGB color in these forums here:
    Link: RGB Color Models

    BTW again, although I have not logged into the forums in a long time I still read them a few times a week.
    Hi Guys!

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    - - - PLJack - - -



    Perfection in design is not achieved when there is nothing left to add.
    It is achieved when there is nothing left to take away.

    Post Edited (PLJack) : 3/27/2009 11:41:36 PM GMT
  • danny270danny270 Posts: 13
    edited 2009-03-28 15:10
    PLJack,

    Good to hear from you. You've not post anything but looks like you''ve been busy working other projects.
    I have gone through your older posts as well.

    I will patiently wait.

    Thanks.

    Danny
  • DigitalDjDigitalDj Posts: 207
    edited 2009-04-05 05:29
    In my experimentation with rgb leds I have found that adding an extra red is a big improvement. The reason for that is rgb leds are not that accurate for producing colors that match the computer or color swatches. By adding the red increaes the brightness which red is not that bright of a color anyway and allows the current on the blue and green to be higher than normal when getting white. For example when I was doing testing I would create white and my red would be at 20ma and the green and blue would be at app. 9ma. By increasing the red this allowed the green and blue to be up closer to 20ma. This allows for more color mixing room and better color matching.

    There are ways to create the presence of black, I use white plastic and while other leds are on that one spot is not is of coarse the absence of light and looks dark. This also works for gray scales. The other way is using smoked black acylic the same as what they use for non glare applications. This also improves the richiness of colors and allows·intensities of white light to create gray.

    Kevin

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔

Sign In or Register to comment.