How to read changes immediately?

Microcontroller used is Teensy 3.2
Arduino 1.8.1

I have pushbutton and a toggle switch (ON1,OFF,ON2)

Pushbutton changes the screen.

Push once: Screen 1
Push twice: Screen 2
Push thrice: Screen 3
Push 4th time: Screen 1
Push 5th time: Screen 2
.
.
.
Continues.

In my screen 1, when the toggle switch's position is changed, I want it to immediately show in my LCD.
What is happening now is that when it is in screen 1, and I changed the toggle switch's position, the code is stuck in that loop and it will not display that change unless I push the button until it completes the loop.

Below is what I am trying to explain above.

Screen 1 shows(position 1 of toggle switch):
on11

toggle switch position switched to off
Screen 1 still shows:
on11

toggle switch position switched to on2
Screen 1 still shows:
on11

The only problem I am facing is this. Is there a way to code so that I don't need to rewrite my code? I've tried interrupts and it does not seem to be working or I may be doing it the wrong way.

#include <Wire.h> 
#include <LiquidCrystal_I2C.h>

LiquidCrystal_I2C lcd(0x3F,20,4); // set the LCD address to 0x27 for a 16 chars and 2 line display
const int pbPin = 10;
const int on1 = 11;
const int on2 = 12;
int bState=0;
int prevbState=0;
int counter=0;
int counterA=0;
int on11=0; //to read on1
int on22=0; //to read on2

void setup()
{
  pinMode(10,INPUT); //pushbutton (pbPin) 
  pinMode(11,INPUT); //toggle-switch (on1)
  pinMode(12,INPUT); //toggle-switch (on2)
  //attachInterrupt(digitalPinToInterrupt(14), screen, HIGH);
  //attachInterrupt(digitalPinToInterrupt(15), screen, HIGH);
lcd.init(); // initialize the lcd 
lcd.init();
// Print a message to the LCD, was a standard code when I copied from the web
lcd.backlight();
lcd.setCursor(3,0);
lcd.print("Hello, world!");
lcd.setCursor(2,1);
lcd.print("Ywrobot Arduino!");
lcd.setCursor(0,2);
lcd.print("Arduino LCM IIC 2004");
lcd.setCursor(2,3);
lcd.print("Power By Ec-yuan!");
Serial.begin(9600);
delay(1000);
lcd.clear();
}


void loop()
{
  lcd.setCursor(0,0);
on11=digitalRead(on1);
on22=digitalRead(on2);
  bState = digitalRead(pbPin);
  Serial.println(counter);
      counterA=counter%3;
  if(bState!=prevbState)
  {
    if(bState==HIGH)
    {
      counter++;
      lcd.print(counter);
      lcd.setCursor(0,1);
      switch(counterA)
      {
      case 0:
      lcd.clear();
      lcd.setCursor(0,1);
      if(on11==HIGH)
        {
          lcd.print("on11");
        }
        else if(on22==HIGH)
        {
          lcd.print("on22");
        }
        else
        {
          lcd.print("off");
        }
      break;
      case 1:
      lcd.clear();
      lcd.print("Screen 2");
      
      break;
      case 2:
      lcd.clear();
      lcd.print("Screen 3");

      break;
      default:
      lcd.print("0");
      break;


      
      }
      
    }  
      else{}
  }
  prevbState = bState;

}

Thanks in advance for taking the time to read. Appreciated

you need to remove delay() and use millis() for timing to allow responsive code

How are the inputs wired ?

arduino_new:
you need to remove delay() and use millis() for timing to allow responsive code

The only delay() is in setup() which will not cause a problem reading inputs in a timely manner.

Basically you need a state change detection, like you are using for the button.

Since you want to do the same thing in two places (printing "on11" etc BTW gruesome names),
you should move that into a function.
Try to minimize the use of clear(), it makes your screen flicker.

I think you want to have something like the following (compiled, untested)

#include <Wire.h>
#include <LiquidCrystal_I2C.h>

