Toggle between two modes or tasks

I have a project, which has two separate "jobs" in the loop code.

One is the "calibration" of the projects constraints

the other is "random movement within the constraints"

i don't THINK i can calibrate within the setup of the sketch

so what i have is "while a button is pressed, its in calibrate, else its in random"
what i want is, press the button to toggle between the two modes

rather than just ask for an answer , i have come up with this plan (which may seem simple/logical/daft to those who know) and was hoping for comment/review

So "integers" are the working part of the "duino

i figure, create an "int" called "toggle"
and then create a simple "if" loop.

"if int is a 0, and button is pressed, flip it to 1"
"if int is a 1, and button is pressed, flip it to 0"

then just read from this using an if/else over the whole sketch as appropriate.

or have i missed a simpler way of doing it?

1 Like

rather than just ask for an answer , i have come up with this plan (which may seem simple/logical/daft to those who know) and was hoping for comment/review

OK. The approach described is fine. Except that the "if a button is pressed" bit needs work. For how long? Your idea of "the button was pressed" and the Arduino's may be quite different.

It appears that what you really mean is that when the switch is pressed now, but was not before, toggle the value.

It is that "but was not before" bit that is critical. It means that you need to keep track of the previous state of the switch, and compare that to the current state of the switch, to detect when a transition has occurred - from released to pressed or from pressed to released. Note, too, that you want to know which transition occurred, so you don't toggle again when releasing the switch. The current state of the switch will tell you which transition occurred.

I'm thrown.

I was expecting this to be dead simple. (it probably is to be fair)

Ive got rid of the rest of the code for now, and just have 1 switch & 1 LED.

I cant make it toggle!

does anyone have a simple software "flip flop" sketch i can have a look at and try and make sense of?

Thanks

Me.

Depending on how your switch is wired, something like this might work.

int prevState = LOW;
int currState;

byte mode = 0;

void loop()
{
   currState = digitalRead(somePin);
   if(currState != prevState)
   {
      // A transition occurred

      if(currState == HIGH)
         mode = !mode; // Toggle mode
   }
   prevState = currState;

   // Do something with mode
}

If pressed returns LOW (i.e. pullup resistors are being used), change the LOW to HIGH and the HIGH to LOW.

It took some fiddling with (and a period where i had pulled the pin out, to check the switch actually worked, then plugged it into the wrong header :blush:)

but that now works, and it has introduced me to " == and !="

thank-you kindly Paul

I tried the code that PaulS wrote, but I can't get it to work, Paul can you or can someone see where I have gone wrong with this.

const int swPin = 2;
const int ledRd = 9;
const int ledGn = 8;

int prevState = HIGH;
int currState;

byte mode = 0;

void setup() {
  pinMode(swPin, INPUT_PULLUP);
  pinMode(ledGn, OUTPUT);
  pinMode(ledRd, OUTPUT);
}

void loop() {
   int currState = digitalRead(swPin);
   if(currState != prevState)
   
      // A transition occurred

      if(currState == LOW) {
         mode = !mode; // Toggle mode
   
   prevState = currState;
   

   digitalWrite(ledRd, HIGH);
   digitalWrite(ledGn, LOW);
}
else {
digitalWrite(ledRd, LOW);
digitalWrite(ledGn, HIGH);
}
}

Many thanks

you are missing an opening curly bracket " {" after this line:

if(currState != prevState)

and then you also need to add one more to the end of the void loop.

i think also that maybe you should change this line:

prevState = currState;

to a different place. Where you have it now, it is just working if the button is pressed. But you also want it to update the prevState on each pass, even if the button isn't pressed.

So maybe something like this would work:

const int swPin = 2;
const int ledRd = 9;
const int ledGn = 8;

int prevState = HIGH;
int currState;

byte mode = 0;

void setup() {
  pinMode(swPin, INPUT_PULLUP);
  pinMode(ledGn, OUTPUT);
  pinMode(ledRd, OUTPUT);
}

