Question about Digital Hourglass program and while loop

Hello to all of the Arduino gurus out there!

I did the “Digital Hourglass” project and after the sixth light turns on, I wanted the lights to flash 10 times, before resetting with the tilt switch.

So I added the condition that if led ==7 a while loop gets setup and they all flash 10 times and then the sequence can be reset if the tilt switch is reset.

What I am trying to is I want to be able to reset the sequence even if I am flashing all of the lights. Right now when all of the lights are flashing and I turn the breadboard over, I still have to wait for the while loop to finish then I can reset it.

I was trying to use the “break” instruction to get out of it, but it’s not working out.

Here is the code :

/define integer for tilt switch
const int switchPin = 8;

//this unsigned long integer will hold the time an LED was changed last
unsigned long previousTime =0;

//variable for initial switch state
int switchState =0;
//variable for previous switch state
int prevSwitchState =0;

//create variable named led, will be used to count which LED is the next one to be turned on.
//start with pin 2

int led = 2;

//delay time between lights
long interval = 6000;

int c=0;

void setup() {
// declare LED pins 2-7 as digital outputs, use for loop, just 3 lines

for(int x =2; x<8; x++){ pinMode(x,OUTPUT);}

//declare switchPin as digital input
pinMode(switchPin,INPUT);

}

void loop() {
// create local variable for time Arduino has been powered on

unsigned long currentTime = millis();

//use if statement to see if enough time has passed to turn on an LED.
//subtract current time from previous time and compare it to the interval
// if the interval has passed, then set previous time equal to current time
//turn on the LED and increment, the led (++) to turn on the next one

if(currentTime - previousTime> interval){
previousTime= currentTime;
digitalWrite(led,HIGH);
led++;
if(led ==7) {
delay(2500);
c=0;
while(c<10){
for(int x=2;x<8;x++){
digitalWrite(x,LOW);
}
delay(500);
for(int x=2;x<8;x++){
digitalWrite(x,HIGH);
}
delay(500);
c++;
}
}
}

//now that you have checked the time, check if the switch has changed state
//look at digital input 8
switchState = digitalRead(switchPin);

//use if statement to see if the switch is in a different state than it was previously

if(switchState != prevSwitchState){
for(int x =2;x<8;x++){
digitalWrite(x,LOW);}
led = 2;
previousTime=currentTime;}

prevSwitchState = switchState;
}

Any help or advice is greatly appreciated.

Thanks

you use millis() to time the event that turns off each LED after each interval. within that condition you can process one of two states: one the turns of the LEDs and the other that flashes the LED.

each state will need a different interval and need to determine when to change states

you may want to wait until the final LED has been turned off for the interval before changing to the flashing state

Welcome to the forums. Please read the sticky post at the top to learn how to properly post your code using code tags. It helps people help you. You can even go back and edit your post and insert the code tags!

As for your code, if you want to check the switch while you are flashing, you can not use a while() loop to do the flashing since you are never checking the switch state while inside that loop. You should implement another elapsed time checker (currentTime - previousTime, but different names) or move your switch checking code into a function that you can call inside the while() and at the end of loop().

Also, how is your switch wired up? Since you declare it as INPUT, you need a pull-up or pull-down resistor on your switch. Do you have one installed?

Hi all, thanks for the welcome. I will insert code properly in the future (just read the How to use this forum....).

The whole reason I chose the while instruction was because I couldn't think of any other way to flash the lights when led ==7... so I will try to check for the change in state for the switch outside of the while().

Also for my tilt switch(digital input) yes I have a 10k resistor wired in series with it.

Let me try some things, thanks for the suggestions!

well I did successfully move the while() loop at the end of the loop, but as you have said (and I tested with break), the while loop ignores the status change in the switch. I cannot check for the status of the switch inside the while,right?

Is there another programming method I can use to flash the lights on and off a certain number of time besides while() loop?

alexplc: Also for my tilt switch(digital input) yes I have a 10k resistor wired in series with it.

In series ?

alexplc: well I did successfully move the while() loop at the end of the loop, but as you have said (and I tested with break), the while loop ignores the status change in the switch. I cannot check for the status of the switch inside the while,right?

Is there another programming method I can use to flash the lights on and off a certain number of time besides while() loop?

