Problem using While Loops inside Switch Statement

Hi there,

I wonder if anyone will be able to help me with a problem I'm having. I'm relatively new to using an Arduino and its programming environment and I've come face-to-face with an issue that I can't seem to find a resolution for.

Essentially, I'm doing a project involving two seven-segment displays and a VL53L0X range sensor. My goal is to be able to take a reading from the sensor when a button is pressed - this much I've achieved. I then want to output to both seven-segment displays the reading taken in cm.

I've succeeded in taking a reading with the press of the button and outputting these readings to the serial monitor. I'm able to multiplex the displays to show values with two digits...however I haven't been able to keep these values visible on the screens by using some kind of loop within my program.

I've been able to make it work for one value only (i.e. when the sensor reads 20mm) where a loop has been entered and this number appears across both displays - the only issue is I cannot seem to break out of this loop once I've entered it!

I've tried many different things; do-while loops inside a switch statement, individual while loops, breaks, nothing seems to be working!

I've attached my working code below...this is the bare-bones of what I have. This program takes a reading from the sensor when a button is pressed, converts it from mm to cm, and outputs that to the serial monitor as expected.

Any guidance will be greatly appreciated!

Thank you

#include <Wire.h>
#include <VL53L0X.h>

VL53L0X sensor;

int distanceReading;
int button = 12;
int timer = 500;

void setup()
{
pinMode(button, INPUT);
pinMode(2, OUTPUT); //output A
pinMode(3, OUTPUT); //output B
pinMode(4, OUTPUT); //output C
pinMode(5, OUTPUT); //output D
pinMode(6, OUTPUT); //output E
pinMode(7, OUTPUT); //output F
pinMode(8, OUTPUT); //output G
pinMode(9, OUTPUT); //output display 1
pinMode(11, OUTPUT); //output display 2
Serial.begin(9600);
Wire.begin();

sensor.setTimeout(500);
if (!sensor.init())
{
Serial.println("Failed to detect and initialize sensor!");
while (1) {}
}
digitalWrite(2, HIGH);
digitalWrite(3, HIGH);
digitalWrite(4, HIGH);
digitalWrite(5, HIGH);
digitalWrite(6, HIGH);
digitalWrite(7, HIGH);
digitalWrite(8, HIGH);
}
void loop()
{
if (digitalRead(button) == HIGH)
{
distanceReading = sensor.readRangeSingleMillimeters();
if (distanceReading >= 500)
{
Serial.println("Object is too far, please move closer");
delay(200);
}
else
{
int distance_cm = distanceReading / 10;
Serial.print(distance_cm); Serial.println("cm");
delay(200);
}
}
}

test_project.ino (1.67 KB)

I don't see a switch statement, but it could be something like this :

switch( number ) {

  case 1 : {
    // do something (even a while loop if you must);
  }
  break ;

  case 2 : {
    // do something ;
  }
  break ;

}

It is hard to help you because I see no switch statements or while loops in your code. Can you better explain what you want to do?

Hi,
Welcome to the forum.

Please read the post at the start of any forum , entitled "How to use this Forum".
OR
http://forum.arduino.cc/index.php/topic,148850.0.html.
Then look down to item #7 about how to post your code.
It will be formatted in a scrolling window that makes it easier to read.

Can you please post a copy of your circuit, in CAD or a picture of a hand drawn circuit in jpg, png?

Thanks.. Tom.. :slight_smile:

Hi everyone,

Thank you so much for your responses! I really appreciate the help. I'll upload my trial code today when I can get to my computer. So far, I have tried to use while statements within a switch statement...I understand it's hard to know what issues I'm having without seeing the full code :confused:

I'll have another quick look at it and i'll upload it here. Thanks again!

Taylor

In general it is not a good idea to use while loops if you want to write responsive code. As you are already using switch/case, it may be better to use if instead of while and when the condition becomes true then move to a different case to react to the change

That way the loop() function can run freely and execute code outside of the switch/case if required. Seeing your code will help decide whether this method is appropriate for what you want to do

Hi everyone,

Here's my code so far:

#include <Wire.h>
#include <VL53L0X.h>

VL53L0X sensor;

int distanceReading;
int button = 12;
int timer = 500;

void setup()
{
  pinMode(button, INPUT);
  pinMode(2, OUTPUT); //output A
  pinMode(3, OUTPUT); //output B
  pinMode(4, OUTPUT); //output C
  pinMode(5, OUTPUT); //output D
  pinMode(6, OUTPUT); //output E
  pinMode(7, OUTPUT); //output F
  pinMode(8, OUTPUT); //output G
  pinMode(9, OUTPUT); //output display 1
  pinMode(11, OUTPUT); //output display 2
  Serial.begin(9600);
  Wire.begin();

  sensor.setTimeout(500);
  if (!sensor.init())
  {
    Serial.println("Failed to detect and initialize sensor!");
    while (1) {}
  }
  digitalWrite(2, HIGH);
  digitalWrite(3, HIGH);
  digitalWrite(4, HIGH);
  digitalWrite(5, HIGH);
  digitalWrite(6, HIGH);
  digitalWrite(7, HIGH);
  digitalWrite(8, HIGH);
}