void loop() {
  int currState = digitalRead(swPin);
  if(currState != prevState) {
    if(currState == LOW) {
      mode = !mode; // Toggle mode
      digitalWrite(ledRd, HIGH);
      digitalWrite(ledGn, LOW);
    }
    else {
      digitalWrite(ledRd, LOW);
      digitalWrite(ledGn, HIGH);
    }
  }
  prevState = currState;
}

Hi try this it is more simple ( i have not test it this, but i have done in a past)

Test it and tell me if it ok.

const int swPin = 2;
const int ledRd = 9;
const int ledGn = 8;

bool ledRd_Bool = LOW,ledGn_Bool = HIGH;

void setup() {
  pinMode(swPin, INPUT_PULLUP);
  pinMode(ledGn, OUTPUT);
  pinMode(ledRd, OUTPUT);
}

void loop() {
   if(digitalRead(swPin) == LOW) {
      ledRd_Bool = !ledRd_Bool;
      ledGn_Bool = !ledGn_Bool;
      while (digitalRead(swPin) == LOW) {}; // Wait here until release the button   
      digitalWrite(ledRd, ledRd_Bool);
      digitalWrite(ledGn, ledGn_Bool);
    }
}

Good luck and happy coding :slight_smile:

Best Regards,
Tasos

To boguz & tasosstr, thank you for your replies.

you're welcome :wink:

I test it and working :slight_smile:

if you want at start up the one led to be on the do the follow:

const int swPin = 2;
const int ledRd = 9;
const int ledGn = 8;

bool ledRd_Bool = LOW,ledGn_Bool = HIGH;

void setup() {
  pinMode(swPin, INPUT_PULLUP);
  pinMode(ledGn, OUTPUT);
  pinMode(ledRd, OUTPUT);

      digitalWrite(ledRd, ledRd_Bool);  // set it at startup
      digitalWrite(ledGn, ledGn_Bool); // set it at startup
}

void loop() {
   if(digitalRead(swPin) == LOW) {
      ledRd_Bool = !ledRd_Bool;
      ledGn_Bool = !ledGn_Bool;
      while (digitalRead(swPin) == LOW) {}; // Wait here until release the button   
      digitalWrite(ledRd, ledRd_Bool);
      digitalWrite(ledGn, ledGn_Bool);
    }
}

Best Regards,
Tasos

@ tasos
That last sketch works perfectly for what I am trying to achieve.
I am using a piezo switch as these are waterproof but they have no feel to them so I need to add a 1 second buzzer sound each time. It is to turn off & on a light and I will repeat this for the hydraulics off & on.
I had a play with trying to add this feature, but I can't work out how to get the buzzer to sound once only for 1 second.

@ tasos
Can you please explain why you have

 digitalWrite(ledRd, ledRd_Bool);  // set it at startup
      digitalWrite(ledGn, ledGn_Bool); // set it at startup

in the void setup

theautomationguy:
@ tasos
Can you please explain why you have

 digitalWrite(ledRd, ledRd_Bool);  // set it at startup

digitalWrite(ledGn, ledGn_Bool); // set it at startup


in the void setup

I am glad it is working as you wish.

In some post you have you're code i see you try to make at start, one led to be on and the other to be off, ( you choose it in the variable

int prevState = HIGH;
int currState;

so in the case you use (digitalWrite ) at setup you can choose the led in you're case, which to be on and which to be off, before you press the button. Be in mind in setup routine everything it will run only one time when the power it is on.

For the buzzer you can use the tone command see tone() - Arduino Reference

And a quick example:

  #define buz 1  // Buzzer connect it on pin 1
// Example of two tones
  tone(buz,450);
  delay(500);
  tone(buz,900);
  delay(500)
noTone(buz);

Best Regards,
Tasos

