Using three push buttons with one led

Hello, I want to use three push buttons with one led, where the first button turns the led on and off, the second button makes the led blink with a delay of 200 miliseconds and the third button makes the led blinks with a delay of 300 miliseconds. I want the first button to be able to turn on the led with one push and it stays that way untill i press it again where it turns off again. The second and the third buttons should only work while the led is on, so you shouldn't be able to turn on the led with no other button execpt with the first one.

I can get the first button to work as i want it to, but then the second and third button don't work. And i can get the second and third button to work but then the first button don't work.

Here is the code im trying to get to work:

//Pins
const int ledPin = 5;
const int buttonPin1 = 6;
const int buttonPin2 = 7;
const int buttonPin3 = 8;
const int intervalStep = 100;        // Sets the reduction
const int intervalDefault = 0;        // Sets the defualt blink interval
int interval = intervalDefault;        // Sets the interval between blinks
unsigned long previousMillis = 0;        // will store last time LED was updated

int i = 0;
int j = 0;
int stateNow = 0;

int stateBefore = 0;
//States
//int buttonState1;
//int buttonState2;
//int buttonState3;
int ledState = LOW;
void setup() {
  // put your setup code here, to run once:
  pinMode(ledPin, OUTPUT);
  pinMode(buttonPin1, INPUT_PULLUP);
  pinMode(buttonPin2, INPUT_PULLUP);
  pinMode(buttonPin3, INPUT_PULLUP);
  Serial.begin(115200);
}

void loop() {
  // put your main code here, to run repeatedly:
  int buttonState1 = digitalRead(buttonPin1);
  int buttonState2 = digitalRead(buttonPin2);
  int buttonState3 = digitalRead(buttonPin3);
  unsigned long currentMillis = millis();
  stateNow = digitalRead(buttonPin1);

  if (stateNow != stateBefore) {
    if (stateNow == HIGH and i == 0) {
      digitalWrite (ledPin, HIGH);
      j=1;

  }

  else if (stateNow == LOW and j==1) {
    i=1;

  }

  else if (stateNow == HIGH and i == 1) {
    digitalWrite (ledPin, LOW);
    j=0;

  }

  else if (stateNow == LOW and j == 0) {
    i=0;

}
else if (buttonState2 == 0) {
    delay(200);
    interval = 100;
    digitalWrite(ledPin, LOW);
}
  else if (buttonState3 == 0) {
    delay(200);
    interval = 300;
    digitalWrite(ledPin, ledState);
}
if (currentMillis - previousMillis >= interval) {
    // save the last time you blinked the LED
    previousMillis = currentMillis;

    // if the LED is off turn it on and vice-versa:
    ledState = !ledState;
    
    // set the LED with the ledState of the variable:
    digitalWrite(ledPin, ledState);
}
  

}

stateBefore = stateNow;

  //if(buttonState2 == 0){
    //delay(200);
    //interval = 100;
    //digitalWrite(ledPin, LOW);
  //}
  //if(buttonState3 == 0){
    //delay(200);
    //interval = 300;
    //digitalWrite(ledPin, LOW);
  //}

  //}
  
}

You might consider how the variables, containing the state of the button press, and when the variables are created to hold previous and current states of being pressed.

Just for clarity, do buttons 2 and 3 switch between the 2x blink speeds? Or do those not count as "on" in:

The second and the third buttons should only work while the led is on

I'd write it with all 3 buttons details (pin, state, prev state, newly pressed) in an array of structs, and a switch..case state machine. Check the buttons at the top of loop and update the struct.

In each case, check to see which if any button is newly pressed, and move to the next state as indicated by the pressed button. Cancel the newly pressed of a button once it's "used".

blomcrestlight:
I'd write it ....

... have subsequently done so. Shall I post it?- it's a total re-do of yours, not a fix, more a change of paradigm.

blomcrestlight:
... have subsequently done so. Shall I post it?- it's a total re-do of yours, not a fix, more a change of paradigm.

You are more than welcome to post your code, I kinde figured it out with how Im suppose to do but I would love to see how you solved it.

Here's the code.

The buttons are in an array of structs.

Each time at top of loop(), for each button i it uses state change detect to compare the current and previous state of button i, and if there's been a change it updates the new press flag for that button.

Then in the current overall state of the system (currentState) it checks which if any button has had a change, and leaves that state for the appropriate new one.

The skectch also just has led 13 blinking away delay()-lessly to prove all is well.

You didn't answer if it's legit to go from one blink speed to the other without going via off; I made it so it can't If it's ok to do that, just change the result of those button presses in those states.

// https://forum.arduino.cc/index.php?topic=671260

// state change detect on a button struct array
//    with switch..case state machine
// 17 mar 2020

//states
enum {stateOFF, stateON, stateBLINKslow, stateBLINKfast} currentState = stateOFF;
// see https://www.gammon.com.au/statemachine

// the buttons
struct buttons
{
  byte pin;
  bool state;
  bool prevState;
  bool newPress; //uses state change detection later on and sets this if newly pressed, else clear
};
const byte buttonPins[] = {6, 7, 8};
const byte numberOfButtons = sizeof(buttonPins) / sizeof(buttonPins[0]);
buttons mybuttons[numberOfButtons];

//the led
const byte ledPin = 5;
unsigned long previousMillis;
bool ledState;
int fastInterval = 100; //made more obvious for testing
int slowInterval = 500;

//the pulse led
int pulseLedInterval = 500;
unsigned long previousMillisPulse;
bool pulseState = false;

