Code Help using Switch Case and while Loop

I am trying to figure out a bit of code here for a project that I am working on. I am having a user select an item from a list and then after the item is selected, have the user press a button to execute the selected task with a push button

I am having the switch case function call a function that I want to have do something while they press the button. But my problem is how do I create a while loop that will take into account a bit of time for a user delay before they press the button.

The relevant code is as follows:


switch (Selection) {
        case 0: // 
        	PWM = enA;
		Pump = inA;
		Solenoid = sol1;
		Dispense(PWM, Pump, Solenoid)
    	 break;

	case 1: // 
        	PWM = enB;
		Pump = inB;
		Solenoid = sol1;
		Dispense(PWM, Pump, Solenoid)
    	 break;
}

void Dispense(int PWM, int Pump, int Solenoid) {
	ButtonState = digitalRead(ButtonPin);	
	while (ButtonState == Low) {
    		analogWrite(PWM,255); // turn on pwm control for pump
		digitalWrite(Pump,HIGH); // turn on pump
		digitalWrite(Solinoid,HIGH); // turn on Solenoid
		ButtonState = digitalRead(ButtonPin);	
	}
}

Welcome to the forum.
Could you please post your entire code and not just the snippet?

What exactly do you mean by:

Do you want to have the program wait for user input?
How are you getting user input?

How is that accomplished? Serial input?

It would be better if we could see your entire sketch.

You don’t have to wait for input you just check regularly and remember the current state. Ie state = waiting check for user input
Input received, state = do whatever
Once whatever is done state = waiting again

Think loop

Here you go. It is rather a large program... Hopefully the formatting stays correct. yes I also know that there are various serial commands that are currently in the code that Ive been using to double check for debugging etc

/*
Soda-Pop Dispenser Machine V 1.3

By:
Geoffrey Andreychuk

July 15th, 2022

*/

// Including additional required libraries:

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



EncoderButton eb1(2, 3, 4); // Declaring the Rotary Encoder & Button along with the Assigned Pins used Encoder+button: EncoderButton(byte encoderPin1, byte encoderPin2, byte switchPin);

LiquidCrystal_I2C lcd(0x27, 20, 4);  // set the LCD address to 0x27 for a 20 chars and 4 line display


int ButtonPin = 33;
int ButtonState = High
int DrinkPointer = 0;       // a variable to point to the current position in the Drink List
int TotalNumDrink = 10;     // variable to hold the value of Drink Options
int DrinkSelection = -1;    // variable to point to the users selected drink option to make the drink
bool IsClicked = false;     // to see if a selection has been made
int Increment;              // variable to hold a + for CW  and - for a CCW turn of Rotary Encoder

unsigned long IdleTime = 25000;       // a timer fuction to be used to clear any selected options and return program to main selection screen
unsigned long EventInterval = 5000;
unsigned long PreviousTime = 0;
unsigned long CurrentTime;

char *DrinkChoices[] = {"Dr. Pepper", "Grape Crush", "Orange Crush", "Cream Soda", "Iced Tea", "Coke", "Diet Coke", "Root Beer", "Sprite", "Soda Water"};

//Pump A
#define enA 5
#define in1 22

//Pump B
#define enB 6
#define in2 23

//Pump C
#define enC 7
#define in3 24

//Pump D
#define enD 8
#define in4 25

//Pump E
#define enE 9
#define in5 26

//Pump F
#define enF 10
#define in6 27

//Pump G
#define enG 11
#define in7 28

//Pump H
#define enH 12
#define in8 29

//Relays to control Solenoid Valves 1-3
#define Sol1 30
#define Sol2 31
#define Sol3 32

//Set all pump and Solenoid pins to outputs

pinMode(enA, OUTPUT);
pinMode(enB, OUTPUT);
pinMode(enC, OUTPUT);
pinMode(enD, OUTPUT);
pinMode(enE, OUTPUT);
pinMode(enF, OUTPUT);
pinMode(enG, OUTPUT);
pinMode(enH, OUTPUT);
pinMode(in1, OUTPUT);
pinMode(in2, OUTPUT);
pinMode(in3, OUTPUT);
pinMode(in4, OUTPUT);
pinMode(in5, OUTPUT);
pinMode(in6, OUTPUT);
pinMode(in7, OUTPUT);
pinMode(in8, OUTPUT);
pinMode(Sol1, OUTPUT);
pinMode(Sol2, OUTPUT);
pinMode(Sol3, OUTPUT);
pinMode(ButtonPin, INPUT_PULLUP)

