State Change and acting on length of input

Hey everybody!
I'm new to arduino, but have past coding experience (not so much with C++)
I've been on a crash course for the last 2 days with this and having some fun with the seed relay driver.

Right now I'm trying to get a relay to latch on or off with a quick push of a pushbutton, and I have that much working. I'm trying to get it so that if you hold the button down for more than a second from an OFF to ON condition, then the relay will turn OFF again upon release of the momentary toggle.

I can't seem to get that part of the code working after many different approaches. I'm also trying to figure out an elegant way to expand the code to independently latch/switch additional switch/relay groups. Any help there would be appreciated as well.

/*
  Set a state of a variable when you press a pushbutton ( the
 button went from off to on ).
 
 created 01-12-2009 by kasperkamperman.com
 based on example 'State change detection' by Tom Igoe
 adapted for Seeed Relay Driver
 */

const int buttonPin  = 10;     // the pin that the pushbutton is attached to
const int relayPin    = 7;    // the pin that the relay is attached to

int buttonState      = 0;     // current state of the button
int lastButtonState  = 0;     // previous state of the button
int relayState         = 0;     // remember current relay state
unsigned long startTime = 0;

void setup() {
  pinMode(buttonPin, INPUT);  // initialize the button pin as a input
  pinMode(relayPin, OUTPUT);    // initialize the button pin as a output
}

void loop() {
  // read the pushbutton input pin
  buttonState = digitalRead(buttonPin);

  // check if the button is pressed or released
  // by comparing the buttonState to its previous state
  if (buttonState != lastButtonState) {

    // change the state of the relay when someone presses the button
    if (buttonState == 1) {
      startTime = millis();
      if(relayState == 1) {
        relayState=0;
      } 
      else {
        relayState=1;
        while (buttonState == 1) {
          if ((millis() - startTime) > 1000) {
            relayState = 0;
            break;
          } 
          else {
            relayState = 1;
            break;
          }
        }
      }
    }

    // remember the current state of the button
    lastButtonState = buttonState;
  }

  // turns relay on if the relayState=1 or off if the relayState=0
  digitalWrite(relayPin, relayState);

  // adding a small delay prevents reading the buttonState to fast
  // ( debouncing )
  delay(20);
}

You can use a boolean variable, and I prefer to use HIGH and LOW with digitalRead().
At this moment, the sketch mixes three things: boolean operations, '1' and '0' and HIGH and LOW.
Please fix all indents. You can use the 'Auto Format' tool in the menu.

boolean button;
boolean previousButton;
...

button = digitalRead(buttonPin) == HIGH ? true : false;

You have two options:
1 ) Wait in a while loop until the button is released, that is what you are doing now. The sketch sequence will be fixed, and adding for example a blinking led will be hard. It is also easy to get confused and make something that is more like a maze than a sequence.
2 ) Let the loop() funtion run over and over again, without delay. Act when it is time to do something. This requires extra variables and is more complex, but the sketch can be extended and things can be added easily.

while (buttonState == 1) {
          if ((millis() - startTime) > 1000) {
            relayState = 0;
            break;
          } 
          else {
            relayState = 1;
            break;
          }
        }

Will go on ad infinitum, as you're not updating buttonState within the while() loop.

Peter_n:
You can use a boolean variable, and I prefer to use HIGH and LOW with digitalRead().
At this moment, the sketch mixes three things: boolean operations, '1' and '0' and HIGH and LOW.
Please fix all indents. You can use the 'Auto Format' tool in the menu.

boolean button;

boolean previousButton;
...

button = digitalRead(buttonPin) == HIGH ? true : false;




You have two options:
1 ) Wait in a while loop until the button is released, that is what you are doing now. The sketch sequence will be fixed, and adding for example a blinking led will be hard. It is also easy to get confused and make something that is more like a maze than a sequence.
2 ) Let the loop() funtion run over and over again, without delay. Act when it is time to do something. This requires extra variables and is more complex, but the sketch can be extended and things can be added easily.

I suppose I'm aiming for the second option but haven't been able to find any examples that I could tweak for my purposes. I'm guessing I need to create an external timer function, triggered by the press of a button. then during the button high-low state change, set up conditions for the relay.

Henry_Best:

while (buttonState == 1) {

if ((millis() - startTime) > 1000) {
            relayState = 0;
            break;
          }
          else {
            relayState = 1;
            break;
          }
        }



Will go on ad infinitum, as you're not updating buttonState within the while() loop.

code doesn't hang, it currently works as-is on my uno but only as a latching on/off. it ignores my time check.

I don't see what that while loop achieves. As Henry_Best said, since you aren't reading buttonState, if it starts off being 1, it will be 1 all the time, so why bother testing for that?

Anyway, you might find this helpful.

You need to capture the current time (with the millis() function) at the moment the button is pressed. When it is pressed long enough, set a flag to change the operation for releasing the relay as soon as the button is released.

Nick Gammon is right: how is your button connected ? how will you deal with bounce ?
You could use the Bounce library : http://playground.arduino.cc/Code/Bounce

You have to solve the bounce first.