Close

When Hardware Guys Write Code…

A project log for Frankfort: RGBW LED Ambiance Lighting

RGBW LED ambiance lighting with automation for Højskole dorm room

The ReverendThe Reverend 10/31/2014 at 06:360 Comments

With parts on the way my next step was to start working on the software side of the project. Now I am a hardware guy, I know that you can do amazing things with software, and if it means less mucking around with 'Hard Logic' and greater flexibility then I am all for it. However, I often have no idea where to start when it comes to the actual code. That is one of the main reasons why I have chosen the Arduino platform for this project, for the simplicity of coding, the number of code examples available and because I don't have the facilities to spin my own PCBs at the Højskole a ready made development board simplifies the situation considerably. Another advantage with this is that I had some of the code from a previous project that I could reuse.

A couple of years back I was asked by a family member if we could do some 'Fancy Lighting' with the glass splash-back behind his stove in the kitchen of the new house that he was building, the 'fancy' solution ended up being an RGB LED strip lighting through the glass, the effect was pretty cool and has become a talking point at parties.

I wrote the original code with help from a friend and while it wasn't the most elegant it was functional and fit for purpose. I planned to reuse elements of this code, making it more elegant where possible.

The controller would have eight push buttons, four power transistors, one PIR sensor and one microphone. The intention was to build it in stages, first the pushbuttons and power transistors to provide basic control, then adding code to allow the LEDs to cross fade, next a PIR would be added and finally the microphone, other coding elements, for example a tap tempo button to control the crossfade rate, could be explored after that. The code would have to grow along with the hardware, and after many long nights, countless uploads and lots of debugging I think I have ended up with a pretty robust foundation. At this stage only the first and second stages have been implemented; basic control and crossfading, and it functions really well. The following snippet is the code in its current iteration.

/*===================[ RGBW LED CONTROLLER ]=============================================================================================

*

*RGBW_LED_Controller.ino

*

*Created: 14/09/2014

*Author: D. Blackler

*

*The code is designed for the Arduino Uno, it takes inputs from eight(8) momentery push buttons, one(1) microphone and one(1) PIR sensor and outputs a

* PWM signal to a length of RGBW LED strip via three(4) power transistors. The input push buttons

* are as follows:

*

* Button Momentery Hold

* Red Red 100% Length determines % of red in mix

* Green Green 100% Length determines % of green in mix

* Blue Blue 100% Length determines % of blue in mix

* White White 100% Length determines intensity of white

* Fade Starts cross fade cycle

* Reset Resets colour mix to all off

*

*

*==================================================================================================================================*/

/*===================[ REVISION HISTORY ]===========================================================================================

*

* Revision 1: 14/09/2014

*-First created and formatted

* Revision 2: 17/10/2014

*-First generation functional code

*

*

*

*

*

*

*

*

*

*

*==================================================================================================================================*/

/*===================[ PIN DEFINITIONS ]===========================================================================================*/

#define REDPB 2

#define GREENPB 3

#define BLUEPB 4

#define WHITEPB 5

#define FADEPB 7

#define RESETPB 8

#define REDPIN 6

#define GREENPIN 9

#define BLUEPIN 10

#define FADESPEED 15 // The higher this number, the slower the cross fade speed will be

// Initialize global variables

int FADE = 0; //Crossfade indicator initialised to 0

/*===================[ SETUP ]=====================================================================================================*/

void setup()

{

pinMode(REDPB, INPUT);

pinMode(GREENPB, INPUT);

pinMode(BLUEPB, INPUT);

pinMode(WHITEPB, INPUT);

pinMode(FADEPB, INPUT);

pinMode(RESETPB, INPUT);

pinMode(REDPIN, OUTPUT);

pinMode(GREENPIN, OUTPUT);

pinMode(BLUEPIN, OUTPUT);

// Initialize serial communications at 9600 bps:

Serial.begin(9600);

}

/*===================[ MAIN FUNCTION ]=============================================================================================*/

void loop()

