Using two button loop

Hi, I'm new to the Arduino world an I'm trying to excecute two different loops when a button is pushed.

More precisely what I'm trying to do is that when a button is pushed, a for loop will happen until the other button is pushed or the for condition is met, wichever happens first. As soon as the other button is pushed, the first button's loop will end and that will be the end of the program. The code I have so far is this>


#include <LiquidCrystal.h>

const int pinOn = 10;
const int pinOff = 9;
const int pinledOn = 13;
const int pinledOff = 8;

LiquidCrystal lcd(12,11,5,4,3,2);

int estaon = 0;
int estaoff = 0;

int inicioOn = 0;
int inicioOff = 0;

int switchVar = 0;
 
void setup() {
  Serial.begin (9600);

  pinMode(pinOn, INPUT);
  pinMode(pinOff, INPUT);

  pinMode(pinledOn, OUTPUT);
  pinMode(pinledOff, OUTPUT);
  lcd.begin(16,2);
}

void Encendido (){
  for (int contador = 0; contador < 1000; contador++){
    
    digitalWrite(pinledOn, HIGH); // Enciende el LED
    lcd.setCursor(0,0);
    lcd.print("    Filling  ");
    lcd.setCursor(0,0);
    lcd.setCursor(0,1);	
    lcd.print("               ");
    lcd.setCursor(0,1);  
    delay(10000);
    digitalWrite(pinledOn, LOW);  
    lcd.setCursor(0,0);	
    lcd.print("  Bottle Ready");	
    lcd.setCursor(0,0);
    lcd.setCursor(0,1);	
    lcd.print("Cantidad: "+String(contador+1));	
    lcd.setCursor(0,1);
    delay(10000);  
  }
    
}

void Apagado() {
  digitalWrite(pinledOff, HIGH);
  digitalWrite(pinledOn, LOW); 
  lcd.setCursor(0,0);
  lcd.print("      Bye     ");
  lcd.setCursor(0,0);
  lcd.setCursor(0,1);
  lcd.print("     OFF    ");
  lcd.setCursor(0,1);
}

void loop() {
  estaon = digitalRead(pinOn);
  estaoff = digitalRead(pinOff);
 
  // WAS THE ON BUTTON PUSHED?
  	if (estaon == LOW && inicioOn == HIGH) {
    	switchVar = 1;

    }
  
  // WAS THE OFF BUTTON PUSHED?
  	else if (estaoff == LOW && inicioOff == HIGH) {
    	switchVar = 2;
    
  	}
inicioOn = estaon;  
inicioOff = estaoff;
  
  	switch (switchVar)
  	{
    	case 1:
    		Encendido ();
    		break;

   		case 2:
    		Apagado ();
    		break;
  	}
}

So far, when I press the On button, the loop works fine; but when I press the Off button the On loops keeps going and its supposed to end and show a Bye message. Any tips?

Just a hint - create a "state machine":
Your buttons pressed just sets a state. In a single loop you check all the possible state combinations and do what you want to do.

Simplified example (symbolic, not usable code):

int state = 0;          //have previous and current state bits in it: bit 7..4 = previous, bit 3..0 = current

loop() {
  if (Button0Pressed())
      state |= 0x1;           //set state bit 0
  else
     state  &= ~0x1;       //clear state bit 0
  if (Button1Pressed())
     state |= 0x2;
  else
    state &= ~0x2;

  switch (state) {
    case 0x00 : //nothing pressed, and nothing before
                        ...
                        break;
    case 0x01 : //Button0 is pressed now, not Button1
                        ...
                        break;
    case 0x02 : //Button1 is pressed now, not Button0
                        ...
                        break;
    case 0x10 : //Button0 was active before, now released
                        ...
                        break;
    case 0x20 : //Button1 was active before, now released
                        ...
                        break;
    case 0x11 : Button0 is still pressed - but not Button0 (now and before)
                        ...
                        break;
    case 0x22 : Button1 is still pressed - but not Button0
                        ...
                        break;
    case 0x10 : Button0 is released now after it was pressed
                        ...
                        break;
    case 0x20 : Button1 is released now after it was pressed
                        ...
                        break;
    case 0x03 : 
                         ... //add all the other combinations, e.g. both buttons pressed, released ...
    case 0x30 :
                         ... //just to make it complete
                         //or use "fallthrough" on some combinations, to reuse existing code
    case ... :
  }

  //update previous state:
  state &= ~0xF0;
  state |= (state << 4);      //we use bit 7..4 as previous, bit 0..3 is current

  delay(1000);                    //just to illustrate that previous and current state should not be
                                           //identical so quickly, we wait for 1 second "press interval"
}

Think in states and program a state machine..., here actually just decoding all combinatoric states possible.

