Having trouble integrating a function in a sketch that controls LEDs

Hello all,

I'm new to Arduino (and loving it!) and C++, and have hit a stumbling block with a project. I've built a Stainless lamp and connected a capacitive sensor such that it cycles among shades of color (generated by two LED strips, one RGB and one white) when touched(triggered). As a basis, I used Clay Shirky's ColorCrossfader sketch I found here and integrated the capacitive sensor. It works great.

I'd like to, however, replace one of the colors with a function/routine that cycles the LEDs, creating a TV-like effect, until the capacitive sensor is triggered and it fades to the next color. I have the "TV" code working great as it's own sketch... but am having trouble integrating it into this sketch.

I've hit two stumbling blocks:
-I know I'm not calling the function "isButtonPressed" correctly on line 44, but can't figure out to call it correctly;
-I kthink I need to say “if the mode is mode8 then run this (TV) code, otherwise, run the other code"... but am unsure of how to structure it/properly phrase this.

I would be so appreciative of any suggestions!

Thanks and best, Jared

//pin connections
int redPin = 9;
int grnPin = 10;
int bluPin = 11;
int whiPin = 3;
int buttonPin = 2;

int mode1 = 1; 
int mode2 = 2;
int mode3 = 3;
int mode4 = 4;
int mode5 = 5;
int mode6 = 6;
int mode7 = 7;
int mode8 = 8;
int mode9 = 9;
int mode10 = 10;

// Color arrays

int modeColor1[4]  = { 0, 0, 0, 0 };
int modeColor2[4]  = { 100, 100, 100, 0 };
int modeColor3[4]  = { 100, 0, 0, 0 };
int modeColor4[4]  = { 0, 100, 0, 0 };
int modeColor5[4]  = { 0, 0, 100, 0 };
int modeColor6[4]  = { 0, 15, 100, 15 };
int modeColor7[4]  = { 0, 0, 0, 80 };

void modeColor8() {
  do 
  {
  analogWrite(whiPin, random(200)+10);
  delay(random(1200));

  analogWrite(redPin, random(70)+35);
  delay(random(100));

  analogWrite(grnPin, random(150)+35);
  delay(random(200));
  
  analogWrite(bluPin, random(230)+35);
  delay(random(400));
  
  } while (isButtonPressed() false);
}

int modeColor9[4]  = { 30, 30, 50, 30 };
int modeColor10[4] = { 100, 30, 8, 10 };

int yellow[4] = { 40, 95, 0, 0 };
int dimWhite[4] = { 30, 30, 30, 0 };
int justwhite [4] = {0, 0, 0, 100 }; 
// etc.

// Set initial color
int redVal = modeColor1[0];
int grnVal = modeColor1[1]; 
int bluVal = modeColor1[2];
int whiVal = modeColor1[3];

int wait = 5;      // 10ms internal crossFade delay; increase for slower fades
int hold = 5;       // Optional hold when a color is complete, before the next crossFade
int DEBUG = 1;      // DEBUG counter; if set to 1, will write values back via serial
int loopCount = 60; // How often should DEBUG report?
int repeat = 0;     // How many times should we loop before stopping? (0 for no stop)
int j = 0;          // Loop counter for repeat

// Initialize color variables
int prevR = redVal;
int prevG = grnVal;
int prevB = bluVal;
int prevW = whiVal;

int currentMode = mode6; 

boolean currentState = LOW;//storage for current button state
boolean lastState = LOW;//storage for last button state

void setup() {
  // put your setup code here, to run once:

  pinMode(buttonPin, INPUT);//this time we will set the pin as INPUT
  pinMode(redPin, OUTPUT);
  pinMode(bluPin, OUTPUT);
  pinMode(grnPin, OUTPUT);
  pinMode(whiPin, OUTPUT);

  if (DEBUG) {           // If we want to see values for debugging...  
  Serial.begin(9600);//initialize Serial connection
  }
}

void loop() {

  isButtonPressed();
  
  currentMode = getNextMode(currentMode);
  int* colors = getColor( currentMode );
  crossFade(colors);
  
  delay(1000);//crude form of button debouncing

}

boolean isButtonPressed(){
  currentState = digitalRead(buttonPin);
  if (currentState == HIGH && lastState == LOW){//if button has just been pressed
    Serial.println("pressed");
    return true; 
   }
   return false;
}

int getNextMode(int mode) {  
  if (mode == mode1) return mode2;
  if (mode == mode2) return mode3;
  if (mode == mode3) return mode4;
  if (mode == mode4) return mode5;
  if (mode == mode5) return mode6;
  if (mode == mode6) return mode7;
  if (mode == mode7) return mode8;
  if (mode == mode8) return mode9;
  if (mode == mode9) return mode10;
  if (mode == mode10) return mode6;
}

int* getColor(int mode) {  
  if (mode == mode1) return modeColor1;
  if (mode == mode2) return modeColor2;
  if (mode == mode3) return modeColor3;
  if (mode == mode4) return modeColor4;
  if (mode == mode5) return modeColor5;
  if (mode == mode6) return modeColor6;
  if (mode == mode7) return    modeColor7;
  if (mode == mode8) return modeColor8;
  if (mode == mode9) return modeColor9;
  if (mode == mode10) return modeColor10;
}