void setup()
{
  // initialize serial communication:
  Serial.begin(9600);
  Serial.println("setup() ... ");
  Serial.println("** state change array of struct **");
  Serial.print("Compiler: ");
  Serial.print(__VERSION__);
  Serial.print(", Arduino IDE: ");
  Serial.println(ARDUINO);
  Serial.print("Created: ");
  Serial.print(__TIME__);
  Serial.print(", ");
  Serial.println(__DATE__);
  Serial.println(__FILE__);

  // initialize the button pins as input with pullup so active low
  //    make sure the button is from pin to ground
  Serial.println(" ");
  Serial.print("Initialising "); Serial.print(numberOfButtons); Serial.println(" pins");
  for (int i = 0; i < numberOfButtons; i++)
  {
    mybuttons[i].pin = buttonPins[i];
    pinMode(mybuttons[i].pin, INPUT_PULLUP);
    mybuttons[i].state = digitalRead(mybuttons[i].pin);
    mybuttons[i].prevState = mybuttons[i].state;
    mybuttons[i].newPress = 0;
    Serial.print("Button: "); Serial.print(i);
    Serial.print(", Pin: "); Serial.print(mybuttons[i].pin);
    Serial.print(", State: "); Serial.print(mybuttons[i].state);
    Serial.print(", Prev state: "); Serial.print(mybuttons[i].prevState);
    Serial.print(", New press: "); Serial.print(mybuttons[i].newPress);
  }

  //initialise pulse led
  pinMode(LED_BUILTIN, OUTPUT);
  digitalWrite(LED_BUILTIN, pulseState);
  pinMode(ledPin, OUTPUT);
  Serial.println(" ");
  Serial.println("setup() done");
  Serial.println("Press a button....");
  Serial.println(" ");
}

void loop()
{
  checkForButtonStateChange();
  stateMachine();
  doPulse();
} //loop

void checkForButtonStateChange()
{
  for (int i = 0; i < numberOfButtons; i++)
  {
    mybuttons[i].state = digitalRead(mybuttons[i].pin);
    // compare the buttonState to its previous state
    if (mybuttons[i].state != mybuttons[i].prevState) // means it changed... but which way?
    {
      if (mybuttons[i].state == LOW)  // changed to pressed
      {
        Serial.print(i);
        Serial.print(" newly pressed");
        mybuttons[i].newPress = true;
      }
      // poor man's de-bounce
      delay(50);
    }
    // save the current state as the last state, for next time through the loop
    mybuttons[i].prevState = mybuttons[i].state;
  }
} // checkForButtonStateChange()

void stateMachine()
{
  switch (currentState)
  {
    case stateOFF:
      digitalWrite(ledPin, LOW);

      if (mybuttons[0].newPress)
      {
        Serial.println(", Switching ON");
        mybuttons[0].newPress = false;
        currentState = stateON;
      }

      if (mybuttons[1].newPress)
      {
        Serial.println(", ignored");
        mybuttons[1].newPress = false;
      }

      if (mybuttons[2].newPress)
      {
        Serial.println(", ignored");
        mybuttons[2].newPress = false;
      }

      break;

    case stateON:
      digitalWrite(ledPin, HIGH);

      if (mybuttons[0].newPress)
      {
        Serial.println(", Switching OFF");
        mybuttons[0].newPress = false;
        currentState = stateOFF;
      }

      if (mybuttons[1].newPress)
      {
        Serial.println(", Switching to BLINK fast");
        mybuttons[1].newPress = false;
        currentState = stateBLINKfast;
      }

      if (mybuttons[2].newPress)
      {
        Serial.println(", Switching to BLINK slow");
        mybuttons[2].newPress = false;
        currentState = stateBLINKslow;
      }
      break;

    case stateBLINKfast:

      if (millis() - previousMillis >= (unsigned long) fastInterval)
      {
        previousMillis = millis();
        ledState = !ledState;
        digitalWrite(ledPin, ledState);
      }

      if (mybuttons[0].newPress)
      {
        Serial.println(", Switching OFF");
        mybuttons[0].newPress = false;
        currentState = stateOFF;
      }

       if (mybuttons[1].newPress)
      {
        Serial.println(", ignored");
        mybuttons[1].newPress = false;
      }

      if (mybuttons[2].newPress)
      {
        Serial.println(", ignored"); //or we could switch to blink slow if that's allowed
        mybuttons[2].newPress = false;
      }
      break;

    case stateBLINKslow:

      if (millis() - previousMillis >= (unsigned long)slowInterval)
      {
        previousMillis = millis();
        ledState = !ledState;
        digitalWrite(ledPin, ledState);
      }

      if (mybuttons[0].newPress)
      {
        Serial.println(", Switching OFF");
        mybuttons[0].newPress = false;
        currentState = stateOFF;
      }

       if (mybuttons[1].newPress)
      {
        Serial.println(", ignored"); //or we could switch to blink fast if that's allowed
        mybuttons[1].newPress = false;
      }

      if (mybuttons[2].newPress)
      {
        Serial.println(", ignored");
        mybuttons[2].newPress = false;
      }
      break;
  }//switch
}//sm


void doPulse()
{
  if (millis() - previousMillisPulse >= (unsigned long)pulseLedInterval)
  {
    previousMillisPulse = millis();
    pulseState = !pulseState;
    digitalWrite(LED_BUILTIN, pulseState);
  }
} //doPulse