Bistable button?

Hey everyone !

i'm new on this forum, new in the arduino world..

So i have question..

I'm trying to use a push button to make a bistable balance.
I push one time the LED is power on, second time she's turned off.

int ledPin = 9;
int gndPin = 8;
int gnd=7;
int bt=6;
int etat=LOW;
int cpt=0;
void setup()
{
pinMode(ledPin, OUTPUT);
pinMode(gndPin, OUTPUT);
pinMode(gnd, OUTPUT);
pinMode(bt,INPUT);
digitalWrite(gndPin, LOW);
digitalWrite(bt, LOW);
digitalWrite(gnd, HIGH);

}

void loop()
{
  etat=digitalRead(bt);
    if(etat==HIGH)
    {
    cpt++;
      do{
          digitalWrite(ledPin,HIGH);
            if(digitalRead(bt)==HIGH&&cpt==1)
              {
                 digitalWrite(ledPin,LOW);
                 break;
              }    
          }while(1);
       digitalWrite(ledPin,LOW);
    }
}

Here is my code, so please don't smile after reading this :roll_eyes:

First of all, if you are starting, you need to get used to the "rules" when you write code. Look how it looks after select the option "Auto-format" from the "Tools" menu:

int ledPin = 9;
int gndPin = 8;
int gnd = 7;
int bt = 6;
int etat = LOW;
int cpt = 0;
void setup()
{
  pinMode(ledPin, OUTPUT);
  pinMode(gndPin, OUTPUT);
  pinMode(gnd, OUTPUT);
  pinMode(bt, INPUT);
  digitalWrite(gndPin, LOW);
  digitalWrite(bt, LOW);
  digitalWrite(gnd, HIGH);

}

void loop()
{
  etat = digitalRead(bt);
  if (etat == HIGH) {
    cpt++;
    do {
      digitalWrite(ledPin, HIGH);
      if (digitalRead(bt) == HIGH && cpt == 1) {
        digitalWrite(ledPin, LOW);
        break;
      }
    } while (1);
    digitalWrite(ledPin, LOW);
  }
}

EDIT:

2nd I like (but is a personal question) to have the ' { ' of the if in the same line (it can solve you many hours of debugging too).

3rd I don't like the while (1) and the break. I prefer use something like:

    do {
      // do something
      if (some_var == some_value) {
         exit = true;
      }
    } while (exit==false);