Thanks Tasos,
I understand.
I understand the tones, but I am just going to use a 5 volt buzzer. But I cant work out how to get the buzzer to sound in that sketch for 1 second (& not repeat) everytime the button is pushed.

I found this while investigating debounce & it has flip flop. I added the pull up resistor & managed to invert the right parts to get it to work. I want to add a 1 off 1 second buzz each time the button is pushed. But get errors everytime I try to add code. Is anyone able to steer me in the right direction how to do this? Thanks in advance.

/* switch
 * 
 * Each time the input pin goes from HIGH to LOW (e.g. because of a push-button
 * press), the output pin is toggled from LOW to HIGH or HIGH to LOW.  There's
 * a minimum delay between toggles to debounce the circuit (i.e. to ignore
 * noise).  
 *
 * David A. Mellis
 * 21 November 2006
 */

int inPin = 2;         // the number of the input pin
int buzzPin = 8;
int outPin = 13;       // the number of the output pin

int state = LOW;      // the current state of the output pin
int reading;           // the current reading from the input pin
int previous = HIGH;    // the previous reading from the input pin

// the follow variables are long's because the time, measured in miliseconds,
// will quickly become a bigger number than can be stored in an int.
long time = 0;         // the last time the output pin was toggled
long debounce = 300;   // original 300 debounce time, increase if the output flickers

void setup()
{
  pinMode(inPin, INPUT_PULLUP);
  pinMode(buzzPin, OUTPUT);
  pinMode(outPin, OUTPUT);
}

void loop()
{
  reading = digitalRead(inPin);

  // if the input just went from LOW and HIGH and we've waited long enough
  // to ignore any noise on the circuit, toggle the output pin and remember
  // the time
  if (reading == LOW && previous == HIGH && millis() - time > debounce) {
    if (state == LOW)
      state = HIGH;
    
      
    else
      state = LOW;

    time = millis();    
  }

  digitalWrite(outPin, state);

  previous = reading;
}

I managed to use tasosstr's sketch & get the 1 sec buzzer I required, this also fixed the switch bounce, I guess the delay caused that.

const int swPin = 2;
const int ledRd = 9;
const int ledGn = 8;
const int buzzPin = 12;

bool ledRd_Bool = LOW,ledGn_Bool = HIGH;

void setup() {
  pinMode(swPin, INPUT_PULLUP);
  pinMode(ledGn, OUTPUT);
  pinMode(ledRd, OUTPUT);

      digitalWrite(ledRd, ledRd_Bool);  // set it at startup
      digitalWrite(ledGn, ledGn_Bool); // set it at startup
}

void loop() {
   if(digitalRead(swPin) == LOW) {
      ledRd_Bool = !ledRd_Bool;
      ledGn_Bool = !ledGn_Bool;
      
      while (digitalRead(swPin) == LOW) {}; // Wait here until release the button   
      digitalWrite(ledRd, ledRd_Bool);
      digitalWrite(ledGn, ledGn_Bool);
      digitalWrite(buzzPin, HIGH);
      delay(1000);
      digitalWrite(buzzPin, LOW);
    }
}

Now to make it better one tone for off & another tone for on. Any suggestions out there. I will use another output pin for another buzzer, but after that I will create different tones which won't be difficult. Arduino's are addictive :slight_smile:

when you press the button set the buzzer to buzz and save the time (using the millis() ) into a variable, called maybe something like buzzBegin.

Then on the loop() check if your interval (1 second) as passed, something like

if(millis() - buzzBegin >= interval) {
   // stop your buzzer
}

this will help you avoid the use of the delay() function.
:wink:

@ boguz
I have managed to get it all to work using delay. I am not sure where the code you have just explained to me goes boguz.
Are you able to c&p what I have pasted here & make the changes, if that isnt too much trouble. I am struggling to grasp where the codes actually go even though I am starting to understand what they are doing.

const int swPin = 2;
const int ledRd = 9;
const int piezoPin = 10;
const int buzzPin = 12;

