Combining codes into states?

Hello all,

newb here, (go easy me!)

So… i’ve been trying to combine these two codes into one, and so far i’ve hit wall after wall… I honestly don’t know what i’m doing, and everytime i sit down with it, a few hours into it and my brain turns to mush…

the setup-

i’m making an arcade cabinet, and thought to add some led lighting for flair. One RGB strip (split into two) for the back and console, and one white LED strip to light the marquee. My intent is to use a momentary switch to cycle through different modes:

-motion sensor mode (for after hours, while the machine is off)
-stable on mode (possibly with color cycle as well?)
-music reactive mode (for when i jukebox the thing while i work)
-and off mode (honestly, the least necessary, but if we’re throwing logs on the fire…).

so far-

i got two codes from some youtube vids and have managed to tweak them to ‘pretty close’.
the first is a motion sensor LED sketch. his code triggers three led strips, plus a fourth under his kitchen cabinets. i’ve taken the three and converted them to RGB pins of a single strip (split into two) and the last i kept as is, to function as a white led strip (for my marquee). He has a momentary button, that, when pressed, keeps the lights on, and when pressed again, turns the lights off (although if you’re not out of the room in time, the sensor kicks in again.

the second, is a music reactive led sketch that (more or less) works for what i need it to do. I think i can tweek it a bit more, once i get how he devided the frequencies (but that’s not important right now).

my thoughts-

i was thinking that a switch state could do it, but every time i try to combine them, it doesn’t seem to work. I also tried adding the music reactive sketch into the motion sensor sketch, since that one had the bulk of what i needed. but then the music react doesn’t loop… it just turns red and sits there. I figure if i “int” a ‘hold button’ to cycle through cases, i can “int” a ‘press button’ to cycle through colors within in a single case.

not sure if i’m making any sense, but i’m weeks into this mess, and am losing hope, and my mind. i spent a few hours with fritzing to give you an idea of my set up, and am uploading the code(s) that i have tried to combine. the one attempt that showed the most promise is now no longer even verrifying :-/ but i can post that too if needed.

… help?

(seriously, anything you can throw my way would be greatly apprieciated.)

cheers!

Component setup:

Motion sensor code (full code, as i didn’t know what i could safely exclude):

//NeilFarr's Arduino project - make a number of kitchen LED strips fade in when an ultrasonic sensor or switch is triggered.
//contact neilsfarr@google.com


//define pins for the LEDs (using different ones for differnet strips to prevent MOSFET overloading and allow for more flexibility in the fade up sequence)
#define RLED 3  // red
#define GLED 5 // green
#define BLED 6 // blue
#define LIGHT_LED 9   // marquee
#define ONBOARD_LED 13  // so we can see what is supposed to be happening, just with the onboard LED.

#define SOUND_SENSOR A0 //microphone
#define SENSOR 4 // PIR module
#define BUTTON 7 // push to make switch

//overall brightness value
int stripbrightR = 0;
int stripbrightG = 0;
int stripbrightB = 0;
int lightbright = 0;
int ledmaxbrightness = 80; // this is the maximum PWM brightness for the LED strips (the under cabinet LED lights can be full 255 brightness, so we don't worry about those).
// note that I set this at 80 for a good lighting for my use - remember the lights don't follow a linear brightness so have a play to see what works

int fadeSpeed1 = 50;
int fadeSpeed2 = 10; //slightly faster fade out time

int offset = 15; //offset allows for one light to begin the glow after the other one
int totaltime = 255 + (offset * 4); // 255 is the maximum brightness value

bool stillactive = false;
bool switchactive = false;
bool switchpressed = false;

unsigned long previousMillis = 0;         // will store last time LED was updated
unsigned long interval = 60000;           // interval at which to wait in an ON state (milliseconds) - basically 1 minutes since last movement - change this temporarily for testing to 10000
unsigned long currentMillis = millis();   // defining the variable - it will get set to the current time when things need to start/stop
unsigned long switchpressedMillis = 0;    //used to track debounce
unsigned long debouncetime = 250;
void setup() {

  Serial.begin(9600);
  //setup sensor and switch pins to input
  pinMode (SENSOR, INPUT_PULLUP);
  pinMode (BUTTON, INPUT);

  //set up LED pins to output.
  pinMode(RLED, OUTPUT);
  pinMode(GLED, OUTPUT);
  pinMode(BLED, OUTPUT);
  pinMode(LIGHT_LED, OUTPUT);

  //setup the onboard LED to show the same state
  pinMode(ONBOARD_LED, OUTPUT);

  //and set the lights to off
  analogWrite(RLED, 0);
  analogWrite(GLED, 0);
  analogWrite(BLED, 0);
  analogWrite(LIGHT_LED, 0);
  analogWrite(ONBOARD_LED, 0);
}

void loop() {

  //flash the light to show it in a ready state.
  analogWrite(ONBOARD_LED, 255);
  delay(250);
  analogWrite(ONBOARD_LED, 0);
  delay(250);
  analogWrite(ONBOARD_LED, 255);
  delay(250);
  analogWrite(ONBOARD_LED, 0);
  delay(250);

  switchactive = false;
  //wait for the sensor
  do {
    currentMillis = millis(); //twiddle thmbs, waiting for the sensor to trigger
  } while (digitalRead(SENSOR) == LOW);  // you could also wait for the button here but make sure to DEBOUNCE the input

  //Once triggered, turn on

  TurnOn();
  previousMillis = millis();
  stillactive = true;
  Serial.println("Motion detected");

  // and keep on for a few seconds unless triggered again

  do {
    currentMillis = millis();

    if ((currentMillis - previousMillis >= interval) or (currentMillis < 5)) { // if the 'on' time has passeed OR the internal timer has reset to 0 (after c.50 days)
      stillactive = false ;//QUIT the loop
    }
    if (switchactive == true) {  //if sensor triggered
      previousMillis = currentMillis; //reset the counter to allow constan movement to keep the lights on
      Serial.println("switch mode enabled");
    }
    if (digitalRead(SENSOR) == HIGH)  {  //if sensor triggered
      previousMillis = currentMillis; //reset the counter to allow constan movement to keep the lights on
      Serial.println("sensor triggered");
    }

    if (digitalRead(BUTTON) == LOW) {  // if switch pushed

      //debounce the switch
      switchpressedMillis = currentMillis;
      switchpressed = true;
      do {
        if (digitalRead(BUTTON) == HIGH) {
          switchpressed = false;
        }
        switchpressedMillis = millis();
      } while (switchpressedMillis - currentMillis < debouncetime) ;

      if (switchpressed == true) {
        Serial.println("switch pressed");

        if (switchactive == true) {
          Serial.println("switch pressed to STOP the lights");
          analogWrite(LIGHT_LED, 0);
          delay(250); // remind you it has been set and allow you time to let go of the button
          analogWrite(LIGHT_LED, 255);
          delay(1000);
          switchactive = false; // reset the variable
          stillactive = false; // quit the loop
        }
        else {
          switchactive = true; //set the variable to show the switch was activated
          Serial.println("switch pressed to extend the lights");
          analogWrite(LIGHT_LED, 0);
          delay(250); // remind you it has been set and allow you time to let go of the button
          analogWrite(LIGHT_LED, 255);
          delay(250);
          delay(500); // allow you time to let go of the button

        }
      }

    }
  } while (stillactive == true);
  Serial.println("Time finished - turning off");
  TurnOff();
}


void TurnOn() {
  analogWrite(ONBOARD_LED, 255); // show the lights are supposed to be on
  for (int i = 0; i < totaltime; i++) {

    stripbrightR = constrain (i, 0, ledmaxbrightness); //maximum brightness set to a lower brightness - could be 255 but I prefer them a little dimmer - this also lengthens the life of the MOSFETs and LEDs
    stripbrightB = constrain ((i - offset), 0, ledmaxbrightness); // start the next lights a little time after
    lightbright  = constrain ((i - (offset * 2)), 0, 180); // start the next lights a little time after - note that the max brightness is 255 for these as they are the undercounter ones
    stripbrightG = constrain ((i - (offset * 3)), 0, ledmaxbrightness); // start the next lights a little time after
    analogWrite(RLED, stripbrightR);
    analogWrite(GLED, stripbrightG);
    analogWrite(BLED, stripbrightB);
    analogWrite(LIGHT_LED, lightbright);
    delay(fadeSpeed1);
  }
}

void TurnOff() {
  analogWrite(ONBOARD_LED, 0); // show the lights are supposed to be off
  for (int i = 255; i >= 0; --i) {
    analogWrite(RLED, constrain (i, 0, ledmaxbrightness));
    analogWrite(GLED, constrain (i, 0, ledmaxbrightness));
    analogWrite(BLED, constrain (i, 0, ledmaxbrightness));
    analogWrite(LIGHT_LED, i);  // no constrain as these were set to 255 as they are the under counter lights.
    delay(fadeSpeed2);
  }
}

(hope i did that right)

music react code (minus defines):

float sensorValue = 0, filteredSignal = 0,
    filteredSignalValues[] = {3.4, 3.1, 2.7, 2.4, 2.1, 1.7, 1.3, 0.9, 0.4};

void setup () {

  Serial.begin (9600);
}

void loop () {

  MainFunction();
}

void MainFunction() {

  sensorValue = (float) analogRead(SOUND_SENSOR) * (5.0 / 1024.0);

  FilterSignal(sensorValue);

  Serial.print(sensorValue);
  Serial.print(" ");
  Serial.println(filteredSignal);

  CompareSignalFiltered(filteredSignal);
}

void FilterSignal(float sensorSignal) {

  filteredSignal = (0.945 * filteredSignal) + (0.0549 * sensorSignal);
}

void CompareSignalFiltered(float filteredSignal) {

  if (filteredSignal > filteredSignalValues[0]) {
    RGBColor(0, 0, 255);
    Serial.println("Blue");
  } else if (filteredSignal <= filteredSignalValues[0] && filteredSignal > filteredSignalValues[1]) {
    Serial.println("Azure");
    RGBColor(0, 255, 255);
  } else if (filteredSignal <= filteredSignalValues[1] && filteredSignal > filteredSignalValues[2]) {
    RGBColor(0, 127, 255);
    Serial.println("Cyan");
  } else if (filteredSignal <= filteredSignalValues[2] && filteredSignal > filteredSignalValues[3]) {
    RGBColor(0, 255, 127);
    Serial.println("Aqua marine");
  } else if (filteredSignal <= filteredSignalValues[3] && filteredSignal > filteredSignalValues[4]) {
    RGBColor(0, 255, 0);
    Serial.println("Green");
  } else if (filteredSignal <= filteredSignalValues[4] && filteredSignal > filteredSignalValues[5]) {
    RGBColor(255, 255, 0);
    Serial.println("Yellow");
  } else if (filteredSignal <= filteredSignalValues[5] && filteredSignal > filteredSignalValues[6]) {
    RGBColor(255, 0, 255);
    Serial.println("Magenta");
  } else if (filteredSignal <= filteredSignalValues[6] && filteredSignal > filteredSignalValues[7]) {
    RGBColor(255, 0, 127);
    Serial.println("Rose");
  } else if (filteredSignal <= filteredSignalValues[7] && filteredSignal > filteredSignalValues[8]) {
    RGBColor(255, 127, 0);
    Serial.println("Orange");
  } else if (filteredSignal <= filteredSignalValues[8]) {
    RGBColor(255, 0, 0);
    Serial.println("Red");
  } else {
    RGBColor(0, 0, 255);
    Serial.println("Default: Blue");
  }
}

void RGBColor(int Rcolor, int Gcolor, int Bcolor) {

  analogWrite(BLED, Bcolor);
  analogWrite(GLED, Gcolor);
  analogWrite(RLED, Rcolor);

  delay(delayLEDS);
} 

p.s. if i’ve posted this incorrectly, please let me know… this is new to me too!

That’s good because it is rare that anyone safely excludes something, especially when the problem is unknown.

You might as well post the entire second sketch for the same reason. While what you omitted may be “obvious”, it might not be to us unless even if we spend time thinking about it, which only subtracts from the time we can spend thinking about the real issues…

L8R

a7

1 Like

there’s a lot to sift thru as well as trying to reverse engineer what the code is intended to do. the nested while loops in your first code listing waiting for timers to expire or input states to change make the code difficult to understand

in general, each thing you are trying to do can be a separate function or set of sub-functions along with common utility functions

providing a clear explanation in words for each activity will help. and of course, separate activities may interact, possibly thru state variables

in general, break the code into various activities that are “polled” each loop() cycle. this is architecture

at a lower level, things can be done less complicated

repeated groups of instructions

        analogWrite(RLED, constrain (i, 0, ledmaxbrightness));
        analogWrite(GLED, constrain (i, 0, ledmaxbrightness));
        analogWrite(BLED, constrain (i, 0, ledmaxbrightness));

should be replaced by a function call, such as done

void RGBColor(int Rcolor, int Gcolor, int Bcolor) {
    analogWrite(BLED, Bcolor);
    analogWrite(GLED, Gcolor);
    analogWrite(RLED, Rcolor);
    delay(delayLEDS);
}

when comparing a value to a range, the boundary of a range can be checked sequentially from highest to lowest values

else if (filteredSignal <= filteredSignalValues[7]) {

within your first code listing, there are 3 while loops that should be unnecessary because loop() is repeatedly called from the arduino main()

loop() should have code or have sub-function that check for conditions and perform some action if the condition exist

a condition may be that time period has expired, such as this

if ((currentMillis - previousMillis >= interval)

of course there can be a boolean indicating that this condition must be tested, or simply that interval > 0

another condition may be that some input has changed state. a common approach is

byte but = digitalRead (ButPin);
if (butLst != but)  {
    butLst = but;
    if (LOW == but) {
        ...
   }
}

the second sketch simply had:

#define BLED 6
#define GLED 5
#define RLED 3
#define delayLEDS 3
#define SOUND_SENSOR A0

as defines… i’d renamed them in preparation of combining the two codes…!

first of all, thank you!!

so, if i’ve understood correctly, i can replace the language used in the first sketch to call the rgbs with the language used in the second sketch? (less complicated is definately good!)

as for eliminating while loops, i think that’s what i was hoping to accomplish…? i have to admit, i’m not sure i understand the ‘byte’ thing… that’s to check the presses of the button and call different functions, yes? my first go through i used a couple of simple ‘if’ buttonpolls i tried to link to each sketch as a function…! I’ll take some time o research ‘bytes’ and try it out.

i guess i’ll start with the basic architecture (again)… and post what i get…!

would allow us, as well as you to better understand what you’re trying to do. (determining what to do is often much more time consuming than how to do it)

bascially, i need the button to activate different modes when pressed.

-LEDs constantly on*
-motion activated (fade on)
-music reactive

*ideally, the ‘constantly on’ would cycle through different colours via the same button (i.e. long press for the 3 different modes, and short press for the different colors when in ‘constantly on’ mode.) but that’s just bells & whistles at this point.

so “what” does each mode need to do?

can the LEDs be constantly off?
what does motion activate?
what is music “reactive”?

spell things out, don’t make assumption that we know what your talking about. even if you suggesting doing something, i make done that something several different ways, so which way do you mean

you’d be surprised that a good description can almost write the code itself

fair enough…!

so:

code starts, and arduino waits for a button push or hold (two seconds).

Hold button for 2 seconds activates mode 1

  • LEDs on, one constant colour
    here, each short button press cycles though color combinations via analog outputs of rgb pins
    e.g.:
    1st press= Red
    2nd press = Violet (red + blue)
    3rd press = Blue
    etc…
    (as a final option, LEDS could all go off)
    cycle back to red; repeat

Hold button again (2sec)
-Music reactive mode
LEDs react to analog mic input (A0), changing color (and intensity?) while music plays over a certain tollerance. (this is the second sketch in the original post)
* press button does nothing visible (if it continues to cycle through a ‘constant colors list’ in the back ground, that’s fine)

Hold again (2sec)
-motion sensor mode
LEDs start off, and fade on when motion is detected. when all is still, they fade off again. (again, short button press does nothing visibly).

Hold again (2sec)
-return to mode 1. (constant LED on.)

hope that helps…!

wow. that’s much better.

i hadn’t understood that the mode switches on a long button press. that complicates handling the button. switching between modes and sub-modes

need to capture button press and release timestamps

look at the following code. of course is doesn’t handle your SENSOR, but handle short/long button presses to advance a mode and demonstrates how short button presses delt with my LEDs in mode 0.

#undef MyHW
#ifdef MyHW
byte ledPins [] = { 10, 11, 12, 13 };
byte butPin     = A1;

#else
byte ledPins [] = { 3, 5, 6, 13 };
byte butPin     = 7;
#endif

enum { Off = HIGH, On = LOW };

#define N_LEDS  sizeof(ledPins)
#define N_MODE  3
int  mode     = 0;

byte butLst   = Off;

unsigned long msecLst  = 0;
unsigned long msec;

// -----------------------------------------------------------------------------
// set LEDs based on 4-bit field
void
setLedBits (
    int  bits)
{
    for (unsigned n = 0; n < N_LEDS; n++)  {
        digitalWrite (ledPins [n], ! (bits & 1));
        bits >>= 1;
    }
}

// -----------------------------------------------------------------------------
// sequentially turn off/on each LED
byte ledState1 = 1;

void
mode1 (void)
{
    if ( (msec - msecLst) > 200)  {
        msecLst = msec;

        setLedBits (ledState1);
        ledState1 >>= 1;
        if (0 == ledState1)
            ledState1 = 0x8;
    }
}

// -----------------------------------------------------------------------------
// alternate LEDS on/off
byte ledState2 = 5;

void
mode2 (void)
{
    if ( (msec - msecLst) > 200)  {
        msecLst = msec;
        setLedBits (ledState2);
        ledState2 ^= 0xF;
    }
}

// -----------------------------------------------------------------------------
// check for short and long button presses
enum { BUT_NONE, BUT_SHORT, BUT_LONG };
int
butChk (void)
{
    static unsigned long msecLst  = 0;
    static byte reported = 1;

    byte but = digitalRead (butPin);

    if (butLst != but)  {
        butLst = but;

        delay (10);     // debounce

        if (On == but)  {
            msecLst  = msec;
            reported = 0;
        }
        else  {
            reported = 1;
            return BUT_SHORT;
        }
    }

    if (! reported && (msec - msecLst) > 2000)  {
        reported = 1;
        return BUT_LONG;
    }

    return BUT_NONE;
}

// -----------------------------------------------------------------------------
void loop() {
    msec  = millis ();

    switch (butChk ())  {
    case BUT_LONG:
        Serial.println (" long");
        mode = (mode + 1) % N_MODE;
        break;

    case BUT_SHORT:
        Serial.println (" short");
        ledState1 = (ledState1 + 1) % 16;
        break;
    }

    // invoke mode behavior
    switch (mode)  {
    case 2:
        mode2 ();
        break;

    case 1:
        mode1 ();
        break;

    default:
        setLedBits (ledState1);
        break;
    }
}

// -----------------------------------------------------------------------------
void setup() {
    Serial.begin(9600);

    for (unsigned i = 0; i < sizeof(ledPins); i++)
        pinMode (ledPins [i], OUTPUT);

    pinMode (butPin, INPUT_PULLUP);
}

This is ambitious for a first Arduino project!

yup, that sounds like me…!

ok, that helped alot! going through your code, and comparing with my previous combination attempt, i went with ‘int’ instead of 'byte’s… and started looking into ‘enum’ but i think i managed with +1 in the ‘oldM/oldC’ "int"s. (though enum might have been more tidy).

so, just as a basic foundation, here’s where i’m at so far:

#define RLED 3  // red
#define GLED 5 // green
#define BLED 6 // blue
#define W_LED 9   // marquee

#define SOUND_SENSOR A0 //microphone
#define SENSOR 4 // PIR module
#define BUTTON 7 // push to make switch

const int SHORT_PRESS_TIME = 500; // 500 milliseconds
const int LONG_PRESS_TIME = 1250; // 1 seconds

// Variables will change:
int reading;
int lastState = LOW;  // the previous state from the input pin
int currentState;     // the current reading from the input pin

int modeState = 0;
int oldM = 0;
int colorState = 0;
int oldC = 0;
int delayLEDs = 3;

unsigned long pressedTime  = 0;
unsigned long releasedTime = 0;

unsigned long lastDebounceTime = 0;  // the last time the output pin was toggled
unsigned long debounceDelay = 250;    // the debounce time; increase if the output flickers

void setup() {
  Serial.begin (9600);
  // put your setup code here, to run once:
  //setup sensor and switch pins to input
  pinMode (SENSOR, INPUT_PULLUP);
  pinMode (BUTTON, INPUT_PULLUP);

  //set up LED pins to output.
  pinMode(RLED, OUTPUT);
  pinMode(GLED, OUTPUT);
  pinMode(BLED, OUTPUT);
  pinMode(W_LED, OUTPUT); //remember to change this when adding other codes

  //and set the lights to off
  analogWrite(RLED, 0);
  analogWrite(GLED, 0);
  analogWrite(BLED, 0);
  analogWrite(W_LED, 0);
}

void loop() {
  // put your main code here, to run repeatedly:

  // read the state of the switch/button:
  currentState = digitalRead(BUTTON);

  if (currentState != lastState) {
    delay(debounceDelay);

    if (lastState == HIGH && currentState == LOW)       // button is pressed
      pressedTime = millis();
    else if (lastState == LOW && currentState == HIGH) { // button is released
      releasedTime = millis();

      long pressDuration = releasedTime - pressedTime;

      if ( pressDuration < SHORT_PRESS_TIME ) {
        Serial.println("short press detected");
        colorState = oldC + 1;                         
      }

      if ( pressDuration > LONG_PRESS_TIME ) {
        Serial.println("long hold detected");
        modeState = oldM + 1;
      }

    }


    switch (modeState) {


      case 1: {

          Serial.println("Color On Mode");


          switch (colorState) {

            case 1: {

                Serial.println("Blue");             //strts at blue
                RGBColor(0, 0, 255);
                analogWrite(W_LED, 255);            // marquee stays on for most
                oldC = colorState;
                break;
              }

            case 2: {
                Serial.println("Azure");
                RGBColor(0, 255, 255);
                oldC = colorState;
                break;
              }
            case 3: {
                RGBColor(0, 127, 255);
                Serial.println("Cyan");
                oldC = colorState;
                break;
              }
            case 4: {
                RGBColor(0, 255, 127);
                Serial.println("Aqua marine");
                oldC = colorState;
                break;
              }
            case 5: {
                RGBColor(0, 255, 0);
                Serial.println("Green");
                oldC = colorState;
                break;
              }
            case 6: {
                RGBColor(255, 255, 0);
                Serial.println("Yellow");
                oldC = colorState;
                break;
              }
            case 7: {
                RGBColor(255, 0, 255);
                Serial.println("Magenta");
                oldC = colorState;
                break;
              }
            case 8: {
                RGBColor(255, 0, 127);
                Serial.println("Rose");
                oldC = colorState;
                break;
              }
            case 9: {
                RGBColor(255, 127, 0);
                Serial.println("Orange");
                oldC = colorState;
                break;
              }
            case 10: {
                RGBColor(255, 0, 0);
                Serial.println("Red");
                oldC = colorState;
                break;
              }
            case 11: {
                RGBColor(0, 0, 0);
                Serial.println("RGB off");
                analogWrite(W_LED, 0);            // marquee off, in off mode
                oldC = 0;
                break;
              }
          }

          oldM = modeState;
          break;
        }

      case 2: {
          Serial.println("Music Mode");
          
          // insert reactive LEDs code here

          oldM = modeState;
          break;
        }

      case 3: {
          Serial.println("Motion Sensor Mode");

          // insert motion sensor code here

          oldM = 0;
          break;
        }
    }
  }
  // save the the last state
  lastState = currentState;

}

// basic rgb call structure for entire sketch (TO INCLUDE W_LED)
void RGBColor(int Rcolor, int Gcolor, int Bcolor) {

  analogWrite(BLED, Bcolor);
  analogWrite(GLED, Gcolor);
  analogWrite(RLED, Rcolor);

  delay(delayLEDs);
}

ok, so i hit another road block with this one....

as it's shown above, the color cycle works fine...! detects the short presses, and cycles through the colors one by one, prints the color and sits there waiting for input.
when i include the other two they run once, and sit there, seemingly just waiting for input.

if i move the switch state to OUTSIDE the 'if condition (basically, i moved the final bracket before 'lastState = currentState' to before the switch states, then the whole thing keeps cycling through as a loop. Doing this makes the Music Mode state work perfectly. but two things happen.

  1. while the Color Mode state 'works', it continuously prints the color (presumably every loop cycle). In fact, the "Music Mode" case continuously prints its title before each color readout. (this issue is not a priority, but i would like to clean the script up a bit, if possible....)

  2. the motion sensor script seems to interfere with the button press. I believe it's looping continuously in such a way that skips the button reading outside the switch states....

any suggestions as to why? or how to fix it?

the code as it stands is as follows:

#define RLED 3  // red
#define GLED 5 // green
#define BLED 6 // blue
#define W_LED 9   // marquee

#define SOUND_SENSOR A0 //microphone
#define SENSOR 4 // PIR module
#define BUTTON 7 // push to make switch

const int SHORT_PRESS_TIME = 500; // 500 milliseconds
const int LONG_PRESS_TIME = 1250; // 1 seconds

float sensorValue = 0, filteredSignal = 0,
      filteredSignalValues[] = {3.4, 3.1, 2.7, 2.4, 2.1, 1.7, 1.3, 0.9, 0.4};

// Variables will change:
int lastState = LOW;  // the previous state from the input pin
int currentState;     // the current reading from the input pin

int modeState = 0;
int oldM = 0;
int colorState = 0;
int oldC = 0;
int delayLEDs = 3;

unsigned long pressedTime  = 0;
unsigned long releasedTime = 0;

unsigned long lastDebounceTime = 0;  // the last time the output pin was toggled
unsigned long debounceDelay = 250;    // the debounce time; increase if the output flickers

int fadeSpeed1 = 50;
int fadeSpeed2 = 10; //slightly faster fade out time

int offset = 15; //offset allows for one light to begin the glow after the other one
int totaltime = 255 + (offset * 4); // 255 is the maximum brightness value

bool stillactive = false;
bool switchactive = false;
bool switchpressed = false;

unsigned long previousMillis = 0;         // will store last time LED was updated
unsigned long interval = 10000;           // interval at which to wait in an ON state (milliseconds) - basically 1 minutes since last movement - change this temporarily for testing to 10000
unsigned long currentMillis = millis();   // defining the variable - it will get set to the current time when things need to start/stop
unsigned long switchpressedMillis = 0;    //used to track debounce

//overall brightness value
int stripbrightR = 0;
int stripbrightG = 0;
int stripbrightB = 0;
int lightbright = 0;
int ledmaxbrightness = 80; // this is the maximum PWM brightness for the LED strips (the under cabinet LED lights can be full 255 brightness, so we don't worry about those).
// note that I set this at 80 for a good lighting for my use - remember the lights don't follow a linear brightness so have a play to see what works

void setup() {
  Serial.begin (9600);
  // put your setup code here, to run once:
  //setup sensor and switch pins to input
  pinMode (SENSOR, INPUT_PULLUP);
  pinMode (BUTTON, INPUT_PULLUP);

  //set up LED pins to output.
  pinMode(RLED, OUTPUT);
  pinMode(GLED, OUTPUT);
  pinMode(BLED, OUTPUT);
  pinMode(W_LED, OUTPUT); //remember to change this when adding other codes

  //and set the lights to off
  analogWrite(RLED, 0);
  analogWrite(GLED, 0);
  analogWrite(BLED, 0);
  analogWrite(W_LED, 0);

}


void loop() {
  // put your main code here, to run repeatedly:

  // read the state of the switch/button:
  currentState = digitalRead(BUTTON);

  if (currentState != lastState) {
    delay(debounceDelay);

    if (lastState == HIGH && currentState == LOW)       // button is pressed
      pressedTime = millis();
    else if (lastState == LOW && currentState == HIGH) { // button is released
      releasedTime = millis();

      long pressDuration = releasedTime - pressedTime;

      if ( pressDuration < SHORT_PRESS_TIME ) {
        Serial.println("short press detected");
        colorState = oldC + 1;
      }

      if ( pressDuration > LONG_PRESS_TIME ) {
        Serial.println("long hold detected");
        modeState = oldM + 1;
      }
    }
  }

  // save the the last state
  //lastState = currentState;

  switch (modeState) {


    case 1: {

        Serial.println("Color On Mode");

        switch (colorState) {

          case 1: {

              Serial.println("Blue");             //strts at blue
              RGBColor(0, 0, 255);
              analogWrite(W_LED, 255);            // marquee stays on for most
              oldC = colorState;
              break;
            }

          case 2: {
              Serial.println("Azure");
              RGBColor(0, 255, 255);
              oldC = colorState;
              break;
            }
          case 3: {
              RGBColor(0, 127, 255);
              Serial.println("Cyan");
              oldC = colorState;
              break;
            }
          case 4: {
              RGBColor(0, 255, 127);
              Serial.println("Aqua marine");
              oldC = colorState;
              break;
            }
          case 5: {
              RGBColor(0, 255, 0);
              Serial.println("Green");
              oldC = colorState;
              break;
            }
          case 6: {
              RGBColor(255, 255, 0);
              Serial.println("Yellow");
              oldC = colorState;
              break;
            }
          case 7: {
              RGBColor(255, 0, 255);
              Serial.println("Magenta");
              oldC = colorState;
              break;
            }
          case 8: {
              RGBColor(255, 0, 127);
              Serial.println("Rose");
              oldC = colorState;
              break;
            }
          case 9: {
              RGBColor(255, 127, 0);
              Serial.println("Orange");
              oldC = colorState;
              break;
            }
          case 10: {
              RGBColor(255, 0, 0);
              Serial.println("Red");
              oldC = colorState;
              break;
            }
          default: {
              RGBColor(0, 0, 0);
              Serial.println("RGB & Marquee off");
              analogWrite(W_LED, 0);            // marquee off, in off mode
              oldC = 0;
              break;
            }
        }

        oldM = modeState;
        break;
      }

    case 2: {
        Serial.println("Music Mode");

        MainFunction();               // reactive LEDs code here

        oldM = modeState;
        break;

      }

    case 3: {
        Serial.println("Motion Sensor Mode");


        do {

          RGBColor(0, 0, 0);
          analogWrite (W_LED, 0);

          currentMillis = millis(); //twiddle thmbs, waiting for the sensor to trigger
        } while (digitalRead(SENSOR) == LOW);  // you could also wait for the button here but make sure to DEBOUNCE the input

        //Once triggered, turn on

        Serial.println("Motion detected");
        TurnOn();
        previousMillis = millis();
        stillactive = true;


        // and keep on for a few seconds unless triggered again

        do {
          currentMillis = millis();

          if ((currentMillis - previousMillis >= interval) or (currentMillis < 5)) { // if the 'on' time has passeed OR the internal timer has reset to 0 (after c.50 days)
            stillactive = false;//QUIT the loop
          }

          if (digitalRead(SENSOR) == HIGH)  {  //if sensor triggered
            previousMillis = currentMillis; //reset the counter to allow constan movement to keep the lights on
            Serial.println("sensor triggered");
          }


        } while (stillactive == true);
        Serial.println("Time finished - turning off");
        TurnOff();


        oldM = 0;
        break;

      }

  }

  // save the the last state
  lastState = currentState;
}

void MainFunction() {


  sensorValue = (float) analogRead(SOUND_SENSOR) * (5.0 / 1024.0);

  FilterSignal(sensorValue);

  Serial.print(sensorValue);
  Serial.print(" ");
  Serial.println(filteredSignal);

  CompareSignalFiltered(filteredSignal);

}

void FilterSignal(float sensorSignal) {

  filteredSignal = (0.945 * filteredSignal) + (0.0549 * sensorSignal);
}

void CompareSignalFiltered(float filteredSignal) {

  if (filteredSignal > filteredSignalValues[0]) {
    RGBColor(0, 0, 255);
    Serial.println("Blue");
  } else if (filteredSignal <= filteredSignalValues[0] && filteredSignal > filteredSignalValues[1]) {
    Serial.println("Azure");
    RGBColor(0, 255, 255);
  } else if (filteredSignal <= filteredSignalValues[1] && filteredSignal > filteredSignalValues[2]) {
    RGBColor(0, 127, 255);
    Serial.println("Cyan");
  } else if (filteredSignal <= filteredSignalValues[2] && filteredSignal > filteredSignalValues[3]) {
    RGBColor(0, 255, 127);
    Serial.println("Aqua marine");
  } else if (filteredSignal <= filteredSignalValues[3] && filteredSignal > filteredSignalValues[4]) {
    RGBColor(0, 255, 0);
    Serial.println("Green");
  } else if (filteredSignal <= filteredSignalValues[4] && filteredSignal > filteredSignalValues[5]) {
    RGBColor(255, 255, 0);
    Serial.println("Yellow");
  } else if (filteredSignal <= filteredSignalValues[5] && filteredSignal > filteredSignalValues[6]) {
    RGBColor(255, 0, 255);
    Serial.println("Magenta");
  } else if (filteredSignal <= filteredSignalValues[6] && filteredSignal > filteredSignalValues[7]) {
    RGBColor(255, 0, 127);
    Serial.println("Rose");
  } else if (filteredSignal <= filteredSignalValues[7] && filteredSignal > filteredSignalValues[8]) {
    RGBColor(255, 127, 0);
    Serial.println("Orange");
  } else if (filteredSignal <= filteredSignalValues[8]) {
    RGBColor(255, 0, 0);
    Serial.println("Red");
  } else {
    RGBColor(0, 0, 255);
    Serial.println("Default: Blue");
  }
}
void TurnOn() {

  for (int i = 0; i < totaltime; i++) {

    stripbrightR = constrain (i, 0, ledmaxbrightness); //maximum brightness set to a lower brightness - could be 255 but I prefer them a little dimmer - this also lengthens the life of the MOSFETs and LEDs
    stripbrightB = constrain ((i - offset), 0, ledmaxbrightness); // start the next lights a little time after
    lightbright  = constrain ((i - (offset * 2)), 0, 180); // start the next lights a little time after - note that the max brightness is 255 for these as they are the undercounter ones
    stripbrightG = constrain ((i - (offset * 3)), 0, ledmaxbrightness); // start the next lights a little time after
    RGBColor(0, 127, 255);
    analogWrite(W_LED, lightbright);
    delay(fadeSpeed1);
  }
}

void TurnOff() {

  for (int i = 255; i >= 0; --i) {
    analogWrite(RLED, constrain (i, 0, ledmaxbrightness));
    analogWrite(GLED, constrain (i, 0, ledmaxbrightness));
    analogWrite(BLED, constrain (i, 0, ledmaxbrightness));
    analogWrite(W_LED, i);  // no constrain as these were set to 255 as they are the under counter lights.
    delay(fadeSpeed2);
  }
}

// basic rgb call structure for entire sketch (TO INCLUDE W_LED)
void RGBColor(int Rcolor, int Gcolor, int Bcolor) {

  analogWrite(BLED, Bcolor);
  analogWrite(GLED, Gcolor);
  analogWrite(RLED, Rcolor);

  delay(delayLEDs);
}

thanks again!

p.s. i do intend to clean up the 'turn on /turn off' scripts a bit...!

The why is simple enough. Previously, you only ran your state machine code after a button release. Now it runs every time around loop, causing the spamming of the colour prints.

A common technique in state machines is to only print stuff on transition to a new states. It's a bit more tricky in your case because the state change occurs outside the main state machine code.

You could have a function that prints the colour and call it when you detect a short press and remove those prints inside the switch.

As to interference with the button, you're going to need to restructure the code to remove the two while loops. You can do it by adding more states I expect, but it'll be quite major surgery.

1 Like