Your program don't do what you what because of this line:

  if (etat == HIGH) {

You must look for the change of state, and not for the 'HIGH' state.

So a latch.

byte LEDpin = 13; //on-board LED
byte ButtonPin = 2; //digital pin 2

boolean button, lastState = LOW;
boolean latch = false;

void setup() 
{
  pinMode(LEDpin, OUTPUT);
  pinMode(ButtonPin, INPUT);
}

void loop() 
{
  button = digitalRead(ButtonPin); // read the button state

  if (button != lastState) // compare the button state to an old state
  {
    if(button == HIGH) // if the button is different from its old state, see if the button is HIGH
    {
      latch = !latch; // 0 -> 1, 1 -> 0

      if(latch == 1)
        digitalWrite(LEDpin, HIGH);
      else 
        digitalWrite(LEDpin, LOW);

      //OR.

      //digitalWrite(LEDpin, latch);

      //OR..

      //digitalWrite(LEDpin, !digitalRead(LEDpin) );

      //OR...

      //latch ? digitalWrite(LEDpin, HIGH): digitalWrite(LEDpin, LOW); //Equal to above IF/ELSE statement.
      
      lastState = button; // update old state
    } 
  }
}

The StateChangeDetection example sketch demonstrates how to read a digital input, debounce it and detect state transitions.

In the example, it is counting button presses. Here, you would want to replace that code with something to toggle the state of an output pin. The following code will toggle the pin for you:

digitalWrite(pin, !digitalRead(pin));

Sorry for the code format.

I would like to push the button one time to get the LED ON, she's stay in this state until i press the button a second time.
Sorry for bad explanation and thank you for your help !

I like the sketch of HazardsMind. I only don't like the "if thing". :slight_smile:

I only don't like the "if thing".

Which one, the first, second, or third if statement?

Here is the new code. What about ? :sweat_smile:

int ledPin = 9;
int gndPin = 8;
int gnd = 7;
int bt = 6;
int etat = 0;
int lsBt = 0;
int cpt = 0;

void setup()
{
  pinMode(ledPin, OUTPUT);
  pinMode(gndPin, OUTPUT);
  pinMode(gnd, OUTPUT);
  pinMode(bt,INPUT);
  digitalWrite(gndPin, LOW);
  digitalWrite(bt, LOW);
  digitalWrite(gnd, HIGH);

}

void loop()
{
  bool exit = false;
  etat = digitalRead(bt);
  if(etat != lsBt && etat == HIGH){
    cpt++;
    do{
      digitalWrite(ledPin, HIGH);
      if(digitalRead(bt) == HIGH && cpt == 1){
        digitalWrite(ledPin , LOW);
        exit = true;
      }    
    }
    while(exit == false);
    lsBt = etat;
  }
  else {
    digitalWrite(ledPin, LOW);
  }
}

That's a little much, do you think you can simplify it?

HazardsMind, the "if thing" that I describe in the first post. For me, and even more if we are trying to teach the language to someone fresh coming, I like to write (and teach to them to write):

   if (some_condition) {
      //some code
   }

instead of:

   if (some_condition) 
   {
      //some code
   }

What do you do if you have multiple IF statements nested inside each other?

if(/*conditon*/) {
  if(/*another condition*/) {
    if(/*another condition*/) {

    /* code */

    }
  }
}

Yes, i have put only one digitalWrite().

int ledPin = 9;
int gndPin = 8;
int gnd = 7;
int bt = 6;
int etat = 0;
int lsBt = 0;
int cpt = 0;

void setup()
{
  pinMode(ledPin, OUTPUT);
  pinMode(gndPin, OUTPUT);
  pinMode(gnd, OUTPUT);
  pinMode(bt,INPUT);
  digitalWrite(gndPin, LOW);
  digitalWrite(bt, LOW);
  digitalWrite(gnd, HIGH);

}

void loop()
{
  bool exit = false;
  etat = digitalRead(bt);
  if(etat != lsBt && etat == HIGH){
    cpt++;
    do{
      digitalWrite(ledPin, HIGH);
      if(digitalRead(bt) == HIGH && cpt >=1) {
      exit = true;
      }    
    }
    while(exit == false);
    lsBt = etat;
  }
  else {
    digitalWrite(ledPin, LOW);
  }
}

Like that.. but it's don't work ..

luisilva:
For me, and even more if we are trying to teach the language to someone fresh coming, I like to write (and teach to them to write):

   if (some_condition) {

//some code
   }




instead of:



if (some_condition)
   {
      //some code
   }

They are both established code layout schemes, each with pros and cons. In my opinion, the benefits of the second layout outweigh the benefits of the first layout.

Unfortunately I’ve pass many hour of my life debugging code and many times the bug was something like:

   for (int i=0; i<MAX; i++);
  {
     // do something
    // inside the loop
   }

So, this bug will never “born” if you had used to do the for loop like:

   for (int i=0; i<MAX; i++) {
     // do something
    // inside the loop
   }

The same for if, while etc.

Is one code standard that I try to follow to avoid headaches (or the same, bugs).

EDIT: for example, in this code standard, your lines:

      if(latch == 1)
        digitalWrite(LEDpin, HIGH);
      else 
        digitalWrite(LEDpin, LOW);

are completely prohibited (rule 14.9).

That’s perfectly valid code, what rules are you referring to?

Yes it is, and I’m not saying that. The rule 14.9 from MISRA 2004 says:

An if (expression) construct shall be followed by a compound statement. The else keyword shall be followed by either a compound statement, or another if statement.

if ( test1 )

{
  x = 1; /* Even a single statement must be in braces /
}
else if ( test2 ) /
No need for braces in else if /
{
  x = 0; /
Single statement must be in braces /
}
else
  x = 3; /
This was (incorrectly) not enclosed in braces /
  y = 2; /
This line was added later but, despite the
             appearance (from the indent), it is actually
             not part of the else, and is executed unconditionally */

This type of rule are only to avoid bugs.

EDIT: for example, in this code standard, your lines:

      if(latch == 1)
        digitalWrite(LEDpin, HIGH);
      else 
        digitalWrite(LEDpin, LOW);

Replace with

 digitalWrite(LEDpin, latch);

If you look at my original sketch, you will see I provided a few alternatives, and that was one of them.

luisilva:
So, this bug will never “born” if you had used to do the for loop like:

The second layout doesn’t prevent the problem - it merely changes how it would appear (it makes it slightly less obvious, in my opinion, since the spurious semicolon is no longer at the end of the line):

for (int i=0; i<MAX; i++) ;{

However, I would expect that sort of mistake to be glaringly obvious to any experienced programmer scanning the code using either layout. The benefit of the second layout IMO is that it is far easier to visually match up matching pairs of brace characters so that the control structure of the code can be verified against the structure implied by the indentation.

PeterH:
However, I would expect that sort of mistake to be glaringly obvious to any experienced programmer scanning the code using either layout.

It depends what time is it, and how many hours you sleep, I think. If there are 02:00 and you sleep 4h the last night there are some mistakes that are obvious than others. Or this or I'm not an experienced programmer.