3 leds and a button, thought it was going to be simple.

I have built a circuit with 3 leds and a momentary tactile button. The red led on digital 12, yellow on 11,green on 10 and the button on 2. I have it set up so that the button is high and when pressed it goes low. Not sure if this is pull up or down. Not even sure if this is the best method but it works. I can get the whole thing to do simple things like turn all LEDs on or off or cycle through modes like blink or wave or bounce. I have been reading magazines, books, web articles, blogs, forums and everything I can find and still cant find any examples of what I need. Ok so now that we have established that I have no problems building circuits and no problem researching, here is what I need.
Here is my terrible pseudo code

green on
then
yellow on
then
red on

for now ill say 5 seconds between each, eventually it will be more like an hour.

if yellow or red is on
and if button = low (pressed)
then start over.

I have been at this for like a week trying everything i can find. If i use delays with each sequence it doesnt read the button unpressed until done going through green, yellow, red. From what i understant an interrupt is on a global scale so I dont wanna use that because I will eventually add some movement for this thing. I want this light scheme independant from everything else, this way the 3 light and button are its own function and has nothing to do with the servos or bumper switches or speakers or anything else. Please if anyone can help it would be great.

osirisenigma:
Here is my terrible pseudo code

Actual code would help. Or don't you have that?

I can get the whole thing to do simple things like turn all LEDs on or off or cycle through modes like blink or wave or bounce.

So you do have some code?


Here's how to do multiple things:

so far all i have is blink all leds on and off a few times then go green then yellow then red. This is my "default" code that i have been playing with but nothing woth saving beyond this. This is pretty much straight out of adafruits tutorials. I threw in some serial print stuff to see what the button was doing but it wont read unpressed untill the whole sequence is over. After the sequence it turns off and i have to press the button twice to get it back on to run the sequence.

int switchPin = 2;              // switch is connected to pin 2

int redPin = 12;
int yellowPin = 11;
int greenPin = 10;


int val;                        // variable for reading the pin status
int val2;                       // variable for reading the delayed/debounced status
int buttonState;                // variable to hold the button state

int lightMode = 0;              // Is the light on or off?

void setup() {
  pinMode(switchPin, INPUT);    // Set the switch pin as input

  pinMode(redPin, OUTPUT);
  pinMode(yellowPin, OUTPUT);
  pinMode(greenPin, OUTPUT);

  
  Serial.begin(9600);                // Set up serial communication at 9600bps
  buttonState = digitalRead(switchPin);   // read the initial state
}

void loop(){
  val = digitalRead(switchPin);      // read input value and store it in val
  delay(10);                         // 10 milliseconds is a good amount of time
  val2 = digitalRead(switchPin);     // read the input again to check for bounces
  if (val == val2) {                 // make sure we got 2 consistant readings!
    if (val != buttonState) {          // the button state has changed!
      if (val == LOW) {                // check if the button is pressed
        if (lightMode == 0) {          // is the light off?
          lightMode = 1;               // turn light on!

  digitalWrite(greenPin, LOW);   // sets the Green LED on
  digitalWrite(yellowPin, LOW);   // sets the Yellow LED off
  digitalWrite(redPin, LOW);      // sets the Red LED off
  delay(250);
  digitalWrite(greenPin, HIGH);   // sets the Green LED on
  digitalWrite(yellowPin, HIGH);   // sets the Yellow LED off
  digitalWrite(redPin, HIGH);      // sets the Red LED off
  delay(250);
  digitalWrite(greenPin, LOW);   // sets the Green LED on
  digitalWrite(yellowPin, LOW);   // sets the Yellow LED off
  digitalWrite(redPin, LOW);      // sets the Red LED off
  delay(250);
  digitalWrite(greenPin, HIGH);   // sets the Green LED on
  digitalWrite(yellowPin, HIGH);   // sets the Yellow LED off
  digitalWrite(redPin, HIGH);      // sets the Red LED off
  delay(250);
  digitalWrite(greenPin, LOW);   // sets the Green LED on
  digitalWrite(yellowPin, LOW);   // sets the Yellow LED off
  digitalWrite(redPin, LOW);      // sets the Red LED off
  delay(250);
  digitalWrite(greenPin, HIGH);   // sets the Green LED on
  digitalWrite(yellowPin, HIGH);   // sets the Yellow LED off
  digitalWrite(redPin, HIGH);      // sets the Red LED off
  delay(250);
  digitalWrite(greenPin, HIGH);   // sets the Green LED on
  digitalWrite(yellowPin, LOW);   // sets the Yellow LED off
  digitalWrite(redPin, LOW);      // sets the Red LED off
  delay(10000);                    // waits for a second
  digitalWrite(greenPin, LOW);    // sets the Green LED on
  digitalWrite(yellowPin, HIGH);  // sets the Yellow LED off
  digitalWrite(redPin, LOW);      // sets the Red LED off
  delay(10000);                    // waits for a second
  digitalWrite(greenPin, LOW);    // sets the Red LED off
  digitalWrite(yellowPin, LOW);   // sets the Yellow LED off
  digitalWrite(redPin, HIGH);     // sets the Green LED off
  delay(10000);                    // waits for half a second
  digitalWrite(greenPin, LOW);   // sets the Green LED on
  digitalWrite(yellowPin, LOW);   // sets the Yellow LED off
  digitalWrite(redPin, LOW);      // sets the Red LED off
  delay(250);
  digitalWrite(greenPin, HIGH);   // sets the Green LED on
  digitalWrite(yellowPin, HIGH);   // sets the Yellow LED off
  digitalWrite(redPin, HIGH);      // sets the Red LED off
  delay(250);
  digitalWrite(greenPin, LOW);   // sets the Green LED on
  digitalWrite(yellowPin, LOW);   // sets the Yellow LED off
  digitalWrite(redPin, LOW);      // sets the Red LED off
  delay(250);
  digitalWrite(greenPin, HIGH);   // sets the Green LED on
  digitalWrite(yellowPin, HIGH);   // sets the Yellow LED off
  digitalWrite(redPin, HIGH);      // sets the Red LED off
  delay(250);
  digitalWrite(greenPin, LOW);   // sets the Green LED on
  digitalWrite(yellowPin, LOW);   // sets the Yellow LED off
  digitalWrite(redPin, LOW);      // sets the Red LED off
  delay(250);
  digitalWrite(greenPin, HIGH);   // sets the Green LED on
  digitalWrite(yellowPin, HIGH);   // sets the Yellow LED off
  digitalWrite(redPin, HIGH);      // sets the Red LED off
  delay(250);
  digitalWrite(greenPin, LOW);   // sets the Green LED on
  digitalWrite(yellowPin, LOW);   // sets the Yellow LED off
  digitalWrite(redPin, LOW);      // sets the Red LED off

        } else {
          lightMode = 0;               // turn light off!
                  }
      }
    }
    buttonState = val;                 // save the new state in our variable
  }
}