LiquidCrystal_I2C lcd(0x3F, 20, 4); // set the LCD address to 0x27 for a 16 chars and 2 line display
const byte pbPin = 10;
const byte on1 = 11;
const byte on2 = 12;
byte bState = 0;
byte prevbState = 0;
int counter = 0;
int counterA = 0;
byte on11 = 0; //to read on1
byte on22 = 0; //to read on2
byte oldOn11 = 0;
byte oldOn22 = 0;

void setup()
{
  pinMode(10, INPUT); //pushbutton (pbPin)
  pinMode(11, INPUT); //toggle-switch (on1)
  pinMode(12, INPUT); //toggle-switch (on2)
  lcd.init();
  lcd.backlight();
  lcd.setCursor(3, 0);
  lcd.print(F("Hello, world!"));
  lcd.setCursor(2, 1);
  lcd.print(F("Ywrobot Arduino!"));
  lcd.setCursor(0, 2);
  lcd.print(F("Arduino LCM IIC 2004"));
  lcd.setCursor(2, 3);
  lcd.print(F("Power By Ec-yuan!"));
  Serial.begin(9600);
  delay(1000);
  lcd.clear();
}

void loop() {
  on11 = digitalRead(on1);
  on22 = digitalRead(on2);
  bool toggleChange = (on11 != oldOn11) || (on22 != oldOn22);
  bState = digitalRead(pbPin);
  if (bState != prevbState)  {
    if (bState == HIGH) {
      counterA = ++counter % 3;
      Serial.println(counter);
      lcd.setCursor(0, 0);
      lcd.print(counter);
      switch (counterA) {
        case 0:
          printSecondLine();
          break;
        case 1:
          lcd.clear();
          lcd.print(F("Screen 2"));
          break;
        case 2:
          lcd.clear();
          lcd.print(F("Screen 3"));
          break;
        default:
          lcd.setCursor(0, 1);
          lcd.print(F("0"));
          break;
      }
    }
  }
  prevbState = bState;
  if (counterA == 0 && toggleChange) {
    printSecondLine();
  }
  oldOn11 = on11;
  oldOn22 = on22;
}

void printSecondLine() {
  lcd.setCursor(0, 1);
  if (on11) {
    lcd.print(F("on11"));
  } else if (on22) {
    lcd.print(F("on22"));
  } else {
    lcd.print(F("off "));
  }
}

Whandall:
Basically you need a state change detection, like you are using for the button.

Since you want to do the same thing in two places (printing "on11" etc BTW gruesome names),
you should move that into a function.
Try to minimize the use of clear(), it makes your screen flicker.

I think you want to have something like the following (compiled, untested)

#include <Wire.h>

#include <LiquidCrystal_I2C.h>

LiquidCrystal_I2C lcd(0x3F, 20, 4); // set the LCD address to 0x27 for a 16 chars and 2 line display
const byte pbPin = 10;
const byte on1 = 11;
const byte on2 = 12;
byte bState = 0;
byte prevbState = 0;
int counter = 0;
int counterA = 0;
byte on11 = 0; //to read on1
byte on22 = 0; //to read on2
byte oldOn11 = 0;
byte oldOn22 = 0;

void setup()
{
 pinMode(10, INPUT); //pushbutton (pbPin)
 pinMode(11, INPUT); //toggle-switch (on1)
 pinMode(12, INPUT); //toggle-switch (on2)
 lcd.init();
 lcd.backlight();
 lcd.setCursor(3, 0);
 lcd.print(F("Hello, world!"));
 lcd.setCursor(2, 1);
 lcd.print(F("Ywrobot Arduino!"));
 lcd.setCursor(0, 2);
 lcd.print(F("Arduino LCM IIC 2004"));
 lcd.setCursor(2, 3);
 lcd.print(F("Power By Ec-yuan!"));
 Serial.begin(9600);
 delay(1000);
 lcd.clear();
}