{

int x = 0;

int R = 0; //Red intensity variable initialised to 0

int G = 0; //Green intensity variable initialised to 0

int B = 0; //Blue intensity variable initialised to 0

x = Button();

{

switch(x)

{

case 1: //If called sets red intensity to 100%, if button is held down, red

R = 255; //intensity dims

analogWrite(REDPIN, R);

while (Button() == 1)

{

R --;

analogWrite(REDPIN, R);

delay(10);

}

break;

case 2: //If called sets green intensity to 100%, if button is held down, green

G = 255; //intensity dims

analogWrite(GREENPIN, G);

while (Button() == 2)

{

G --;

analogWrite(GREENPIN, G);

delay(10);

}

break;

case 3: //If called sets blue intensity to 100%, if button is held down, blue

B = 255; //intensity dims

analogWrite(BLUEPIN, B);

while (Button() == 3)

{

B --;

analogWrite(BLUEPIN, B);

delay(10);

}

break;

case 4: //If called sets white intensity to 100%, if button is held down, white

R = 255; //intensity dims. R,G & B are used to create 'white'

G = 255;

B = 255;

analogWrite(REDPIN, R);

analogWrite(GREENPIN, G);

analogWrite(BLUEPIN, B);

while (Button() == 4)

{

R --;

G --;

B --;

analogWrite(REDPIN, R);

analogWrite(GREENPIN, G);

analogWrite(BLUEPIN, B);

delay(10);

}

break;

case 5: //If called sets crossfade indicatorred to 1 and then calls Crossfade

FADE = 1; //subroutine

Crossfade();

break;

case 6: //If called sets all intensities and crossfade indicator to 0

R = 0;

G = 0;

B = 0;

FADE = 0;

analogWrite(REDPIN, R);

analogWrite(GREENPIN, G);

analogWrite(BLUEPIN, B);

break;

}

}

}

/*===================[ FUNCTIONS ]=================================================================================================*/

/* The following function returns a number depending on which button or combination of buttons is pressed it also includes simple

* delay and recheck debouncing. The returns are as follows:

*

* Button Return

* Red '1'

* Green '2'

* Blue '3'

* White '4'

* Crossfade '5'

* Reset '6'

*

*/

int Button()

