Trouble with implementing toggle button

I am trying to add a toggle button to my project to start and stop the program.

All the other code is working as intended but the button isn’t starting the program when pressed once and stopping it when pressed again. Instead it is starting the program only when pressed and held.

I have attached the full code for the project below. Using Arduino MKR1000.

//Variables to detect current and previous button states
int oldbuttonState = 0;
int newbuttonState;
int programState = 1;

void setup() {
//Setup pin for button
  pinMode(5,INPUT);
}

void loop() {
      
  newbuttonState = digitalRead(5); 
  if (oldbuttonState == 0 && newbuttonState == 1){
    if(programState == 1){

   }
    else{
      if (oldbuttonState == 0 && newbuttonState == 1){
      if(programState == 0){
        lcd.clear();
        lcd.print("Push Button");
  
        programState = 1;
      
                  
          }
        }
      }
    }
newbuttonState = oldbuttonState;
}

sketch_nov25a.ino (7.06 KB)

To start with, I suspect that this is the wrong way round:

  newbuttonState = oldbuttonState;

I made that change and the button has started toggling but now the program only seems to run during the press of the button and not when it has been released.

I can't see how it even does that.

I would add a boolean variable that controls whether to run. Just have your button code toggle that variable, not contain the entire content of loop.

I made the changes but now the toggle isn't working again.

From what I can tell the oldbuttonState is just copying the newbuttonState instead of becoming the newbuttonStates previous value.

//Variables to detect current and previous button states
int oldbuttonState = 0;
int newbuttonState;

void setup() {

  //Setup pin for button 
 pinMode(5,INPUT);
}
void loop() {

  bool programState;
  
  newbuttonState = digitalRead(5);
 if (oldbuttonState == 0 && newbuttonState == 1){
    lcd.clear();
    programState == true;
    }

   
  if (oldbuttonState == 1 && newbuttonState == 0){
      lcd.clear();
      programState = false;
      }

  if (programState = true){
      lcd.setCursor(0,0);
      lcd.print("Press Button to");
      lcd.setCursor(0,1);
      lcd.print("Begin Program");
      
  programState = false;
    }

   if (programState = false){
  (program I am trying to run)
  programState = true
   }

oldbuttonState = newbuttonState;
  
}

Make programState global.

Fix this:

  if (programState = true)
//Variables to detect current and previous button states
int oldbuttonState = 0;
int newbuttonState;
bool programState;

void setup() {

  //Setup pin for button 
 pinMode(5,INPUT);
}
void loop() {

  
  newbuttonState = digitalRead(5);
 if (oldbuttonState == 0 && newbuttonState == 1){
    lcd.clear();
    programState == true;
    }

   
  if (oldbuttonState == 1 && newbuttonState == 0){
      lcd.clear();
      programState = false;
      }

  if (programState = true){
      lcd.setCursor(0,0);
      lcd.print("Press Button to");
      lcd.setCursor(0,1);
      lcd.print("Begin Program");
      
  programState = false;
    }

   if (programState = false){
  (program I am trying to run)
  programState = true
   }

oldbuttonState = newbuttonState;
  
}

Still having the same issues when it is a global variable.

If I make programState global it always displays the true scope even if I make it equal false.

You are using = where you mean == and vice versa.

Like this?

//Variables to detect current and previous button states
int oldbuttonState = 0;
int newbuttonState;
bool programState;

void setup() {

 //Setup pin for button
  pinMode(5,INPUT);
}

void loop() {
  newbuttonState = digitalRead(5);

  if (oldbuttonState == 0 && newbuttonState == 1){
    lcd.clear();
    programState = true;
    }
   
  if (oldbuttonState == 1 && newbuttonState == 0){
      lcd.clear();
      programState = false;
      }
    
  if (programState == true){
    lcd.setCursor(0,0);
    lcd.print("Press Button to");
    lcd.setCursor(0,1);
    lcd.print("Begin Program");
    programState = false;
    }

  if (programState == false){
  (code I am trying to run)
 
  programState = true;

  }
oldbuttonState = newbuttonState;
  
}

Not quite. I would just check for a press where one wasn't seen before, which is what your first if does. When you get a press just do:

    lcd.clear();
    programState = !programState;

Get rid of the second if.

Not 100% sure if this is what you meant but have changed the code.

//Variables to detect current and previous button states
int oldbuttonState = 0;
int newbuttonState;
bool programState;

void setup() {
//Setup pin for button
  pinMode(5,INPUT);
}

void loop() {
  newbuttonState = digitalRead(5);

 if (oldbuttonState == 0 && newbuttonState == 1){
    lcd.clear();
    programState = !programState;
  }
    
  if (programState == true){
    lcd.setCursor(0,0);
    lcd.print("Press Button to");
    lcd.setCursor(0,1);
    lcd.print("Begin Program");
    programState = false;
  }
        
  if (programState == false){
  (program I'm trying to run)
  programState = true;

   } 
oldbuttonState = newbuttonState;
  
}

When I do this it displays both the true and false to the LCD at the same time and pressing the button just temporarily clears the display.

Don't touch programState except here:

 if (oldbuttonState == 0 && newbuttonState == 1){
    lcd.clear();
    programState = !programState;
  }

Thanks! Its working great now!