void loop() {
 on11 = digitalRead(on1);
 on22 = digitalRead(on2);
 bool toggleChange = (on11 != oldOn11) || (on22 != oldOn22);
 bState = digitalRead(pbPin);
 if (bState != prevbState)  {
   if (bState == HIGH) {
     counterA = ++counter % 3;
     Serial.println(counter);
     lcd.setCursor(0, 0);
     lcd.print(counter);
     switch (counterA) {
       case 0:
         printSecondLine();
         break;
       case 1:
         lcd.clear();
         lcd.print(F("Screen 2"));
         break;
       case 2:
         lcd.clear();
         lcd.print(F("Screen 3"));
         break;
       default:
         lcd.setCursor(0, 1);
         lcd.print(F("0"));
         break;
     }
   }
 }
 prevbState = bState;
 if (counterA == 0 && toggleChange) {
   printSecondLine();
 }
 oldOn11 = on11;
 oldOn22 = on22;
}

void printSecondLine() {
 lcd.setCursor(0, 1);
 if (on11) {
   lcd.print(F("on11"));
 } else if (on22) {
   lcd.print(F("on22"));
 } else {
   lcd.print(F("off "));
 }
}

Thanks Whandall, the program works out fine with my connections. Just time to understand the program :slight_smile:
Thanks all for reading my post as well.

Whandall:
Basically you need a state change detection, like you are using for the button.

Since you want to do the same thing in two places (printing "on11" etc BTW gruesome names),
you should move that into a function.
Try to minimize the use of clear(), it makes your screen flicker.

I think you want to have something like the following (compiled, untested)

#include <Wire.h>

#include <LiquidCrystal_I2C.h>

LiquidCrystal_I2C lcd(0x3F, 20, 4); // set the LCD address to 0x27 for a 16 chars and 2 line display
const byte pbPin = 10;
const byte on1 = 11;
const byte on2 = 12;
byte bState = 0;
byte prevbState = 0;
int counter = 0;
int counterA = 0;
byte on11 = 0; //to read on1
byte on22 = 0; //to read on2
byte oldOn11 = 0;
byte oldOn22 = 0;

void setup()
{
 pinMode(10, INPUT); //pushbutton (pbPin)
 pinMode(11, INPUT); //toggle-switch (on1)
 pinMode(12, INPUT); //toggle-switch (on2)
 lcd.init();
 lcd.backlight();
 lcd.setCursor(3, 0);
 lcd.print(F("Hello, world!"));
 lcd.setCursor(2, 1);
 lcd.print(F("Ywrobot Arduino!"));
 lcd.setCursor(0, 2);
 lcd.print(F("Arduino LCM IIC 2004"));
 lcd.setCursor(2, 3);
 lcd.print(F("Power By Ec-yuan!"));
 Serial.begin(9600);
 delay(1000);
 lcd.clear();
}

void loop() {
 on11 = digitalRead(on1);
 on22 = digitalRead(on2);
 bool toggleChange = (on11 != oldOn11) || (on22 != oldOn22);
 bState = digitalRead(pbPin);
 if (bState != prevbState)  {
   if (bState == HIGH) {
     counterA = ++counter % 3;
     Serial.println(counter);
     lcd.setCursor(0, 0);
     lcd.print(counter);
     switch (counterA) {
       case 0:
         printSecondLine();
         break;
       case 1:
         lcd.clear();
         lcd.print(F("Screen 2"));
         break;
       case 2:
         lcd.clear();
         lcd.print(F("Screen 3"));
         break;
       default:
         lcd.setCursor(0, 1);
         lcd.print(F("0"));
         break;
     }
   }
 }
 prevbState = bState;
 if (counterA == 0 && toggleChange) {
   printSecondLine();
 }
 oldOn11 = on11;
 oldOn22 = on22;
}

void printSecondLine() {
 lcd.setCursor(0, 1);
 if (on11) {
   lcd.print(F("on11"));
 } else if (on22) {
   lcd.print(F("on22"));
 } else {
   lcd.print(F("off "));
 }
}