void setup() 
{
  Serial.begin(9600);
  lcd.init();  // initialize the display
  lcd.backlight();
  IdleMenu();

  //Link the event(s) to your function
  eb1.setClickHandler(onEb1Clicked);
  eb1.setEncoderHandler(onEb1Encoder);
}

void IdleMenu()  // Prints the idle screen message to the display
{
  lcd.clear();
  lcd.setCursor(0, 0);  // Sets the cursor to column 4, line 0, since counting begins with row 0
  lcd.print("Drink Selection Menu");
  // set the cursor to  line 1 which  is the second row
  lcd.setCursor(2, 1);
  lcd.print("Rotate Knob Left");  // print to the second line
  lcd.setCursor(2, 2);
  lcd.print("or Right & Press");  // print to the fourth line
  lcd.setCursor(0, 3);
  lcd.print("to make Selection!!");
}

void SelectionMenu() 
{
  lcd.clear();
  lcd.setCursor(0, 0);
  lcd.print("<-----------------");
  lcd.setCursor(3, 1);
  lcd.print(DrinkChoices[DrinkPointer]);
  lcd.setCursor(3, 2);
  lcd.print("---------------->");
  lcd.setCursor(0, 3);
  lcd.print("Press knob to Select");
};


 //A function to handle the 'encoder' event
void onEb1Encoder(EncoderButton& eb) 
{
  Serial.print("eb1 incremented by: ");
  Serial.println(eb.increment());
  Serial.print("eb1 position is: ");
  Serial.println(eb.position());
  Serial.println("Increment is: ");
  Serial.println(Increment);
  Serial.println("DrinkPointer position: ");
  Serial.println(DrinkPointer);
}


void UpdatePointer()
 {
  Increment = (eb1.position());
  Serial.println("----------------");
  Serial.println("Position is: ");
  Serial.println(eb1.position());
  eb1.resetPosition();
  DrinkPointer = DrinkPointer + Increment;  
  Serial.println("DrinkPointer position: ");
  Serial.println(DrinkPointer);
  if (DrinkPointer = (TotalNumDrink - 1)) 
  {
    DrinkPointer = 0;
    return;
  }
  if (DrinkPointer = 0) 
  {
    DrinkPointer = (TotalNumDrink - 1);
    return;
  }
}

     
void PlaceGlass() // Function to tell the user which side to place glass
{
    // cleans up the screen before letting user know where to put glass
    Serial.print("Is Clicked: ");
    Serial.println(IsClicked);
    Serial.print("Drink Selection is: ")
    Serial.println(DrinkChoices[DrinkSelection]);
    lcd.clear();
    lcd.setCursor(0, 0);
    lcd.println("Place Glass");
    lcd.setCursor(5, 1);
    if (DrinkSelection <= 0 && DrinkSelection < 6)  
    {
       lcd.println("Right ------->");
    }	
    If (DrinkSelection >= 6 && DrinkSelection < 10) 
    {
       lcd.println("<-------- Left");
  }
  lcd.setCursor(2,2); 
  lcd.println("Press & Hold Button");	
  lcd.setCursor(1,3); 
  lcd.println("to dispense Pop");
}

