Project 8 (DIGITAL HOURGLASS)

Hello!
I just finished project 8, but it wasn't very stimulating so I tried to add a button instead of a tilt sensor (well, mainly because I couldn't find a tilt sensor in my Starter-kit lol). So basically, the button is supposed to reset all LED's, and it works, atleast sort of.
The problem is this: I have to hold the reset button down for the same amount of time as my "interval" variable for it to work. Look at the code please.

void setup(){
 Serial.begin(1200);
 pinMode(12, INPUT);
 pinMode(2, OUTPUT); 
 pinMode(3, OUTPUT); 
 pinMode(7, OUTPUT);
 pinMode(8, OUTPUT); 
 pinMode(9, OUTPUT); 
 pinMode(10, OUTPUT);  
 

}
int outPin = 2;
int interval = 3000; // this is how long I have to hold the button down in order for it to reset
unsigned long previousTime = 0;

void loop(){
  int inPin = digitalRead(12);
  unsigned long currentTime = millis();


  if(currentTime - previousTime  > interval){
    previousTime = currentTime;
  
    digitalWrite(outPin, HIGH);
    outPin++;
      if(outPin == 4 && digitalRead(3) == HIGH){ // I had to do this because I didn't connect the LED's in order (1..2..3..4..5 etc)
      outPin = 7;
      }
if(inPin){
  
  for(int i = 2; i <11; i++){
    digitalWrite(i, LOW);
    if(i == 3){
      i = 6;
      }
    outPin = 2;
    previousTime = currentTime;
    inPin = LOW;
}
}

}
}

Can someone please spot my bug? Please ask if you need me to explain my code a bit clearer, I know it's not the most handsome code out there!

Thanks in advance!

Hmmmmm, sorry can't help you with the bug. But, for what it's worth, my tilt switch (I think it's a tilt switch because it has a ball inside) looks nothing like the book. It has 4 legs (book says 2), basically a tall box shaped like 2 cubes high. Has "up" with an arrow on the top. There's a noise if you shake it, this is the ball bearing inside that makes the circuit.

added - yes it's a tilt switch

I'm having difficulties deciphering just what you wrote in your code, but here's an example of what should roughly happen (in a mixture of C and pseudo code) assuming your circuit is correct.

const int buttonPin = 2;
const int LEDPins[6] = {3, 4, 5, 6, 7, 8};

void setup()
{
	pinMode(buttonPin, INPUT);
	
	for (int i = 0; i < 6; i++)
		pinMode(LEDPins[i], OUTPUT);
}

void loop()
{
	if (digitalRead(buttonPin) == HIGH)
	{
		for (int i = 0; i < 6; i++)
			digitalWrite(LEDPins[i], LOW);

		timerRestart(); //pseudo
		delay(50); //short delay for debounce
	}
	
	if (yourTimerIsOver) //pseudo
	{
		digitalWriteNextLED //pseudo
	}
}

And I would also suggest checking for the tilt sensor with nass' description.

Just a guess as I'm pretty clueless myself but I think you need to define the state of your switch and make the if statement work off that. at the moment the if runs off "if(inPin)" which I'm guessing always returns 1 because yes there's an inPin? So something like (pseudocode):

buttonState = digitalRead(inPin);

if (buttonState == LOW ){ //button not pressed
do X
} else // button pressed
do Y

X would be the normal code that runs the hourglass and Y would be a reset

NB this is just a guess really but makes some sort of sense to me.

Thx for the advice guys. I couldn't spot my bug so I just wrote new (and more efficient) code, and now it works just as it should. Here it is:

void setup(){
 Serial.begin(9600);
 pinMode(2, OUTPUT);
 pinMode(3, OUTPUT);
 for(int i = 7; i < 11; i++){
   pinMode(i, OUTPUT);
 }
 pinMode(12, OUTPUT);
}

unsigned long previousTime = 0;
int interval = 2000;
int l = 2;

void loop(){
unsigned long currentTime = millis();
int buttonPin = digitalRead(12);

 if(currentTime - previousTime > interval){
   previousTime = currentTime;
   
   digitalWrite(l, HIGH);
   l++;
   
     if(l == 4){
       l = 7;
     }
     if(l == 11){
       l--;
     }
 }
 if(buttonPin){
   for(int j = 2; j < 11; j++){
     digitalWrite(j, LOW);
       if(j == 4){
         j = 6;
       }
       previousTime = currentTime;
       l = 2;
 }
 
  
}
}

What does debounce mean?

From arduino.cc/en/Tutorial/Debounce:

"...debounce an input, which means checking twice in a short period of time to make sure it's definitely pressed. Without debouncing, pressing the button once can appear to the code as multiple presses. Makes use of the millis() function to keep track of the time when the button is pressed."

Essentially Arduino may read the button multiple times because of how fast it may be processing data. If you aren't quick enough to release a button it may execute the block of code attached to the button press multiple times. In this case it's not a big deal as it would just continue restarting the timer and turning the LEDs off which wouldn't even appear to the user. However it many cases it can cause problems so I typically add a short delay. In fact, in this case it may be better not to delay as it would create an offset for the timer.

I suggest working on your coding style. Using a variable named buttonPin implied that the variable holds the pin not the value. Button value would be a better variable if you need to hold the value which you really don't here. You can just read the button state when you get to the if. Another small change that may help overall readability is adding const ints for your pins so you can easily read what each pin is for current and future work you may do on the code. Small things, but they add a large amount to readability.

Also, here's a very simple Timer class I had written in Java but quickly ported for use in Arduino code:

class Timer
{
  //end and start point
  private:
	  long end;
	  long start;
  
  public:
	  Timer(long milliseconds)
	  {
		end = milliseconds; 
		start = millis(); //current time
	  }
	  
	  bool isOver()
	  {
		if (millis() - start > end)
		  return true;
		
		return false;
	  }  
	  
	  void restart() 
	  {
		start = millis();
	  }
    
          long getTimeRemaining() {return end-(millis()-start);}
          long getStart() {return start;}
          long getEnd() {return end;}
};

I use a similar class for when I need a timer in my Arduino sketches. It may help with code clarity for your timer too.

Thanks for the explanation! I didn't try the timer but it looks like it could be very useful. Nice one!