I been trying to add on another state detection from this code but up to no avail. Basically when it goes to "on11" another pushbutton can be used. That pushbutton relies on this counter which changes between 2 screens. On the first screen, for example it prints out "hello world" and the second screen it prints out "hello all".
Any guidance or help with this is appreciated.

Any guidance or help with this is appreciated.

Post your attempt, and explain what it ACTUALLY does, and how that differs from what you want.

//Current problems, not able to use pbPin2 to check the state change






#include <Wire.h>
#include <LiquidCrystal_I2C.h>

LiquidCrystal_I2C lcd(0x3F, 20, 4); // set the LCD address to 0x27 for a 16 chars and 2 line display
const byte pbPin = 5;
const byte pbPin2 = 0;
const byte on1 = 6;
const byte on2 = 7;
byte bState = 0;
byte bState2 = 0;
byte prevbState = 0;
byte prevbState2 = 0;
int counter = 0;
int counterA = 0;
int counter2 = 0;
int counterA2= 0;
byte on11 = 0; //to read on1
byte on22 = 0; //to read on2
byte oldOn11 = 0;
byte oldOn22 = 0;

void setup()
{
  pinMode(5, INPUT); //pushbutton (pbPin)
  pinMode(0, INPUT); //pushbutton (pbPin2)
  pinMode(6, INPUT); //toggle-switch (on1)
  pinMode(7, INPUT); //toggle-switch (on2)
  lcd.init();
  lcd.backlight();
  lcd.setCursor(3, 0);
  lcd.print(F("Hello, world!"));
  Serial.begin(9600);
  delay(1000);
  lcd.clear();
}

void loop() 
{
bState = digitalRead(pbPin);
bState2 = digitalRead(pbPin2);
on11 = digitalRead(on1);
on22 = digitalRead(on2);

//--------------------STATE-DETECTION FOR PUSHBUTTON 1--------------------//
if(bState != prevbState)  {
  if(bState == HIGH)  {
    counterA = ++counter % 3;
    lcd.setCursor(0,0);
    //lcd.print(counter);
//--------------------STATE-DETECTION FOR TOGGLE SWITCH--------------------//
  switch(counterA)  {
      case 0:
      lcd.clear();
      lcd.print("case 0-toggle switch");
      lcd.setCursor(0,1);
      if(on11==HIGH)  {
        lcd.print("ON11");
        lcd.setCursor(0,2);
//--------------------STATE-DETECTION FOR PUSHBUTTON 2--------------------//
/*if(bState2 != prevbState2)  {
if(bState2 == HIGH) { 
          switch(counterA2) {
          case 0:
          lcd.print("case 0-pushbutton 2");
          break;
          case 1:
          lcd.print("case 1-pushbutton 2");
          break;
          default:
          lcd.print("ERROR-PUSHBUTTON 2");
          break;
        }
}
}
prevbState2 = bState2; 
*/




        
      }
      else if(on22==HIGH){
        lcd.print("ON22");
      }
      else{lcd.print("OFF");}
      break;
      case 1:
      lcd.clear();
      lcd.print("case 1-toggle switch");
      break;
      case 2:
      lcd.clear();
      lcd.print("case 2-toggle switch");
      break;
      default:
      lcd.print("ERROR");
      break;
  }
  }
}
prevbState = bState;
//---------------------STATE-DETECTION LOOP--------------------//
if(counterA==0 && (on11!=oldOn11 || on22!=oldOn22)) {
  lcd.clear();
lcd.print("case 0-toggle switch");
      lcd.setCursor(0,1);
      if(on11==HIGH)  {
        lcd.print("ON11");
      }
      else if(on22==HIGH){
        lcd.print("ON22");
      }
      else{lcd.print("OFF  ");}
      
}
oldOn11 = on11;
oldOn22 = on22;
//--------------------STATE-DETECTION LOOP(2)--------------------//
/*if((on11!=oldOn11 || on22!=oldOn22) && counterA2 == 0)  {
  if(bState2 != prevbState2)  {
  if(bState2 == HIGH) { 
          switch(counterA2) {
          case 0:
          lcd.print("case 0-pushbutton 2");
          break;
          case 1:
          lcd.print("case 1-pushbutton 2");
          break;
          default:
          lcd.print("ERROR-PUSHBUTTON 2");
          break;
        }
}
}
prevbState2 = bState2; 
}*/

/*if(on11==HIGH)  {
//--------------------STATE-DETECTION PUSHBUTTON2--------------------//
if(bState2!=prevbState2)  {
  if(bState==HIGH)  {
    counterA2 == ++counter2 % 2;
    lcd.setCursor(0,2);
    switch(counterA2){
      case 0:
      lcd.print("case 0-Pushbutton 2");
      break;
      case 1:
      lcd.print("case 1-Pushbutton 2");
      break;
    }
  }
  else{}
}
prevbState2 = bState2;
}else{}
*/
//--------------------PUSHBUTTON 2 COUNTER--------------------//
if(bState!=prevbState)  {
if(bState==HIGH)  {
  counterA2 = ++counter % 2;
if(counterA2==0 && on11==HIGH) {
  lcd.setCursor(0,3);
  lcd.print("??????????????");
  
}
else{}

  
}
}

prevbState2 = bState2;


}

