The While Loop

Welcome to the first of my basic introduction to programming tutorials. In these tutorials I aim to introduce the beginner programmer (of such devices as the Arduino) to proper ways of programming.

All too often I have come across people trying to get to grips with programming in C or C++ who have just failed to grasp some of the basic concepts of how things work. One big example is the while loop.

Now, the while loop has a structure something like this:

While this condition is true, {
  Perform these operations
}

Now, that may seem pretty simple and straight forward. But, let's take an example I came across recently of someone trying to use a while loop who didn't understand exactly how it works:

int buttonStatus;

buttonStatus = digitalRead(4);
while(buttonStatus == HIGH) {
  digitalWrite(7,HIGH);
}
digitalWrite(7,LOW);

The aim of this piece of code was to have an LED light up when a button is pressed, then go out again when the button is released. At first glance, and reading it as if it were English, that program makes perfect sense:

  • Call the button press "buttonStatus".
  • While the button is pressed, light the LED.
  • Turn off the LED.

But no. That's not how it woks. What is actually happening is when the button is pressed the LED is lighting up and never going off. Why is that?

Well, let's look at exactly how the program is working.

buttonStatus = digitalRead(4);

This reads the current state of the button and stores that state in the variable buttonStatus. If the button is pressed then buttonStatus is set to HIGH. If not, it's set to LOW.

while(buttonStatus == HIGH)

This will repeat the code between the curly brackets while the value in the buttonStatus is HIGH. If the button was pressed this will be HIGH at this point.

digitalWrite(7,HIGH);

This will tell the microcontroller to light the LED. It will be doing this every time it passes through the while loop.

digitalWrite(7,LOW);

This turns off the LED, but only once the while loop has finished.

So, what is missing? Well, we're looking at the button state variable, but there is one thing we're failing to do. Namely, read the button again. The command buttonStatus = digitalRead(4); doesn't connect the variable to the button, instead it just reads the button once and remembers the state at that precise moment in time. The thing with a while loop is you have to update the value you're comparing inside the while loop. As it stands, no matter what you do with the button, the value stored in buttonState never changes.

What you should have is:

int buttonStatus;

buttonStatus = digitalRead(4);
while(buttonStatus == HIGH) { 
  digitalWrite(7,HIGH);
  buttonStatus = digitalRead(4);
}
digitalWrite(7,LOW);

Now, every pass through the while loop ends with a new request to get the current state of the button.

However, it's not perfect. There are ways it can be improved. Take the command to light the LED: digitalWrite(7,HIGH). It will be running this command constantly while the button is pressed. This is a waste of time. Once the LED is lit it will remain lit until told to switch off. It would be far better to place the lighting of the LED between the pressing of the button and the waiting for it to be released. We can do that by wrapping the while loop in an if structure:

int buttonStatus;

buttonStatus = digitalRead(4);
if(buttonStatus == HIGH) {
  digitalWrite(7,HIGH):
  while(buttonStatus == HIGH) {
    buttonStatus = digitalRead(4);
  }
  digitalWrite(7,LOW);
}

What we're saying now is, if the button has been pressed then light the LED, then wait while the button is pressed. Finally turn off the LED.

The while loop now is pretty empty.All it is doing is reading the state of the button. In fact, it can be even more empty. Why read the button into a variable then compare that variable if we're not doing anything else with it? Take the following version of the program for example:

if(digitalRead(4)==HIGH) {
  digitalWrite(7,HIGH);
  while(digitalRead(4)==HIGH);
  digitalWrite(7,LOW);
}

That does the exact same thing as the last snippet, but is considerably smaller. You note we have completely discarded the buttonState variable. Also, the while loop has changed somewhat. The { and } have vanished, because there is no longer anything in them. Instead, if you look closely, you will see that the while statement now has a semi-colon on the end. This is exactly the same as having an empty pair of curly brackets. It's like saying "While digitalRead(4) is HIGH, do nothing."

Now, there's two other commands that go with a while loop. These are break and continue. These are ways of skipping bits of the while loop.

If you want to force your way out of a while loop, say you have met all the conditions you need to meet, but not all those conditions are being checked by the while loop itself, or maybe you have detected an error and the while loop should terminate early, you can use the break command. This will just stop the while loop immediately and continue straight after the end of the while loop. Our code snipped could be written like this:

if(digitalRead(4)==HIGH) {
  digitalWrite(7,HIGH);
  while(1) {
    if(digitalRead(4)==LOW) {
      break;
    }
  }
  digitalWrite(7,LOW);
}

It will operate just the same. What we are now saying is:

If the button is pressed, light the LED. Then, repeat the next bit forever. Inside that, we are saying "Has the button been released?" If the answer is yes, then we will terminate our while loop. It's a bit of a convoluted way of writing our button snippet, but it illustrates how break can drop you out of a while loop at any point you choose. None of the commands inside the while loop following the break will be executed.

Along with this is the continue command. This has a similar function to the break command in that no commands inside the while loop will be executed once it has been called. However, instead of breaking out of the while loop to continue with the rest of the program, it jumps back to the start of the while loop. It basically skips all the rest of the commands in the while loop and "continues" with the loop as normal. It can be very useful if you have a lot of code in a while loop and you want some of it to execute nice and fast. Say you have an if at the start of the while loop with some high priority code in it. If the if equates to true, the code will execute. The rest of the while loop will also then have to execute. If you include a continue inside that if then the rest of the while loop will be skipped, giving the if section a chance to execute again. It will be given priority over the rest of the while loop.

It can also be used to speed up the processing of a while loop which has multiple options in it. If you are saying "while this is true, do either this, this, this or that", then after each "this" or "that" you can have a continue. You know that once one of the options has been selected and executed that none of the others should be chosen, so why bother even looking at them? Just skip back to the top of the while loop. Here's an example:

int analogValue;

while(1) {
  analogValue = analogRead(1);

  digitalWrite(2,LOW);
  digitalWrite(3,LOW);
  digitalWrite(4,LOW);
  digitalWrite(5,LOW);

  if(analogValue < 256) {
    digitalWrite(2,HIGH);
    continue;
  }

  if(analogValue < 512) {
    digitalWrite(3,HIGH);
    continue;
  }

  if(analogValue < 768) {
    digitalWrite(4,HIGH);
    continue;
  }

  digitalWrite(5,HIGH);
}

What we're seeing here is an if-elseif-elseif...else construct. We're saying:

  • Do this forever:
    • Read the analog value.
    • Turn off the LEDs.
    • Is the analog value less than 256?
    • Yes: Turn on the first LED and go back to the start.
    • Is the analog value less than 512?
    • Yes: Turn on the second LED and go back to the start.
    • Is the analog value less than 768?
    • Yes: Turn on the third LED and go back to the start.
    • If I have got here, then all the previous if statements must have failed, so turn on the top LED.

So, in summary, the main thing to remember with a while loop is:

Remember to update the values you are comparing inside the while loop.

My Pi 4 Experiences