0

So first off, I know millis() exists. Just asking out of curiosity. Say you have a button you wanna check for during a delay.. Maybe a 10 second delay. So you make a for loop that checks for input and delays 1 ms... 10,000 times. What's bad about this?

 int pin = 13;   
    bool button = false;        
    
    void setup()
    {
      pinMode(pin, INPUT);    
    }
    
    void loop()
    {

     while(button == false) {
     for(int i = 0; i<10000; i++) {
     if(digitalRead(pin,HIGH){
     button = true;
}
     delay(1);

    }
  }
}
1
  • Guess why loop() is called loop. Your code becomes simpler, if you don't nest other waiting loops inside. Simpler is Better. Commented Mar 18, 2022 at 12:18

3 Answers 3

3

You can do this, for quite simple sketches. It starts to become ugly if you add more features and conditions.

Therefore, the "correctTM" (read: professional) way is to implement a state machine. See in the IDE the non-delay blink example.

const unsigned long DELAY_MS = 1000;

int pin = 13;

enum State {
    WAITING, WORKING,
};

State state;

unsigned long startTime;

void setup()
{
    pinMode(pin, INPUT);
    state = WAITING;
    startTime = millis();
}

void loop()
{
    switch (state) {
    case WAITING:
        // You can put both conditions in one "if" with an "||" operator.
        // But it will look less clear.
        if (millis() - startTime > DELAY_MS) {
            state = WORKING;
        } else if (digitalRead(pin)) {
            state = WORKING;
        }
        break;
    case WORKING:
        // anything to do after the delay or the button
        break;
    default:
        // any error handling you see fit
        break;
    }
}

The function loop() is designed to be called endlessly in repetition. Use this to your advantage.

1

What's bad about this?

It looks a bit clunky but I suppose there is nothing particularly bad about it (apart from your typo of digitalWrite rather than digitalRead).

I would do it more like:

unsigned long now = millis ();
button = LOW;

while ((millis () - now < 10000) && (button == LOW))
  button = digitalRead (pin);
1
  • 1
    but then, if would work too in loop()
    – Juraj
    Commented Mar 18, 2022 at 7:59
0

I know millis() exists

Ok, millis is always the best way...

Say you have a button you wanna check for during a delay.. So you make a for loop that checks for input and delays 1 ms... 10,000 times.

Your code is not really doing what you want. Your while loop never ends until button is pressed so 10s delay has no sense. I suppose your code should exit after 10 seconds or if button is pressed.

Just asking out of curiosity

You're code, without millis(), should be

bool button = false;
...
...
void loop() {
  uint16_t ms2wait = 10000;
  while (button == false && --ms2wait > 0) {
    if(digitalRead(pin,HIGH)
      button = true;
    delay(1);
  }
}
3
  • In my case I don't want the while loop to end until a button is pressed. I'm also trying to bring forth discussion on why millis() is better than delaying 1ms 10,000 times.
    – BobaJFET
    Commented Mar 18, 2022 at 19:26
  • You should ask "Would my code do something else while it's waiting for an event?". If the answer is YES your code should use a millis() approach if it's NO you can use delay(). I said millis is the best way because YES is on 99,99% the right answer. In your example, 10 seconds is a huge amount of time and it's quite obvious your MCU should do something else in the meanwhile. In general checking if 10000ms are elapsed or freezing your MCU for 1ms 10000 times is quite the same.
    – Marco Cogo
    Commented Mar 26, 2022 at 8:01
  • I say quite because using1msx10000 you don't consider the time spent to run the code inside the for loop and this could increase the real delay after 10000 cycles.
    – Marco Cogo
    Commented Mar 26, 2022 at 8:01

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.