int calculateStep(int prevValue, int endValue) {
  int step = endValue - prevValue; // What's the overall gap?
  if (step) {                      // If its non-zero, 
    step = 1020/step;              //   divide by 1020
  } 
  return step;
}

/* The next function is calculateVal. When the loop value, i,
*  reaches the step size appropriate for one of the
*  colors, it increases or decreases the value of that color by 1. 
*  (R, G, and B are each calculated separately.)
*/

int calculateVal(int step, int val, int i) {

  if ((step) && i % step == 0) { // If step is non-zero and its time to change a value,
    if (step > 0) {              //   increment the value if step is positive...
      val += 1;           
    } 
    else if (step < 0) {         //   ...or decrement it if step is negative
      val -= 1;
    } 
  }
  // Defensive driving: make sure val stays in the range 0-255
  if (val > 255) {
    val = 255;
  } 
  else if (val < 0) {
    val = 0;
  }
  return val;
}

/* crossFade() converts the percentage colors to a 
*  0-255 range, then loops 1020 times, checking to see if  
*  the value needs to be updated each time, then writing
*  the color values to the correct pins.
*/

void crossFade(int color[4]) {
  // Convert to 0-255
  int R = (color[0] * 255) / 100;
  int G = (color[1] * 255) / 100;
  int B = (color[2] * 255) / 100;
  int W = (color[3] * 255) / 100;

  int stepR = calculateStep(prevR, R);
  int stepG = calculateStep(prevG, G); 
  int stepB = calculateStep(prevB, B);
  int stepW = calculateStep(prevW, W);

  for (int i = 0; i <= 1020; i++) {
    redVal = calculateVal(stepR, redVal, i);
    grnVal = calculateVal(stepG, grnVal, i);
    bluVal = calculateVal(stepB, bluVal, i);
    whiVal = calculateVal(stepW, whiVal, i);


    analogWrite(redPin, redVal);   // Write current values to LED pins
    analogWrite(grnPin, grnVal);      
    analogWrite(bluPin, bluVal); 
    analogWrite(whiPin, whiVal); 


    delay(wait); // Pause for 'wait' milliseconds before resuming the loop

    if (DEBUG) { // If we want serial output, print it at the 
      if (i == 0 or i % loopCount == 0) { // beginning, and every loopCount times
        Serial.print("Loop/RGB: #");
        Serial.print(i);
        Serial.print(" | ");
        Serial.print(redVal);
        Serial.print(" / ");
        Serial.print(grnVal);
        Serial.print(" / ");  
        Serial.println(bluVal); 
        Serial.print(" / ");  
        Serial.println(whiVal); 
      } 
      DEBUG += 1;
    }
  }
  // Update current values for next loop
  prevR = redVal; 
  prevG = grnVal; 
  prevB = bluVal;
  prevW = whiVal;
  delay(hold); // Pause for optional 'wait' milliseconds before resuming the loop
}

Have you tried == or != ? What are you looking for it to not be, true or false? It's good to see you're using arrays but you can also use 2D arrays too.

Ex.
myArray[2][3]= { {a,b,c},{d,e,f} };
. . .
myArray[0][2] -> c
myArray[1][0] -> d

Also when does lastState get updated?

GetColor and getNextMode would look better as case statements.

Thanks for your response HazardsMind.

I wasn't aware of the possibility of 2D arrays, seems a much more efficient way of packaging things...

When the Boolean "isButtonPressed" runs, I am looking for it not to be true-- so that when it is true (ie when the button is triggered), it knows to "Serial.println", which calls the crossfading function.

Should I just get rid of the Boolean "isButtonPressed" I created, and replace it on line 44 with
" currentState = digitalRead(buttonPin);
if (currentState == LOW && lastState == LOW){//if button has just been pressed

If I do that, will it know to Serial.println when currentState == HIGH (the button is triggered)?

I'm not sure when lastState gets updated; delay(1000) is there for debouncing. I much appreciate your patience with my ignorance, I'm reading/learning as much and as quickly as I can.

I can see how GetColor and getNextMode would work well as Case Statements (which I didn't know existed, thank you).

Thank you very much!

When the Boolean "isButtonPressed" runs, I am looking for it not to be true-- so that when it is true (ie when the button is triggered), it knows to "Serial.println", which calls the crossfading function.

do
{
}
while (!isButtonPressed());

The ! is the not operator.

Thank you Paul!

Now I just need to figure out how to correctly call modeColor8...

in

"if (mode == mode8) return modeColor8"; if I understand correctly, this doesn't work because I'm asking it to return an int/value, which modeColor8 is not-- it's a void function.

so something like:

if (mode == mode 8) {ModeColor8()} else {getColor()}?? I imagine this can't live in the getColor function-- would it live in the void loop ()? I know the key has much to do with the below code in the void loop...

currentMode = getNextMode(currentMode);
int* colors = getColor( currentMode );
crossFade(colors);

Thanks again, Jared