Please post your revised code.

And yes, you can check the status with a digitalRead() inside a while-loop; it's ugly, in principle you should only read buttons, sensors, serial data and the likes once in loop().

Hi sterretje,

I answered you in correctly about the wiring for the tilt switch. It is wired with a pull up 10k pull up resistor.
As for getting the code to work, I’m trying a bunch of things and I just can’t get the while loop to acknowledge that the switch has changed states →

//define integer for tilt switch
  const int switchPin = 8;

  //this unsigned long integer will hold the time an LED was changed last
  unsigned long previousTime =0;

  //variable for initial switch state
  int switchState =0;
  //variable for previous switch state
  int prevSwitchState =0;

 //create variable named led, will be used to count which LED is the next one to be turned on.
 //start with pin 2

 int led = 2;
 int c=0;

 //delay time between lights
 long interval = 6000;




void setup() {
// declare LED pins 2-7 as digital outputs, use for loop, just 3 lines

  for(int x =2; x<8; x++){ pinMode(x,OUTPUT);}

  //declare switchPin as digital input
  pinMode(switchPin,INPUT);  

}

 
void loop() {
// create local variable for time Arduino has been powered on
 
  unsigned long currentTime = millis();

  //use if statement to see if enough time has passed to turn on an LED.
  //subtract current time from previous time and compare it to the interval
// if the interval has passed, then set previous time equal to current time
  //turn on the LED and increment, the led (++) to turn on the next one
  
  if(currentTime - previousTime> interval){
    previousTime= currentTime;
    digitalWrite(led,HIGH);
    led++; //preparing to light the next led


if(led ==7){
  delay(2500);
  c=0;
  while(c<5){
    for(int x=2; x<8; x++){
      digitalWrite(x,LOW);
    }
    delay(500);
     for(int x=2; x<8; x++){
      digitalWrite(x,HIGH);
    }
     delay(500);
     c++;
     const int switchPin = 8;
     switchState = digitalRead(switchPin);

     if(switchState !=prevSwitchState){
      c=5;
      break;
     }
     }
    }
   }

//now that you have checked the time, check if the switch has changed state
    //look at digital input 8
      switchState = digitalRead(switchPin);
    //use if statement to see if the switch is in a different state than it was previously
    
    if(switchState != prevSwitchState){
      for(int x =2;x<8;x++){
        digitalWrite(x,LOW);}
        led = 2;
        previousTime=currentTime;}

   prevSwitchState = switchState;
 // this is the end of the code   
    
}

The key to doing this is to not have the entire flash routine execute at once. It should just change state whenever the correct amount of time has elapsed. This allows loop() to always check the tilt switch each time through and reset when needed.

This code should do that. (It also uses an array of pins rather than your hardcoded 2…8 to add flexibility)

//define integer for tilt switch
const int switchPin = 8;
const int ledPin[] = { 2, 3, 4, 5, 6, 7 };
const int nLEDs = sizeof(ledPin) / sizeof( ledPin[0] );

//this unsigned long integer will hold the time an LED was changed last
unsigned long currentTime;
unsigned long previousTime = 0;

//variable for initial switch state
int switchState = 0;
//variable for previous switch state
int prevSwitchState = 0;

int currentIdx;

const int maxFlashCount = 10;   // times ON + OFF to flash leds
int flashCount;
bool isFlashing;

//delay time between lights
const unsigned long timeInterval = 6000;
const unsigned long flashInterval = 500;
unsigned long interval;

void setup() {
  // declare LED pins digital outputs, use for loop, just 3 lines
  for (int x = 0; x < nLEDs; x++) {
    pinMode(ledPin[x], OUTPUT);
  }

  //declare switchPin as digital input
  pinMode(switchPin, INPUT_PULLUP);
  prevSwitchState = digitalRead(switchPin);
  resetState();
}