Pushbutton 1 is able to switch cases.
On case 0 of pushbutton 1, the toggle switch can switch between 3 states.
On "on11", I want it to be able to switch cases using a pushbutton which is currently not able to.

If its possible, may I have some guidance on my code as well?

#include <Wire.h>
#include <LiquidCrystal_I2C.h>

LiquidCrystal_I2C lcd(0x3F, 20, 4); // set the LCD address to 0x27 for a 16 chars and 2 line display
const byte pbPin = 5;
const byte pbPin2 = 0;
const byte on1 = 6;
const byte on2 = 7;
byte bState = 0;
byte bState2 = 0;
byte prevbState = 0;
byte prevbState2 = 0;
int counter = 0;
int counterA = 0;
int counter2 = 0;
int counterA2= 0;
byte on11 = 0; //to read on1
byte on22 = 0; //to read on2
byte oldOn11 = 0;
byte oldOn22 = 0;

void setup()
{
  pinMode(5, INPUT); //pushbutton (pbPin)
  pinMode(0, INPUT); //pushbutton (pbPin2)
  pinMode(6, INPUT); //toggle-switch (on1)
  pinMode(7, INPUT); //toggle-switch (on2)
  lcd.init();
  lcd.backlight();
  lcd.setCursor(3, 0);
  lcd.print(F("Hello, world!"));
  Serial.begin(9600);
  delay(1000);
  lcd.clear();
}