You have to be patient. 20000 seconds is about 5.5 hours.

You can make it more responsive by checking the button within the for loop and exit prematurely.

That might take 20 seconds.

Or for "instant response" you can redo that function, and the other, using the technique of an FSM or "finite state machine".

Start with a visit with you friend google to

  arduino two things at once

and

  arduino blink without delay

for a start.

a7

consider to make things a little simpler

void loop() {
    if (LOW == digitalRead(pinOn) && switchVar)
        switchVar != swtichVar;
    if (LOW == digitalRead(pinOff) && ! switchVar)
        switchVar != swtichVar;

    if (switchVar)
        Encendido ();
    else
        Apagado ();
}

It would be just that tiniest iota clearer if both toggles were just assignments… the value is known to be true or false at the point each executes.

a7

Try this and then convert it into "Blink without delay" approach:

void setup()
{
  Serial.begin(9600);
  pinMode(13, OUTPUT);
  pinMode(8, INPUT_PULLUP);
  pinMode(9, INPUT_PULLUP);
}

void loop()
{
  if (digitalRead(8) == LOW)
  {
    for (int i = 0; i < 5; i++)
    {
      digitalWrite(13, HIGH);
      delay(200);
      if (digitalRead(9) == LOW)
      {
        break;
      }
      digitalWrite(13, LOW);
      delay(200);
      if (digitalRead(9) == LOW)
      {
        break;
      }
    }
    Serial.println("Bye");
    while (1);
  }
}

1. Upload the above sketch. Connect a jumper at DPin-8 (pinOn). Gently, touch the other end of the jumper with GND-pin. Check that L (built-in LED connected at DPin-13) blinks for 5 times at 200 ms interval. At the end "Bye" message will appear on the Serial Monitor.

2. Connect a jumper at DPin-9 (pinOff). Press RESET Button of the UNO. Start the blinking of L by touching the open end of DPin-8 jumper. At the end-of-2/3 blinks, gently touch the other end of DPin-9 jumper with GND-pin. Check that L is not blinking and the message "Bye" has appeared on Serial Monitor

Kindly post systematic Circuit Diagram

Sure, I think maybe the circuit view would be better.

The idea of the circuit is to work as a simulation for a filling machine, I'm working it right now on TinkerCAD, this is the circuit I have:

So, when you press the left push button, the circuit will let the fluid pass for 10 seconds, then it will stop for 10 seconds while the operator changes the bottle and then starts again until the right button is pressed. So far I've managed to make the first button work, but it doesn't read the Off input. I think its beacuse of the Delay that consumes all the proccesor.

I know it is. :wink:

If I am reading it correctly, this:

  for (int contador = 0; contador < 1000; contador++){

launches a process of 10 second filling and 10 second bottle changing periods numbering… 1000.

Without a glance at any buttons. That's 5.5 hours, lotsa bottles and prolly not what you meant.

You have to change it up entirely or at least look at the button within that loop to see if breaking out of the loop is called for (button presst, I guess).

a7

Yeah, originally I wasn't using the for loop. At the end, the contador variable is just to show on screen how many bottles have been filled up, but that can be achieved without the for. But still without the for it's still not reading the Off input.

Post in a new response the full code as you are talking about. Not gonna guess and try to keep my version consistent with yours.

You do know that it still means (if I at all understand you) that the button will be ignored for the 20 seconds a loop-less bottle fill and exchange process is coded to take… you may want to start thinking about coding this in a better manner as has been variously suggested above.

TIA

a7

Con todas estas banderas con igual sentido, pienso que no has fijado en las estados de tu machina.

en ves de....

mejor como dijo @tjaekel que haces principalmente una machina estatal.

hay el estado principal al aplicar poder.

Hay el estado al empujar buton 1.

Si tocas buton 2, regressa al pincipal o toma nuevo estado?

Si cumples el cyclo, regressa al principal o toma nuevo estao?

Entonces, son dos estados, tres estados o quatro estados?

@Perehama my Spanish isn't what it ever was, but the code speaks clearly.

It is two buttons and history for two buttons in order to recognize two buttons that change state between just two values.

So the program does nothing (state is 0) until a button is pressed, then will forever more be in state 1 or state 2 depending on the last button presst.

I had to hack it a bit to save time wiring it up. You play with it here:

I used simpler functions to demonstrate the flow. If you have 5.5 hours, you can test it with the real functions which are in there still, just edit appropriately.

a7

@alto777 I only reply in Spanish to keep mine up. I was posing the question to @luismp as to the states, because it wasn't clear to me from the OP code or initial description. The code shared overly complicates things (this is a really simple program) and has a lot of global flags with similar semantics. This suggests to me that the OP hasn't thought through the states of the machine.

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