void loop() {
  // create local variable for time Arduino has been powered on

  currentTime = millis();

  //use if statement to see if enough time has passed to turn on an LED.
  //subtract current time from previous time and compare it to the interval
  // if the interval has passed, then set previous time equal to current time
  //turn on the LED and increment, the led (++) to turn on the next one

  if (currentTime - previousTime > interval) {
    previousTime = currentTime;
    if ( isFlashing == false ) {
      // not flashing so light up next led
      digitalWrite(ledPin[currentIdx], HIGH);
      currentIdx++; //preparing to light the next led
      if (currentIdx == nLEDs) {
        // time to start flashing
        resetState();
        isFlashing = true;
        interval = flashInterval;
        delay(2500);
      }
    }
    else {
      // we are flashing
      int newState = !digitalRead(ledPin[0]); // read opposite of current state
      for (int x = 0; x < nLEDs; x++) {
        digitalWrite(ledPin[x], newState);
      }
      flashCount++;
      if ( flashCount == maxFlashCount ) {
        // we are done flashing, return to normal
        resetState();
      }
    }
  }

  //now that you have checked the time, check if the switch has changed state
  //look at digital input 8
  switchState = digitalRead(switchPin);
  //use if statement to see if the switch is in a different state than it was previously

  if (switchState != prevSwitchState) {
    resetState();
  }
  prevSwitchState = switchState;
  // this is the end of the code
}

void resetState() {
  for (int x = 0; x < nLEDs; x++) {
    digitalWrite(ledPin[x], LOW);
  }
  currentIdx = 0;
  isFlashing = false;
  flashCount = 0;
  interval = timeInterval;
  previousTime = currentTime;
}

WOW blh64! lots of new programming techniques here to me. I will say that the program is working, which is great, but if you could answer these questions so I can understand better I would greatly appreciate it.

1.) When defining the constant “nLEDs” I see that it is the size of the ledPin array divided by the size of ledPin[0] →

const int nLEDs = sizeof(ledPin)/sizeof(ledPin[0]);

-first why are we doing this? and what exactly is ledPin[0]? where does the 0 come from?

2.) for the constant “maxFlashCount” a flash of and off equals 1 flash count correct?

const int maxFlashCount = 20; // time ON+OFF to flash leds

The reason I ask is because I had to set it to 20 for the leds to flash 10 times

3.) the resetState() seems to play a big role in all of this. Can you explain how the last “void” section is setting resetState()?

void resetState() {
  for (int x=0; x< nLEDs; x++){
    digitalWrite(ledPin[x],LOW);
  }
  currentIdx =0;
  isFlashing = false;
  flashCount =0;
  interval = timeInterval;
  previousTime = currentTime;
  
}

I really like the way this was done. Now I see that I was going down the wrong road with the while loop.

Thanks for your help so far.
Alex

alexplc:
1.) When defining the constant “nLEDs” I see that it is the size of the ledPin array divided by the size of ledPin[0] →

-first why are we doing this? and what exactly is ledPin[0]? where does the 0 come from?

It is a common technique to make the compiler figure out how many elements you have in an array so if, in the future, you add or remove an element, this contant remains correct.
the sizeof() function returns the size of something in bytes. so, in your example, ledPin is an ‘int’ which is 2 bytes per element, therefore sizeof(ledPins) returns 6*2 = 12. But we want to know how many elements are in the array, not how many bytes. That is why we take the sizeof() the first element, ledPin[0]. This makes the number of elements 12 / 2 = 6. This is all done at compile time.

2.) for the constant “maxFlashCount” a flash of and off equals 1 flash count correct?

const int maxFlashCount = 20; // time ON+OFF to flash leds

The reason I ask is because I had to set it to 20 for the leds to flash 10 times

The way the code is written, your flasCount increments every time it changes state so if you consider a flash to be ON and OFF, then you have to double it.

3.) the resetState() seems to play a big role in all of this. Can you explain how the last “void” section is setting resetState()?

void resetState() {

for (int x=0; x< nLEDs; x++){
    digitalWrite(ledPin,LOW);
  }
  currentIdx =0;
  isFlashing = false;
  flashCount =0;
  interval = timeInterval;
  previousTime = currentTime;
 
}

That is how you write your own function. Several places throughout the code require resetting things back to the beginning (the start of the program, any time the sensor is tripped, after done flashing…) so rather than repeat the exact same code several places, you put it all into a function and then just call that function when/where needed.

The ‘void’ is the type of function. It means that this function does not return any value. Many functions do return some sort of value, some do not.

I really like the way this was done. Now I see that I was going down the wrong road with the while loop.

Thanks for your help so far.
Alex