The way it runs now, it will only make the change at the start of the while loop. Could someone take a look at my code and let me what I'm doing wrong?
The problem is that you are using a while loop and the problem is compounded by using delay()s within the while loop. To make the code as horrible as possible you do not use for loops either, not that using them would solve the problem.
So, how to solve the problem of making the program responsive to inputs ? Well, you have helpfully divided your program into what you call phases. I would call them states and use switch/case to control which portion of code is executed each time through loop(). Use millis() for timing and the code will run freely so that you can read inputs each time through loop(). This form of program is often referred to as a State Machine. It sounds scary but isn't
Have a look at Using millis() for timing. A beginners guide, Several things at the same time and look at the BlinkWithoutDelay example in the IDE to see how to use millis() for non blocking timing.
As to State Machines, have a look at this example. It does not do exactly what you want but it does introduce the idea of using states to control which code is executed and of doing something else in loop(). You can run it without any LEDs and monitor what it is doing using the Serial monitor.
/*
* State machine example
* Requirement :
* Blink one LED at a steady rate whilst turning on a series of LEDs for periods that are
* different for each LED
*
* The single blinking LED is implemented using the BlinkWithoutDelay principle so that its
* operation does not slow down or stop the operation of the remainder of the program
*
* Control of the other 3 LEDs is controlled using a "State Machine".
* The program is in one of 3 states during which one of the LEDs is illuminated for
* a period of time. Again timing is implemented using millis(). Once the period for the
* current state is over the program moves onto the next state in the series.
*
* NOTE : this is not necessarily the best way to write a program to meet the requirements
* but it is written this way to illustrate the use of a "State Machine". The Serial monitor
* is used for feedback as to what is happening in the program so it can be tested without LEDs
* Instead of turning an LED on for a period in each state any appropriate non blocking code for the current
* state could be run such as testing for user input and changing state if it is detected.
*/
enum ledStates //give the states names (actually numbers 0 to 2) to make reading the code easier
{
REDLED,
GREENLED,
BLUELED
};
byte currentState;
const byte blinkLedPin = 3;
const byte redLedPin = 5;
const byte greenLedPin = 6;
const byte blueLedPin = 9;
const byte sequenceLedPins[] = {redLedPin, greenLedPin, blueLedPin};
unsigned long sequencePeriods[] = {1500, 3500, 5500};
const byte NUMBER_OF_LEDS = sizeof(sequenceLedPins) / sizeof(sequenceLedPins[0]);
unsigned long currentTime;
unsigned long blinkLedStartTime;
unsigned long sequenceLedStartTime;
unsigned long blinkLedPeriod = 300;
void setup()
{
Serial.begin(115200);
for (int led = 0; led < NUMBER_OF_LEDS; led++) //set pinMode()s for LEDs
{
pinMode(sequenceLedPins[led], OUTPUT);
digitalWrite(sequenceLedPins[led], HIGH); //turn all sequence LEDs off initially
}
pinMode(blinkLedPin, OUTPUT);
digitalWrite(blinkLedPin, HIGH); //turn off the blinkLed initially
digitalWrite(sequenceLedPins[currentState], LOW); //turn on the sequence LED for initial state
currentState = REDLED; //start in this state
reportState();
}
void loop()
{
currentTime = millis(); //used throughout loop() for consistent timing
//let's start with the single blinking LED
if (currentTime - blinkLedStartTime >= blinkLedPeriod) //time to change the single LED state
{
digitalWrite(blinkLedPin, !digitalRead(blinkLedPin));
blinkLedStartTime = currentTime;
Serial.println(F("\tBLINK"));
}
//now we need to check which state we are in and run the appropriate code for it
//note that by using millis() for timing we keep loop() running freely
//so that we can blink the single LED
//when the priod for the current state ends we set the entry conditions for the next state,
//change the current state so that next time through the code for the next state is executed
switch (currentState)
{
case REDLED:
//when the priod for the current state ends we set the entry conditions for the next state,
//change the current state so that next time through the code for the next state is executed
if (currentTime - sequenceLedStartTime >= sequencePeriods[currentState]) //time to change states
{
digitalWrite(sequenceLedPins[currentState], HIGH); //turn off current LED
sequenceLedStartTime = currentTime; //start time for next state
currentState = GREENLED; //next state to move to
reportState();
digitalWrite(sequenceLedPins[currentState], LOW); //turn on LED for target state
}
break; //end of code for this state
//
case GREENLED:
if (currentTime - sequenceLedStartTime >= sequencePeriods[currentState]) //time to change states
{
digitalWrite(sequenceLedPins[currentState], HIGH); //turn off current LED
sequenceLedStartTime = currentTime; //start time for next state
currentState = BLUELED; //next state to move to
reportState();
digitalWrite(sequenceLedPins[currentState], LOW); //turn on LED for target state
}
break; //end of code for this state
//
case BLUELED:
if (currentTime - sequenceLedStartTime >= sequencePeriods[currentState]) //time to change states
{
digitalWrite(sequenceLedPins[currentState], HIGH); //turn off current LED
sequenceLedStartTime = currentTime; //start time for next state
currentState = REDLED; //next state to move to
reportState();
digitalWrite(sequenceLedPins[currentState], LOW); //turn on LED for target state
}
break; //end of code for this state
}
}
void reportState()
{
Serial.print(F("Now in state "));
Serial.print(currentState);
Serial.print(F(" for "));
Serial.print(sequencePeriods[currentState]);
Serial.println(F(" milliseconds"));
}