void loop() 
{
bState = digitalRead(pbPin);
bState2 = digitalRead(pbPin2);
on11 = digitalRead(on1);
on22 = digitalRead(on2);

//--------------------STATE-DETECTION FOR PUSHBUTTON 1--------------------//
if(bState != prevbState)  {
  if(bState == HIGH)  {
    counterA = ++counter % 3;
    lcd.setCursor(0,0);
    //lcd.print(counter);
//--------------------STATE-DETECTION FOR TOGGLE SWITCH--------------------//
  switch(counterA)  {
      case 0:
      lcd.clear();
      lcd.print("case 0-toggle switch");
      lcd.setCursor(0,1);
      if(on11==HIGH)  {
        lcd.print("ON11");
        lcd.setCursor(0,2);
//--------------------STATE-DETECTION FOR PUSHBUTTON 2--------------------//
/*if(bState2 != prevbState2)  {
if(bState2 == HIGH) { 
          switch(counterA2) {
          case 0:
          lcd.print("case 0-pushbutton 2");
          break;
          case 1:
          lcd.print("case 1-pushbutton 2");
          break;
          default:
          lcd.print("ERROR-PUSHBUTTON 2");
          break;
        }
}
}
prevbState2 = bState2; 
*/




        
      }
      else if(on22==HIGH){
        lcd.print("ON22");
      }
      else{lcd.print("OFF");}
      break;
      case 1:
      lcd.clear();
      lcd.print("case 1-toggle switch");
      break;
      case 2:
      lcd.clear();
      lcd.print("case 2-toggle switch");
      break;
      default:
      lcd.print("ERROR");
      break;
  }
  }
}
prevbState = bState;
//---------------------STATE-DETECTION LOOP--------------------//
if(counterA==0 && (on11!=oldOn11 || on22!=oldOn22)) {
  lcd.clear();
lcd.print("case 0-toggle switch");
      lcd.setCursor(0,1);
      if(on11==HIGH)  {
        lcd.print("ON11");
      }
      else if(on22==HIGH){
        lcd.print("ON22");
      }
      else{lcd.print("OFF  ");}
      
}
oldOn11 = on11;
oldOn22 = on22;
//--------------------STATE-DETECTION LOOP(2)--------------------//
/*if((on11!=oldOn11 || on22!=oldOn22) && counterA2 == 0)  {
  if(bState2 != prevbState2)  {
  if(bState2 == HIGH) { 
          switch(counterA2) {
          case 0:
          lcd.print("case 0-pushbutton 2");
          break;
          case 1:
          lcd.print("case 1-pushbutton 2");
          break;
          default:
          lcd.print("ERROR-PUSHBUTTON 2");
          break;
        }
}
}
prevbState2 = bState2; 
}*/

/*if(on11==HIGH)  {
//--------------------STATE-DETECTION PUSHBUTTON2--------------------//
if(bState2!=prevbState2)  {
  if(bState==HIGH)  {
    counterA2 == ++counter2 % 2;
    lcd.setCursor(0,2);
    switch(counterA2){
      case 0:
      lcd.print("case 0-Pushbutton 2");
      break;
      case 1:
      lcd.print("case 1-Pushbutton 2");
      break;
    }
  }
  else{}
}
prevbState2 = bState2;
}else{}
*/
//--------------------PUSHBUTTON 2 COUNTER--------------------//
if(bState2!=prevbState2)  {
if(bState2==HIGH)  {
  counterA2 = ++counter % 2;
if(counterA==0 && on11==HIGH && counterA2==0) {
  lcd.setCursor(0,3);
  lcd.print("??????????????");
  
}
else if(counterA==0 && on11==HIGH && counterA2==1){
  lcd.setCursor(0,3);
  lcd.print("!!!!!!!!!!!!!!");
  }

  
}
}

prevbState2 = bState2;


}

Pushbutton 1 is able to switch cases.
On case 0 of pushbutton 1, the toggle switch can switch between 3 states.
On "on11", I want it to be able to switch cases using a pushbutton which is currently not able to.
Just updated It seems that I have somehow managed to get it working.

If its possible, may I have some guidance on my code as well? Pls don't mind my naming sense, I know it can be a pain to get it through. My bad on this side.

pinMode(5, INPUT); //pushbutton (pbPin)

Good job defining the pin number constants at the top but you should use those constants. Then you don't even need the comment...

pinMode(pbPin, INPUT);

int counter = 0;
int counterA = 0;
int counter2 = 0;
int counterA2= 0

It is really going to make it 1000 times easier of you use sensible names. What do these count? Screens? States? Primary-menu?

I see a lot of copy-paste code. Try to make a function or class which does this instead. For example a Button class can keep the current state and previous state inside the class. Then methods like Button::justPressed() can return true when the button is pressed.

Try to split the screen output away from the button input. For example, when any button is pressed in a way that requires the screen to update, set a variable to true, for example updateRequired. Then you put all of the screen stuff into one function and only call that when something changes. The advantage of this is the button logic is easier to read without all of the details printing to the screen.

void loop() {
  bool updateRequired = false;
  if(buttonForward.justPressed()) {
    //do whatever the "forward" action is
    updateRequired = true;
  }
  if(buttonBackward.justPressed()) {
    //do whatever the "backward" action is
    updateRequired = true;
  }
  if(updateRequired) updateScreen();
}