void loop() {
  int buttonState = 0; 
  buttonState = digitalRead(button); 
  
  if (buttonState == HIGH) {
    distanceReading = sensor.readRangeSingleMillimeters();
    int distance_cm = distanceReading/10;
    if (distance_cm <= 50) {
    Serial.print(distance_cm); Serial.println("cm");
    } 
    switch(distance_cm) {
      case 2: {
        while (true) {
          digitalWrite(2, LOW);
          digitalWrite(3, LOW);
          digitalWrite(4, LOW);
          digitalWrite(5, LOW);
          digitalWrite(6, LOW); //Zero (Seven Segment 1)
          digitalWrite(7, LOW);
          digitalWrite(8, HIGH);
          digitalWrite(9, LOW);
          digitalWrite(11, HIGH);
          delay(5);
          digitalWrite(2, LOW);
          digitalWrite(3, LOW);
          digitalWrite(4, HIGH);
          digitalWrite(5, LOW);
          digitalWrite(6, LOW); //Two (Seven Segment 2)
          digitalWrite(7, HIGH);
          digitalWrite(8, LOW);
          digitalWrite(9, HIGH);
          digitalWrite(11, LOW);
          delay(5);
          if (buttonState == HIGH) {
            break;
            }           
          }
       }        
     }
    delay(200);
  }
 
}

I haven't put every case in because I want to make sure I can get one case working as intended.

Essentially I'm trying to make it so when a button is pressed and released in quick succession, a reading will be taken from the sensor. This value will then be outputted to the seven segment displays which are multiplexed.
I want to make it so this value STAYS on the screens after the button has been released. When the button is then pressed and released again, I want it so the multiplex loop stops, a new reading is taken, and that value is outputted to the screen (if this makes any sense).
If anyone has a better idea of how to implement this, I am all-ears! The switch statement with loops inside was my initial instinct, but I am having no luck whatsoever.

         while (true)
          {
            digitalWrite(2, LOW);
            digitalWrite(3, LOW);
            digitalWrite(4, LOW);
            digitalWrite(5, LOW);
            digitalWrite(6, LOW); //Zero (Seven Segment 1)
            digitalWrite(7, LOW);
            digitalWrite(8, HIGH);
            digitalWrite(9, LOW);
            digitalWrite(11, HIGH);
            delay(5);
            digitalWrite(2, LOW);
            digitalWrite(3, LOW);
            digitalWrite(4, HIGH);
            digitalWrite(5, LOW);
            digitalWrite(6, LOW); //Two (Seven Segment 2)
            digitalWrite(7, HIGH);
            digitalWrite(8, LOW);
            digitalWrite(9, HIGH);
            digitalWrite(11, LOW);
            delay(5);
            if (buttonState == HIGH)
            {
              break;
            }
          }

How will buttonState ever change once the code is in this while loop ?

Also, there's really no reason to entangle the two - the display piece doesn't care about buttons and how the range was read. It just needs to know what it is and it can get on with displaying it.

Split them out and then dump the while - let the loop function do the looping.

That delay(200) is going to have to go though.

Hi there,

would you mind explaining how I may be able to do this?

The output on the screens will change dependant on the value acquired by the sensor. If the sensor value is 3cm for instance, the screens will need to display '0' and '3' through multiplexing. I guess i'm confused as to how I can keep this figure across the screens in between button presses and how I may be able to write the code for each scenario or each possible value from the sensor.

taylorcameronee:
Essentially I'm trying to make it so when a button is pressed and released in quick succession, a reading will be taken from the sensor. This value will then be outputted to the seven segment displays which are multiplexed.
I want to make it so this value STAYS on the screens after the button has been released. When the button is then pressed and released again, I want it so the multiplex loop stops, a new reading is taken, and that value is outputted to the screen (if this makes any sense).
If anyone has a better idea of how to implement this, I am all-ears! The switch statement with loops inside was my initial instinct, but I am having no luck whatsoever.

I have a couple of questions about this description because I'm nit sure I understand it:

  1. "pressed and released in quick succession" does not define what "quick" is.
  2. What is the "multiplex loop"?
  3. "I want it so the multiplex loop stops, a new reading is taken, and that value is outputted to the screen" is this different from the operation defined in the first 3 sentences?

I'm trying to figure out if you are using one button to perform 2 different operations. Also, I'm trying to figure out if it would suffice to simply determine if the button has been depressed rather than detect off-on-off sequence.

taylorcameronee:
Hi there,

would you mind explaining how I may be able to do this?

