LED w/ Switch, with additional timer options

Good morning, I am doing a project for my work where I am running into a slight stumbling block. This is my first project and may be a bit ambitious but I believe the right track is here if not near by? Here is the scenario to shed better light on the what and why and hows.

Parts Button, Arduino, three LEDs, 1 green, 1 yellow, and 1 red. Resistors as necessary.

Summary When someone pushes the button the green light turns on (this is the part I have done). The green light is on for 15 minutes. At 15 minutes and one second the green light turns off and the yellow light turns on. Add five more minutes, at 20 minutes and one second, the yellow LED turns off and the red one turns on.

I forgot to add, when the button is pushed a second time to turn off the timer and lights. Push the button again and the entire light/timer process starts again.

Purpose Inform a nurse a patient has been waiting too long without some form of communication of wait time.

Question Where and how to place a timer?

Current Code - Shamelessly looked up by google

const int buttonPin = 4; const int ledPin = 2;

int buttonPushCounter = 0; int buttonState = 0; int lastButtonState = 0;

void setup() { pinMode(buttonPin, INPUT); pinMode(ledPin, OUTPUT); Serial.begin(9600); }

void loop() { buttonState = digitalRead(buttonPin); if (buttonState != lastButtonState) { if (buttonState == HIGH) { buttonPushCounter++; Serial.println("on"); Serial.print("number of button pushes: "); Serial.println(buttonPushCounter); } else { Serial.println("off"); } delay(50); } lastButtonState = buttonState;

if (buttonPushCounter % 2 == 0) { digitalWrite(ledPin, HIGH); } else { digitalWrite(ledPin, LOW); }

}

Attempts Foremost, I removed the constants for my two additional LEDs (yellow and red).

  • Placed logic after the buttonPushCounter (last if statement of the code) to delay(5000) then digitialWrite(ledPin, LOW); to send to ground to turn off, then digitalWrite(ledPin2,HIGH); to turn on the yellow LED. This didn't work; green stayed lit or after pushing the button to turn it off the green light would turn off and then 5 seconds later turn on again.

Thoughts? Advice?

Thank you for any support you can offer.

Kambien

Ok, so I took the code above and frankensteined this. It works!

const int buttonPin = 4; const int ledPin = 2; const int ledPinY = 12; const int ledPinR = 9;

int buttonPushCounter = 0; int buttonState = 0; int lastButtonState = 0;

void setup() { pinMode(buttonPin, INPUT); pinMode(ledPin, OUTPUT); Serial.begin(9600); }

void loop() { buttonState = digitalRead(buttonPin); if (buttonState == HIGH) { digitalWrite(ledPin, HIGH); delay(5000); digitalWrite(ledPin, LOW); delay(50); digitalWrite(ledPinY, HIGH); delay(5000); digitalWrite(ledPinY, LOW); delay(50); digitalWrite(ledPinR, HIGH); delay(5000); } else { if (buttonState == LOW) { digitalWrite(ledPin, LOW); delay(50); digitalWrite(ledPinY, LOW); delay(50); digitalWrite(ledPinR, LOW); delay(50); }

} lastButtonState = buttonState;

}

Now to figure out how to write a command for the second button command so it doesn’t shut off until receiving a second press.

Now to figure out how to write a command for the second button command so it doesn't shut off until receiving a second press.

First change to using millis() for timing rather than delay() as during a delay() you cannot easily read and respond to a button press.

See Using millis() for timing. A beginners guide, Several things at the same time and look at the BlinkWithoutDelay example in the IDE.

You can get rid of   lastButtonState = buttonState;since you are not using it any longer and it was in the wrong place to begin with.

Thank you both!

I have removed the unnecessary button state and am currently learning milli for timing.

Alright, so now I have come up with this. I decided to instead build a second button into the mix as the "stop" or "reset" everything. Or lack of better words, "off".

I haven't converted everything to milli yet, that is to come.

I found a flaw in my logic. As the first portion of the loop, in the initial if statement which runs the LEDs on the timer. This works beautifully; however, the off button will not work until it begins the final timer. It seems like I need to validate between each timer if the off button was pushed.

Updated code:

const int buttonOn = 4; const int buttonOff = 11; const int ledPin = 2; const int ledPinY = 12; const int ledPinR = 9;

int buttonStateOn; int buttonStateOff;

void setup() { pinMode(buttonOn, INPUT); pinMode(buttonOff, INPUT); pinMode(ledPin, OUTPUT); pinMode(ledPinY, OUTPUT); pinMode(ledPinR, OUTPUT); Serial.begin(9600); }

void loop() { buttonStateOn = digitalRead(buttonOn); buttonStateOff = digitalRead(buttonOff); if (buttonStateOn == HIGH) { digitalWrite(ledPin, HIGH); delay(3000); digitalWrite(ledPin, LOW); delay(50); digitalWrite(ledPinY, HIGH); delay(5000); digitalWrite(ledPinY, LOW); delay(50); digitalWrite(ledPinR, HIGH); } if (buttonStateOff == HIGH) { digitalWrite(ledPin, LOW); delay(50); digitalWrite(ledPinY, LOW); delay(50); digitalWrite(ledPinR, LOW); delay(50); } }

It seems like I need to validate between each timer if the off button was pushed.

No No No

Use millis() for timing ( no delay()s ) and let loop() repeat freely and you can check whether the "off" button has been pressed each time through loop(), typically many thousands of times per second.

You need to turn your program into a state machine where the end of each timed state is determined by subtracting the current value of millis() from the start time of the state and comparing it with the required duration of the state.

Thank you!

