While loop being entered regardless of conditions

This is my first time using an arduino, however I have programmed in python for a while. I am unsure why this code isn't working as expected:

#include <LiquidCrystal_I2C.h>

LiquidCrystal_I2C lcd(0x27, 16, 2);
const int button = 2;

void setup()
{
  lcd.init();
  lcd.backlight();
  pinMode(button, INPUT);
}

void loop()
{
  lcd.clear();
    while (digitalRead(button) == true)
      {
        lcd.setCursor(0, 0);
        lcd.print("Test");
        delay(100);
      }
}

I am expecting it to only print text when I'm pressing the button, however it is flickering the text constantly (even if the button is completly disconected) - pressing the button only stops the flickering

Edit -
Thanks for all the help! Works fine now, though I feel a bit of a muppet having forgotten ground noise is a thing

has the op consider using serial prints for debugging?

like

#include <LiquidCrystal_I2C.h>

LiquidCrystal_I2C lcd(0x27, 16, 2);
const int button = 2;

void setup()
{
Serial.begin(115200);
  lcd.init();
  lcd.backlight();
  pinMode(button, INPUT);
}

void loop()
{
  lcd.clear();
Serial.print( "digitalRead(button) ";
Serial.print( digitalRead(button) );
Serial.println(); 
    while (digitalRead(button) == true)
      {
        lcd.setCursor(0, 0);
        lcd.print("Test");
        delay(100);
      }
}

?

perhaps using a pullup or down resistor with the switch may stop the input from being a floater?

switch wiring

1 Like

Disconnected arduino pin has undefined state and may change it many times at second from HIGH to LOW and vice verse.
You need to pull your button pin to LOW or to HIGh with internal or external pullup.

1 Like
1 Like

Nice to read you solved your problem, but I need to give you some small hints for a better understanding of Arduino programs.

First of all, digitalRead() returned value is actually not "true" or "false", but HIGH or LOW. They're symbols, meaning respectively the value 1 and 0.
Second, to test a value or an expression for true or false it's useless to compare it with true or false.

So instead of:
while (digitalRead(button) == true)

you can simply write:
while (digitalRead(button) == HIGH)

or, knowing that any value different from zero is considered "true", making simpler as
while (digitalRead(button))

If you use INPUT_PULLUP you must just invert the logic to:
while (digitalRead(button) == LOW)

After that, when dealing with buttons pressed, you should handle what to do if keep pressing the button. Moreover, there's no need to use "while()", it's useless continuosly print 10 times per second the same message! With your code, the LCD willi continuosly print the message making it unnecessarily flicker, especially because you keep clearing thousands of times per second (the loop() function is continuosly called).

After the message is printed, just wait for the button release, something like this (it's just an example, the code strictly depends on what you want to do while button is pressed, if you need to do it once or not, if you need to do something else in the meanwhile, and so on...):

void loop()
{
  if (digitalRead(button) == LOW) {
    // The user pressed the button! Show the message:
    lcd.setCursor(0, 0);
    lcd.print("Test");
    // Just a little debounce time here
    delay(50); 
    // Now wait until the button is released
    while (digitalRead(button) == LOW) { delay(100); }
    // Done. Now clear the message
    lcd.setCursor(0, 0);
    lcd.print("    ");
  }
}
1 Like

More like this?

#include <LiquidCrystal_I2C.h>

LiquidCrystal_I2C lcd(0x27, 16, 2);
const int button = 2;

void setup()
{
  lcd.init();
  lcd.backlight();
  pinMode(button, INPUT_PULLUP);
  lcd.clear();
  lcd.setCursor(0, 0);
  lcd.print("Button test");
}

void loop()
{
    if (digitalRead(button) == LOW)
      {
        lcd.clear();
        lcd.setCursor(0, 0);
        lcd.print("It's working!");
        delay(500);
        lcd.setCursor(0, 1);
        lcd.print("Hurrah!");
        while (digitalRead(button) == LOW)
          {
            delay(100);
          }
          lcd.clear();
          lcd.setCursor(0, 0);
          lcd.print("Button test");
      }
}

100mS is a long time to delay. lower the delay to 1mS for a more responsive code.

Look at File|Examples|02.Digital|BlinkWithoutDelay to use millis() for timing instead of delay().

you're better off recognizing a button press (transition from off to on) rather than waiting in a while loop

consider

#include <LiquidCrystal_I2C.h>

LiquidCrystal_I2C lcd (0x27, 16, 2);

const byte PinBut = 2;
byte butLst;
byte flag;

void loop ()
{
    byte but = digitalRead (PinBut);
    if (butLst != but)  {
        butLst = but;
        delay (20);     // debounce

        if (LOW == but)  {
            flag = ! flag;
        
            lcd.clear ();
            lcd.setCursor (0, 0);

            if (flag)
                lcd.print ("on");
            else
                lcd.print ("off");

        }
    }
}

void setup ()
{
    pinMode (PinBut, INPUT_PULLUP);
    butLst = digitalRead (PinBut);

    lcd.init ();
    lcd.backlight ();
    lcd.clear ();
    lcd.setCursor (0, 0);
    lcd.print ("Button test");
}

Yep, but as the OP doesn't seem to need a time-critical system (i.e. does nothing while button presses) 10 times per second is enough.

As first approach I didn't mention that, just to keep the OP code as unchanged as possible considering he/she's not an expert Arduino coder, avoiding some (even if useful and frequent, anyway) concepts, to be later extended if necessary...:wink:

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.