The output on the screens will change dependant on the value acquired by the sensor. If the sensor value is 3cm for instance, the screens will need to display '0' and '3' through multiplexing. I guess i'm confused as to how I can keep this figure across the screens in between button presses and how I may be able to write the code for each scenario or each possible value from the sensor.

I believe you need to detect when the button state CHANGES rather than the actual STATE of the button.

Check out this tutorial:

StateChangeDetection

It sounds like you need to spend more time with the basic operations. Break the project into parts and make sure you understand each one before merging the pieces.

Learn how to display any number.
Learn how to read the sensor.
Learn how to read the sensor and display the result.
Modify the above to change the display ONLY when the result changes.
Learn how to read buttons, then add that to the previous program.

ToddL1962:
I have a couple of questions about this description because I'm nit sure I understand it:

  1. "pressed and released in quick succession" does not define what "quick" is.
  2. What is the "multiplex loop"?
  3. "I want it so the multiplex loop stops, a new reading is taken, and that value is outputted to the screen" is this different from the operation defined in the first 3 sentences?

I'm trying to figure out if you are using one button to perform 2 different operations. Also, I'm trying to figure out if it would suffice to simply determine if the button has been depressed rather than detect off-on-off sequence.

Hi Todd,
Apologies if I haven't been clear.

  1. By 'pressed and released in quick succession', I mean a single button press with no holding, so I'd assume the state would be HIGH for less than a second.
  2. The multiplex loop is what I need to construct in order to have two figures displayed across two different screens. My explanation in this regard may be quite weak. I need the screens to remain multiplexing even after the button state has changed from HIGH to LOW. only when the button is pressed again will the sensor take a new reading which will break that loop to start another loop depending on the value obtained.
    I've seen you've provided a link on state change detection; thank you very much for this. I'll investigate this further.
    Once again, thanks for your continued support!

You need to write a state machine to handle the button presses,
and a separate state machine to update the multiplexed display.

You then call the update function for both state machines from loop() and
never use delay().

The code can be entirely separate then, as updating a state machine should be
a quick series of checks for any transition that needs to happen, then return to
loop() to let the rest of the code progress.

By 'pressed and released in quick succession', I mean a single button press with no holding, so I'd assume the state would be HIGH for less than a second.

What should happen if the button is held down and not released ?

MarkT:
You need to write a state machine to handle the button presses,
and a separate state machine to update the multiplexed display.

You then call the update function for both state machines from loop() and
never use delay().

The code can be entirely separate then, as updating a state machine should be
a quick series of checks for any transition that needs to happen, then return to
loop() to let the rest of the code progress.

Hi Mark,
Thank you for your response. This makes sense to me, however I'm having trouble trying to execute what you're saying. Here's my current code with a state machine for the button presses, i'm unsure how to implement one for the displays...would you mind talking me through it?

#include <Wire.h>
#include <VL53L0X.h>

VL53L0X sensor;

int button = 12;
int distanceReading;
int buttonState = 0;
int buttonPushCounter = 0;
int lastButtonState = 0;

void setup()
{
  pinMode(button, INPUT);
  pinMode(2, OUTPUT); //output A
  pinMode(3, OUTPUT); //output B
  pinMode(4, OUTPUT); //output C
  pinMode(5, OUTPUT); //output D
  pinMode(6, OUTPUT); //output E
  pinMode(7, OUTPUT); //output F
  pinMode(8, OUTPUT); //output G
  pinMode(9, OUTPUT); //output display 1
  pinMode(11, OUTPUT); //output display 2
  Serial.begin(9600);
  Wire.begin();

  sensor.setTimeout(500);
  if (!sensor.init())
  {
    Serial.println("Failed to detect and initialize sensor!");
    while (1) {}
  }
  digitalWrite(2, HIGH);
  digitalWrite(3, HIGH);
  digitalWrite(4, HIGH);
  digitalWrite(5, HIGH);
  digitalWrite(6, HIGH);
  digitalWrite(7, HIGH);
  digitalWrite(8, HIGH);
}

void loop() {
  
  buttonState = digitalRead(button); 
  if (buttonState != lastButtonState) {
  
    // if the state has changed, increment the counter
    
    if (buttonState == HIGH) { // if the current state is HIGH then the button went from off to on:
      
      buttonPushCounter++;
      distanceReading = sensor.readRangeSingleMillimeters();
      int distance_cm = distanceReading/10;
      if (distance_cm <= 50) {
      Serial.print(distance_cm); Serial.println("cm"); 
      Serial.println(buttonPushCounter);
    } 
    
    else {
      Serial.println("Out of Range!");
    }
    delay(100);
  }
 lastButtonState = buttonState;
}
}

UKHeliBob:
What should happen if the button is held down and not released ?

Hi there,
Nothing should happen. The change of state of the button from LOW to HIGH should trigger the sensor to take a reading. If the button is held, nothing more should happen. Only when the button is released and pressed again (i.e. the state is changed again from LOW to HIGH) should a new action happen.

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