I get the blocking part and thats why my button wont read until the sequence is done. I figured that out with the serial monitor. I guess my next step would be to mes around with the examples you provided until i get the desired behavior with my 3 leds but im not sure where to throw my button code in there.

There are a couple of ways to do this.

  1. Use an interrupt for the switch. I'll let you figure this one out as it may be advanced for your current knowledge level, but it is the most efficient.

  2. If you are using the loop then you cannot use delay() as this blocks everyhting else while you are witing for the delay to expire - you worked this out anyway. What you need is to run through the loop continuously and use a 'state machine' to remember which light you are one. by running through the loop you will be able keep tab of the time the light has been on AND check the button is pressed. It will look someting like this:

Define GREEN as 0, YELLOW as 1 and RED as 2

int State = GREEN
long last_pressed_time;

loop()

if button is pressed then and state = YELLOW then state = GREEN (this is just a number you can define)
if button is pressed the last_press_time = millis()

switch (state)
case GREEN: write the digital out put for GREEN
case YELOW: write the ...
case RED: write then ...
default: case = GREEN (or whatever the first state is)
end case

if millis() - last_pressed_time > 250 (milliseconds) then state=state+1, last_pressed_time = millis()

end loop

Hopefully you get the gist here. The trick is to know the time the button was pressed or the last change of lights hapened so that you can track the time untile the next one. The state machine simply says that the state you are in is one of the colours and writes to the correect output.

The link in the previous post basically does a similar thing.

Sorry to butt in but I just saw this on Youtube which may be of some help.

Using an interrupt for the button detection is going to be inadequate because there is still now way to abort a delay().

You really do need to use the millis() approach to timing. This will allow you to abort your timing and reset immediately upon pressing the button.

Ok so thi is coming along. I went with Mr. Gammons example and with some modification I can get the lights to behave the way that I want but im still not sure how to get my button to reset the sequence. I assume it would be something like this:

if (val == LOW)
millis() == millis - (greenTime + yellowTime + redTime)

Or does it not work that way? From what I have researched I can not jus reset it back to zero and that I have to minus the time that has passed. Sorry for the ignorance. I can not find any instances of something like what im trying to do and also im a .NET guy. Oh also can I have a millis 1 and millis 2 so i can run a different set of LEDs on millis 2 and reset millis 1 without effecting set 2? Did i lose anyone there?

The millis() function simply returns the number of milliseconds since the program started operating. As such you cannot write to it or assign it a value; it is read only. This would be true of similar .NET functions that report time.

If you want to remember a time when an event occurred, then you need to assign the value of millis() at the time to a variable and use it in subsequent calculations.

Think of your sequence as a progression through different states. You start in state 0 where everything is off, then you move to state 1 (let's say green light is on and everything else off), then you move to state 2 (where you turn yellow on and the rest off) and then to state 3 (where red is on and the rest off) and then back to state 0 (or 1, depending on your logic). Something (usually called an event) happens to cause the transition of your 'state machine' between states. In your program it is a time difference from the time the state was entered to 'now' for all transitions (which you were coding as blocking delay() funcion calls) but you have an additional event if you are in one of the states of a button being pressed. This is how state machines work, and all you need to implement one is a case statement and a 'state' variable, as per my previous explanation.

To 'reset' your state machine, you put it back to the state (or some other state) and then the code takes care of the rest. BTW, it is also usual to have an evet that starts the state machine, but you don't apear to have one.

Hope things are clearer now.