boolean ledRd_Bool = LOW;

void setup() {
  pinMode(swPin, INPUT_PULLUP);
  pinMode(buzzPin, OUTPUT);
  pinMode(piezoPin, OUTPUT);
  pinMode(ledRd, OUTPUT);


}

void loop() {
   if(digitalRead(swPin) == LOW) {
      ledRd_Bool = !ledRd_Bool;
      
      while (digitalRead(swPin) == LOW) {}; // Wait here until release the button   
      digitalWrite(ledRd, ledRd_Bool);
      digitalWrite(piezoPin, ledRd_Bool);
      digitalWrite(buzzPin, !ledRd_Bool);
      delay(800);
      digitalWrite(piezoPin, LOW);
      digitalWrite(buzzPin, LOW);
   } 
   }

I modify the first code for you in one line to get the buzzer with a sound for a second.

const int swPin = 2;
const int ledRd = 9;
const int ledGn = 8;
#define buz 3  // Connect buzzer to pin 3 and the other pin to gnd

bool ledRd_Bool = LOW,ledGn_Bool = HIGH;

void setup() {
  pinMode(swPin, INPUT_PULLUP);  // make pin 2 as input and activate internall pull up resistor
  pinMode(ledGn, OUTPUT);
  pinMode(ledRd, OUTPUT);
}

void loop() {
   if(digitalRead(swPin) == LOW) {
      ledRd_Bool = !ledRd_Bool; // invert ledRd_Bool flag if it is HIGH make it LOW if it is LOW make it HIGH
      ledGn_Bool = !ledGn_Bool;
      while (digitalRead(swPin) == LOW) {}; // Wait here until release the button   
      digitalWrite(ledRd, ledRd_Bool);
      digitalWrite(ledGn, ledGn_Bool);
      tone(buz,450,1000);  // create a tone on pin 3, create a 450Hz freq. for 1 Second
    }
}

and i make some comment to explain you a bit more what some lines does because i understand now you learn c.

boguz use a delay check without block the entire program but in you're case tone(buz,450,1000);  // create a tone on pin 3, create a 450Hz freq. for 1 Second this line does for you without any extra code.

Now the above it is to give you one sound on each button press, do you want another sound for each led change on High ?

if yes tell me and i will make an example for you.

the code while (digitalRead(swPin) == LOW) {}; // Wait here until release the button  it is used for debounce of the button for the time you hold the button pressed then the program stay there.

I do and the other code for you :slight_smile:

const int swPin = 2;
const int ledRd = 9;
const int ledGn = 8;
#define buz 3  // Connect buzzer to pin 3 and the other pin to gnd

bool ledRd_Bool = LOW,ledGn_Bool = HIGH;

void setup() {
  pinMode(swPin, INPUT_PULLUP);  // make pin 2 as input and activate internall pull up resistor
  pinMode(ledGn, OUTPUT);
  pinMode(ledRd, OUTPUT);
}

void loop() {
   if(digitalRead(swPin) == LOW) {
      ledRd_Bool = !ledRd_Bool; // invert ledRd_Bool flag if it is HIGH make it LOW if it is LOW make it HIGH
      ledGn_Bool = !ledGn_Bool;
      while (digitalRead(swPin) == LOW) {}; // Wait here until release the button   
      digitalWrite(ledRd, ledRd_Bool);
      digitalWrite(ledGn, ledGn_Bool);
      //tone(buz,450,1000);  // create a tone on pin 3, create a 450Hz freq. for 1 Second
      if (ledRd_Bool == HIGH){ // Check if red led it is high then make a sound of 450Hz for a second
        tone(buz,450,1000); 
      }
      
      if (ledGn_Bool == HIGH){ // Check if Green led it is high then make a sound of 900Hz for a second
        tone(buz,900,1000);
      }
    }
}

Best Regards,
Tasos