{

// Checking 'RED' Push button, includes software debouncing

if ((digitalRead(REDPB) == HIGH)&&(digitalRead(GREENPB) == LOW)&&(digitalRead(BLUEPB) == LOW)&&(digitalRead(WHITEPB) == LOW)&&

(digitalRead(FADEPB) == LOW)&&(digitalRead(RESETPB) == LOW))

{

delay (10);

if ((digitalRead(REDPB) == HIGH)&&(digitalRead(GREENPB) == LOW)&&(digitalRead(BLUEPB) == LOW)&&(digitalRead(WHITEPB) == LOW)&&

(digitalRead(FADEPB) == LOW)&&(digitalRead(RESETPB) == LOW))

{

Serial.print("B1 = " );

Serial.println(HIGH);

return 1;

}

}

// Checking 'GREEN' Push button, includes software debouncing

if ((digitalRead(REDPB) == LOW)&&(digitalRead(GREENPB) == HIGH)&&(digitalRead(BLUEPB) == LOW)&&(digitalRead(WHITEPB) == LOW)&&

(digitalRead(FADEPB) == LOW)&&(digitalRead(RESETPB) == LOW))

{

delay (10);

if ((digitalRead(REDPB) == LOW)&&(digitalRead(GREENPB) == HIGH)&&(digitalRead(BLUEPB) == LOW)&&(digitalRead(WHITEPB) == LOW)&&

(digitalRead(FADEPB) == LOW)&&(digitalRead(RESETPB) == LOW))

{

Serial.print("B2 = " );

Serial.println(HIGH);

return 2;

}

}

// Checking 'BLUE' Push button, includes software debouncing

if ((digitalRead(REDPB) == LOW)&&(digitalRead(GREENPB) == LOW)&&(digitalRead(BLUEPB) == HIGH)&&(digitalRead(WHITEPB) == LOW)&&

(digitalRead(FADEPB) == LOW)&&(digitalRead(RESETPB) == LOW))

{

delay (10);

if ((digitalRead(REDPB) == LOW)&&(digitalRead(GREENPB) == LOW)&&(digitalRead(BLUEPB) == HIGH)&&(digitalRead(WHITEPB) == LOW)&&

(digitalRead(FADEPB) == LOW)&&(digitalRead(RESETPB) == LOW))

{

Serial.print("B3 = " );

Serial.println(HIGH);

return 3;

}

}

// Checking 'WHITE' Push button, includes software debouncing

if ((digitalRead(REDPB) == LOW)&&(digitalRead(GREENPB) == LOW)&&(digitalRead(BLUEPB) == LOW)&&(digitalRead(WHITEPB) == HIGH)&&

(digitalRead(FADEPB) == LOW)&&(digitalRead(RESETPB) == LOW))

{

delay (10);

if ((digitalRead(REDPB) == LOW)&&(digitalRead(GREENPB) == LOW)&&(digitalRead(BLUEPB) == LOW)&&(digitalRead(WHITEPB) == HIGH)&&

(digitalRead(FADEPB) == LOW)&&(digitalRead(RESETPB) == LOW))

{

Serial.print("B4 = " );

Serial.println(HIGH);

return 4;

}

}

// Checking 'FADE' Push button, includes software debouncing

if ((digitalRead(REDPB) == LOW)&&(digitalRead(GREENPB) == LOW)&&(digitalRead(BLUEPB) == LOW)&&(digitalRead(WHITEPB) == LOW)&&

(digitalRead(FADEPB) == HIGH)&&(digitalRead(RESETPB) == LOW))

{

delay (10);

if ((digitalRead(REDPB) == LOW)&&(digitalRead(GREENPB) == LOW)&&(digitalRead(BLUEPB) == LOW)&&(digitalRead(WHITEPB) == LOW)&&

(digitalRead(FADEPB) == HIGH)&&(digitalRead(RESETPB) == LOW))

{

Serial.print("B5 = " );

Serial.println(HIGH);

return 5;

}

}

// Checking 'RESET' Push button, includes software debouncing

if ((digitalRead(REDPB) == LOW)&&(digitalRead(GREENPB) == LOW)&&(digitalRead(BLUEPB) == LOW)&&(digitalRead(WHITEPB) == LOW)&&

(digitalRead(FADEPB) == LOW)&&(digitalRead(RESETPB) == HIGH))

{

delay (10);

if ((digitalRead(REDPB) == LOW)&&(digitalRead(GREENPB) == LOW)&&(digitalRead(BLUEPB) == LOW)&&(digitalRead(WHITEPB) == LOW)&&

(digitalRead(FADEPB) == LOW)&&(digitalRead(RESETPB) == HIGH))

{

Serial.print("B6 = " );

Serial.println(HIGH);

return 6;

}

}

return 0;

}

//Crossfade subroutine

void Crossfade()

{

while(FADE == 1)

{

unsigned int rgbColour[3];

// Start off with red.

rgbColour[0] = 255;

rgbColour[1] = 0;

rgbColour[2] = 0;

// Choose the colours to increment and decrement.

for (int decColour = 0; decColour < 3; decColour += 1)

{

int incColour = decColour == 2 ? 0 : decColour + 1;

// cross-fade the two colours.

for(int i = 0; i < 255; i += 1)

{

rgbColour[decColour] -= 1;

rgbColour[incColour] += 1;

setColourRgb(rgbColour[0], rgbColour[1], rgbColour[2]);

delay(FADESPEED);

if (digitalRead(RESETPB) == HIGH)

{

delay (10);

if (digitalRead(RESETPB) == HIGH)

{

FADE = 0;

break; //Breaks out of crossfade if RESETPB is pressed - includes software debouncing

}

}

}

}

}

}

//Writing RGB PWM output values

void setColourRgb(unsigned int red, unsigned int green, unsigned int blue)

{

analogWrite(REDPIN, red);

analogWrite(GREENPIN, green);

analogWrite(BLUEPIN, blue);

}

As always, my work is open for critique so if you think I could have done something better please let me know in the comments.

Discussions