void Dispense(int PWM, int Pump, int Solenoid) 
{
  ButtonState = digitalRead(ButtonPin);	
  while (ButtonState == Low) {
  analogWrite(PWM,255); // turn on pwm control for pump
  digitalWrite(Pump,HIGH); // turn on pump
  digitalWrite(Solenoid,HIGH); // turn on Solenoid
  ButtonState = digitalRead(ButtonPin);	
}

void loop() 
{
  eb1.update();
  CurrentTime = millis();
  if ((CurrentTime - PreviousTime) >= IdleTime)
  {
    IdleMenu();
    PreviousTime = CurrentTime;
  }
  if ((CurrentTime - PreviousTime >= EventInterval) && (eb1.position() != 0))
 { 
    SelectionMenu();
    UpdatePointer();
    PreviousTime = CurrentTime;
  };
  if ((eb1.isPressed()) == true) && ((IsClicked) == false) 
  {
    IsClicked = true; // to ensure selection is held till timout value is reached then reset
    DrinkSelection = DrinkPointer; // to ensure that the selected drink is not changed till either drink is poured or idle timer timeout is reached
    PlaceGlass();

switch (DrinkSelection)
{
  case 0: // Selection Dr. Pepper
  PWM = enA;
  Pump = inA;
  Solenoid = sol1;
  Dispense(PWM, Pump, Solenoid)
break;

case 1: // Selection Grape Crush
  PWM = enB
  Pump = inB;
  Solenoid = sol1;
  Dispense(PWM, Pump, Solenoid)
 break;

case 2: // Selection Orange Crush
  PWM = enC;
  Pump = inC;
  Solenoid = sol1;
  Dispense(PWM, Pump, Solenoid)
break;

case 3: // Selection Cream Soda
  PWM = enD;
  Pump = inD;
  Solenoid = sol1;
  Dispense(PWM, Pump, Solenoid)
break;

Case 4: // Selection Iced Tea
  PWM = 0
  Pump = 0;
  Solenoid = soL3;
  Dispense(PWM, Pump, Solenoid)
break;

case 5: // Selection Soda Water
  PWM = 0;
  Pump = 0;
  Solenoid = sol1;
  Dispense(PWM, Pump, Solenoid)
 break;

case 6: // Selection Coke
  PWM = enE;
  Pump = inE;
  Solenoid = sol2;
  Dispense(PWM, Pump, Solenoid)
break;

case 7: // Selection Diet Coke
  PWM = enF;
  Pump = inF;
  Solenoid = sol2;
  Dispense(PWM, Pump, Solenoid)
break;

case 8: // Selection Sprite
 PWM = enG;
  Pump = inG;
  Solenoid = sol2;
  Dispense(PWM, Pump, Solenoid)
break;

 case 9: // Selection Root Beer
  PWM = enH;
  Pump = inH;
  Solenoid = sol1;
  Dispense(PWM, Pump, Solenoid)
break;
}

/*To ensure that nothing is accidently dispensed till a  new drink selection is made by the next user and return the system back to an idle state */

  IsClicked = false;
DrinkSelection = -1
  PWM = 0;
  Pump = 0;
  aSolinoid = 0;
  };

};


I kinda do, cuz of already obtaining user input previously, I have uploaded the complete code to try and help make it easier to follow exactly what I am trying to do

I have copied my entire code.. Hopefully that helps clear things up as to what I am trying to do etc

These statements should probably be using ==

Thanks for copying the entire code.

Firstly, you have numerous simple errors in the code. I'm posting the corrected versions of the first few that I found. Please go through you code with a fine tooth comb, correct it and re-post it.

int ButtonState = High //yours
int ButtonState = HIGH; // new ver

pinMode(ButtonPin, INPUT_PULLUP)
pinMode(ButtonPin, INPUT_PULLUP);

All of the pinMode statements need to be in setup()

  eb1.setClickHandler(onEb1Clicked);//  I think onEb1Clicked is not correct

After you have made the corrections, found all missing semi-colons, etc, do try to run the code and let us know exactly what problems you are having. Don't forget to re-post the updated code

thank you for your help with that, but going back to the original question, it is regarding the while loop that I have the problem. I am trying to figure out how to incorporate a delay till while loop until after the user has pressed the button to dispense their drink. the only way that really comes to mind is to nest two while loops, the first one until the user presses the button which just keeps checking to see if the button is pressed yet, and then once pressed run the code that I have currently written, and then break out of the loop/function when done.

However that would be very dirty programing/code. I can just hear my old computer programing teacher yelling at me for just thinking of writing code like that.

So, if I understand correctly, you would like the program to do nothing until the user presses a button?

Here is some pseudo-code for you to think about:
In loop()
read button pin
if button pin is pressed, call a drink dispenser function:
everything from PlaceGlass() onwards that is currently in loop() would be in its own function

Hi,

if button is not pressed then call the default case ( do nothing and display "select option then press button") and go round the loop again

Tom.... :smiley: :+1: :coffee: :australia:

1 Like

I suspect that you're approaching this the wrong way. Looking at all the errors in your code (as indicated by @cncnotes) I think that you're writing ALL the code first and next start debugging. This is the wrong approach.

Write small pieces in separate sketches providing functionality and test them; later integrate into the final program.

3 Likes

I suspect you are wrong. You appear to be thinking linearly when the uC thinks loop. The uC can remember as many previous user inputs as you like and branch into multiple options. Forcing a linear program is likely to be problematic

Waiting for buttonPush is just another state

It is LOW, case matters in C++

It looks like you're using a pin number of zero to mean No Pin but you didn't implement that in Dispense(). Try this:

void Dispense(int PWM, int Pump, int Solenoid) 
{
  while (digitalRead(ButtonPin) == LOW) 
  {
    if (PWM != 0)
      analogWrite(PWM, 255); // turn on pwm control for pump

  if (Pump != 0)
    digitalWrite(Pump, HIGH); // turn on pump

  if (Solenoid != 0)
    digitalWrite(Solenoid, HIGH); // turn on Solenoid
  }
}

I originally declared everything as global variables, and was going to slowly change many over to local, and as such had not gotten around to that yet. For the time being I am keeping everything as global variables.

Currently have the program almost working properly. I have the function coded however it is not working as expected within the context of sketch. For some reason I am getting stuck in the loop, however that only occurs if I run the whole sketch. If I take the code from just that function in question(which is just a while loop essentially), and put that code into a new sketch within the loop function along with the variables and values that I use placed accordingly except for the rotary encoder and lcd screen, the code works as expected.

Here is the current code for this project

 /*
Soda-Pop Dispenser Machine V 1.8

By:
Geoffrey Andreychuk

July 30th, 2022

*/

// Including additional required libraries:

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



EncoderButton eb1(2, 3, 4); // Declaring the Rotary Encoder & Button along with the Assigned Pins used Encoder+button: EncoderButton(byte encoderPin1, byte encoderPin2, byte switchPin);

LiquidCrystal_I2C lcd(0x27, 20, 4);  // set the LCD address to 0x27 for a 20 chars and 4 line display


int ButtonPin = 7; // pin that the push button is assigned to to dispense the drink
int ButtonState = 1; // the state of the button that the user presses to dispense drink
int Solenoid = 0;  // soleenoid to open the valve to dispence beverage
int Pump = 0; // to turn on or off the pump to dispense syrup
bool IsClicked = false;


int DrinkPointer = 5;       // a variable to point to the current position in the Drink List
int TotalNumDrink = 10;     // variable to hold the value of Drink Options
int DrinkSelection = 0;    // variable to point to the users selected drink option to make the drink
int Increment;              // variable to hold a + for CW  and - for a CCW turn of Rotary Encoder

unsigned long IdleTime = 15000;       // a timer fuction to be used to clear any selected options and return program to main selection screen
unsigned long EventInterval = 12000;
unsigned long PreviousTime = 0;
unsigned long CurrentTime;

char *DrinkChoices[] = {"0.", " Dr. Pepper", "Grape Crush", "Orange Crush", "Cream Soda", " Iced Tea", "Soda Water", "   Coke", "Diet Coke", "Root Beer", "  Sprite"};  


void setup() 
{

//Pump A
#define inA 22

//Pump B
#define inB 23

//Pump C
#define inC 24

//Pump D
#define inD 25

//Pump E
#define inE 26

//Pump F
#define inF 27

//Pump G
#define inG 28

//Pump H
#define inH 29

//Relays to control Solenoid Valves 13
#define Sol1 32
#define Sol2 33
#define Sol3 34
 
  //Set all pump and Solenoid pins to outputs
  pinMode(inA, OUTPUT);
  pinMode(inB, OUTPUT);
  pinMode(inC, OUTPUT);
  pinMode(inD, OUTPUT);
  pinMode(inE, OUTPUT);
  pinMode(inF, OUTPUT);
  pinMode(inG, OUTPUT);
  pinMode(inH, OUTPUT);
  pinMode(Sol1, OUTPUT);
  pinMode(Sol2, OUTPUT);
  pinMode(Sol3, OUTPUT);
//Sets button pin as input  
  pinMode(ButtonPin, INPUT_PULLUP);

  
  Serial.begin(9600);
  lcd.init();  // initialize the display
  lcd.backlight();
  IdleMenu();

  //Link the event(s) to your function
  eb1.setClickHandler(onEb1Clicked);
  eb1.setEncoderHandler(onEb1Encoder);
  eb1.setIdleHandler(onEb1Idle);
  CurrentTime = millis ();
}

void onEb1Encoder(EncoderButton& eb) 
{
}

void ResetorIdle()
{
  IsClicked = false;
  DrinkSelection = 4; // To ensure that nothing is accidently dispensed till a selection is actually made
  Pump = 0; // Sets the enable pin for the previously selected pump to null
  Solenoid = 0; // Sets the previously selected solenoid valve back to null
}


void onEb1Clicked(EncoderButton& eb) 
{ 
  DrinkSelection = DrinkPointer;  // to ensure that the selected drink is not changed till either drink is poured or idle timer timeout is reached
  IsClicked = true;
  PlaceGlass();
  PourDrink();
  ResetorIdle();
}

void onEb1Idle(EncoderButton& eb)
{
//  ResetorIdle();
//  IdleMenu();
}

void IdleMenu()  // Prints the idle screen message to the display
{
  lcd.clear();
  lcd.setCursor(0, 0);  // Sets the cursor to the first row
  lcd.print("Drink Selection Menu");  // set the cursor to  line 1 which  is the second row
  lcd.setCursor(2, 1);
  lcd.print("Rotate Knob Left");  // print to the second line
  lcd.setCursor(2, 2);
  lcd.print("or Right & Press");  // print to the fourth line
  lcd.setCursor(0, 3);
  lcd.print("to make Selection!!");
}

void SelectionMenu() 
{
  lcd.clear();
  lcd.setCursor(0, 0);
  lcd.print("<-----------------");
  lcd.setCursor(5, 1);
  lcd.print(DrinkChoices[DrinkPointer]);
  lcd.setCursor(3, 2);
  lcd.print("---------------->");
  lcd.setCursor(0, 3);
  lcd.print("Press knob to Select");
}

void UpdatePointer()
{ 
  Increment = (eb1.position());
  DrinkPointer = DrinkPointer + Increment;
  eb1.resetPosition();
  if (DrinkPointer > TotalNumDrink) // Catches a positive increment overturn and wrap around
  {
    DrinkPointer = 1;
    return;
  }
  if (DrinkPointer < 1) // Catches a negative increment overturn and wrap around
  {
    DrinkPointer = TotalNumDrink;
    return;
  }
}

     
void PlaceGlass() // Function to tell the user which side to place glass
{ // cleans up the screen before letting user know where to put glass
  lcd.clear();
  lcd.setCursor(4, 0);
  lcd.print("Place Glass");
  lcd.setCursor(2, 1);
  if (DrinkSelection >= 1 && DrinkSelection <= 7)  
  {
      lcd.print("Right --------->");
  }	
  else if (DrinkSelection > 7 && DrinkSelection <= 10) 
  {
    lcd.print("<---------- Left");
  }
  lcd.setCursor(1,2); 
  lcd.print("Press & Hold Button");	
  lcd.setCursor(0,3); 
  lcd.print("to dispense Pop");
}

void ErrorMessage()
{
  lcd.clear();
  lcd.setCursor(6,0);
  lcd.print("Error!!");
  lcd.setCursor(0,1);
  lcd.print("Invalid Selection");
  lcd.setCursor(0,2);
  lcd.print("Or Out of Syrup");
  lcd.setCursor(2,3);
  lcd.print("Sorry, Not Sorry!!");
}
void PourDrink()
{
  switch (DrinkSelection)
  {
    case 0:
      ErrorMessage();
     break;
    
    case 1: // Selection Dr. Pepper
      Pump = inA;
      Solenoid = Sol1;
      Dispense();
    break;

    case 2: // Selection Grape Crush
      Pump = inB;
      Solenoid = Sol1;
      Dispense();
    break;

    case 3: // Selection Orange Crush
      Pump = inC;
      Solenoid = Sol1;
      Dispense();
    break;

    case 4: // Selection Cream Soda
      Pump = inD;
      Solenoid = Sol1;
      Dispense();
    break;

    case 5: // Selection Iced Tea
      Pump = 0;
      Solenoid = Sol3;
      Dispense();
    break;

    case 6: // Selection Soda Water
      Pump = 0;
      Solenoid = Sol1;
      Dispense();
    break;

    case 7: // Selection Coke
     // Pump = inE;
     // Solenoid = Sol2;
     // Dispense();     
      ErrorMessage();
    break;

    case 8: // Selection Diet Coke
   //   Pump = inF;
   //   Solenoid = Sol2;
   //   Dispense();
      ErrorMessage();
    break;

    case 9: // Selection Sprite
    //  Pump = inG;
    //  Solenoid = Sol2;
    //  Dispense();
      ErrorMessage();
    break;

    case 10: // Selection Root Beer
   //   Pump = inH;
   //  Solenoid = Sol2;
   //   Dispense();
      ErrorMessage();
    break;
  }
}

void Dispense() 
{
  while (IsClicked == true)
  {
    ButtonState = digitalRead(ButtonPin);
    if (ButtonState == 0)
    {
       while (ButtonState == 0)
      {
          digitalWrite(Pump, 1); // turn on pump
        digitalWrite(Solenoid, 1); // turn on Solenoid
        ButtonState = digitalRead(ButtonPin); //This appears to be not getting checked!!!!!!
      } 
      IsClicked = false;
      break;
    }
  }
}

void loop() 
{
  CurrentTime = millis();
  eb1.update();
  if (eb1.position() != 0)
 {
    UpdatePointer();
    SelectionMenu();
    PreviousTime = CurrentTime;
    
  }
  if (CurrentTime - PreviousTime >= IdleTime)
  {
    ResetorIdle();
    IdleMenu();
    PreviousTime = CurrentTime;
  }
}

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