I realized trying to do this between each was terribly off, I am working on building in a variable assigned to TimerA and then subtracting the amount of time necessary from it.

What do you mean by "a state machine"? Do you mean in the literal sense of passing through various states of code? Or something else? Or is my translation completely off?

Thank you again!

I am think I am stuck, I don't understand how to use the millis() well and struggling to find examples where it connects it to a sensor (2nd button = off/reset button). I have successfully recreated this with while statements, do statements, and for statements. So I guess there is progress in continuing to learn how the language interacts with the sensors we attach to the code; however, I am completely running amiss on simply stopping the entire loop when the off/reset button is switched.

Can anyone provide any guidance please?

Loving the arduino units! Quite impressive.

Your program can be in one of several states

start of loop()

in state 0 LEDs off When button 1 becomes pressed turn on green LED save state 1 start time change to state 1

in state 1 when 15 minutes have passed turn off green LED turn on yellow LED save state 2 start time change to state 2

in state 2 when 5 minutes have passed turn off yellow LED turn on red LED change to state ? What should happen next ?

each time through loop() if button 2 becomes pressed turn off all LEDs change to state 0

end of loop()

Use millis() to time the timed states. Save the start time when changing to one of these states Note that only the code for the current state plus the common code at the end is executed each time through loop(). A convenient way to do this is to use switch/case. If button 2 becomes pressed during any pass through loop() the system reverts to state 0

Ah! This makes so much more sense. THANK YOU!

Is this a good link for me to start from?

https://playground.arduino.cc/Code/FiniteStateMachine

This one may be better I am thinking. Going to start here.

http://www.instructables.com/id/Finite-State-Machine-on-an-Arduino/

UKHeliBob: Note that only the code for the current state plus the common code at the end is executed each time through loop().

Clearly having that "common code" makes practical sense, doing away with the need to check button2 in each of the other states. But I'm wondering if (note I say "wondering if", not "suggesting") there's a breach of some kind of state machine protocol there, since that common code is not inside any state, and my understanding of the whole idea of finite states is that you must be in one state or other at any time?

wilfredmedlin: Clearly having that "common code" makes practical sense, doing away with the need to check button2 in each of the other states. But I'm wondering if (note I say "wondering if", not "suggesting") there's a breach of some kind of state machine protocol there, since that common code is not inside any state, and my understanding of the whole idea of finite states is that you must be in one state or other at any time?

The program will still be in a defined state even if common code is executed. The point of the "state machine" approach is to execute the code for the current state and no other state, not no other code.

UKHeliBob: execute the code for the current state and no other state, not no other code.

That makes sense, aye.

I've updated my state machine template to include a doCommonCode() function.

Unfortunately I am at another block point and am hoping to receive some guidance. I believe I have implemented the code correctly for a finite state machine; however, I believe there is an issue with my logic to check for the initiation of the button off.

Please consider I have never written this form of code before so it's very new to me and am doing the best I can. This thread has been immensely helpful in guiding me to overcome several hurdles.

Here is my code:

#include "Arduino.h"
#define DELAY 4000 //milliseconds

static unsigned long time;
static unsigned int state;
// static unsigned int delay;

const int  buttonOn = 4;
const int  buttonOff = 11;
const int ledPin = 2;
const int ledPinY = 12;
const int ledPinR = 9;

int buttonStateOn;
int buttonStateOff;

void setup()
{
 pinMode(buttonOn, INPUT);
 pinMode(buttonOff, INPUT);
 pinMode(ledPin, OUTPUT);
 pinMode(ledPinY, OUTPUT);
 pinMode(ledPinR, OUTPUT);
 Serial.begin(9600);

 time = 0;
 state = 1;
}

void loop()
{
 switch (state)
   {
   case 1:
     buttonStateOn = digitalRead(buttonOn);
     buttonStateOff = digitalRead(buttonOff);
     if (buttonStateOn == HIGH) {
       digitalWrite(ledPin, HIGH);
       time = millis();
       if (time - millis() > DELAY) { //check if time has passed
         time = millis();
         state = 2;
       }
     } else {
       buttonStateOff = digitalRead(buttonOff);
       if (buttonStateOff = HIGH) {
         state = 4;
       }
     }
   break;
   case 2:
     if (buttonStateOff == LOW) {
       digitalWrite(ledPin, LOW);
       delay(50);
       digitalWrite(ledPinY, HIGH);
       time = millis();
         if (time - millis() > DELAY) { //check if time has passed
           time = millis();
           state = 3;
         }
       } else {
           buttonStateOff = digitalRead(buttonOff);
           if (buttonStateOff = HIGH) {
             state = 4;
           }
       }
   break;
   case 3:
     if (buttonStateOff == LOW) {
       digitalWrite(ledPinY, LOW);
       delay(50);
       digitalWrite(ledPinR, HIGH);
       time = millis();
       if (time - millis() > DELAY) { //check if time has passed
         time = millis();
         state = 3;
       } else {
         buttonStateOff = digitalRead(buttonOff);
         if (buttonStateOff = HIGH) {
           state = 4;
         }
       }
     }
   break;
   case 4:
       digitalWrite(ledPin, LOW);
       delay(50);
       digitalWrite(ledPinY, LOW);
       delay(50);
       digitalWrite(ledPinR, LOW);
   break;
   default: 
     state = 4;
     break;
   }
}

Repeated several places

if (buttonStateOff = HIGH)

== for comparison

cattledog: Repeated several places

if (buttonStateOff = HIGH)

== for comparison

Thank you! Do you know if the rest of my logic looks sound? Did I implement the FSM well/correctly?