7 years, 9 months ago.

Push Button , keep last status until press another button.

Hello everyone, I need little help regaring push buttons. I would be grateful if someone help me. So I have for example the program as follows:

  1. include "mbed.h" DigitalOut led1(LED1); DigitalOut led2(LED2); DigitalIn button1(PC_14); DigitalIn button2(PC_15);

void button_1(); void button_2(); void button_1and2();

int main() { for(;;) { if(button1 && !button2) { button_1(); } if(button2 && !button1) { button_2(); } if (button1 && button2) { button_1and2(); } } } void button_1() { led1 = 1; wait(0.5); wait 500 ms led1 = 0; wait(0.5); wait 500 ms } void button_2() { led2 = 1; wait(0.5); wait 500 ms led2 = 0; wait(0.5); wait 500 ms } void button_1and2() { led1 = 1; led2 = 1; wait(0.5); wait 500 ms led1 = 0; led2 = 0; wait(0.5); wait 500 ms }

The problem now it is that i need to keep the button pressed to can execute the functions. I want to press once the button and to run his void. And when i press another button to execute his functions.

Thank you.

Hi Viktoria. Please use the <<code>> and <</code>> markers to properly format your code which will assist others to review your code.

include "mbed.h"

DigitalOut led1(LED1);
DigitalOut led2(LED2);

DigitalIn button1(PC_14);
DigitalIn button2(PC_15);

void button_1();
void button_2();
void button_1and2();

int main()
{
    for(;;) {
        if(button1 && !button2) {
            button_1();
        }

        if(button2 && !button1) {
            button_2();
        }

        if (button1 && button2) {
            button_1and2();
        }
    }
}

void button_1()
{
    led1 = 1;
    wait(0.5); // wait 500 ms

    led1 = 0;
    wait(0.5);  //wait 500 ms
}

void button_2()
{
    led2 = 1;
    wait(0.5); // wait 500 ms

    led2 = 0;
    wait(0.5);  // wait 500 ms
}

void button_1and2()
{
    led1 = 1;
    led2 = 1;
    wait(0.5); // wait 500 ms

    led1 = 0;
    led2 = 0;
    wait(0.5);  //wait 500 ms
}
posted by Sanjiv Bhatia 15 Mar 2017

Ok I will know in future. I'm new in programing and especially on mbed.

posted by Viktoria Vladimirova 16 Mar 2017

2 Answers

7 years, 9 months ago.

The trick is to remember the state of the buttons last time through the loop. Only then can you check for a change in state. Also, since you want to perform the same function over and over until a new button is pressed, you have to remember that, too.

The follow code demonstrates the "button memory" you are looking for. However, this program will not produce a very good user experience. Some things you will have to consider as you move forward are how to capture a button press when you aren't looking for one, button debounce, race conditions (it is almost impossible to press button 1 and button 2 at exactly the same time, so you are unlikely to ever perform button_1and2()), etc... Anyway, that's farther down the road. This should get you started.

updated main()

int main()
{
    enum {performNothing, performButton1, performButton2, performButton3};

    bool wasEitherButtonPressed = false;
    int  performFunc = performNothing;

    while (true) {

        // Capture current button state
        bool isB1Pressed = (button1 == 1) ? true : false;
        bool isB2Pressed = (button2 == 1) ? true : false;
        bool isEitherButtonPressed = isB1Pressed || isB2Pressed;

        // If either one or both buttons are pressed after neither
        // being pressed, pick a new function to perform.
        if (!wasEitherButtonPressed && isEitherButtonPressed) {
            if(isB1Pressed && isB2Pressed) {
                performFunc = performButton3;
            } else if (isB2Pressed) {
                performFunc = performButton2;
            } else {
                performFunc = performButton1;
            }
        }

        // Perform the same function (until a new button press)
        if (performFunc == performButton1) {
            button_1();
        } else if (performFunc == performButton2) {
            button_2();
        } else if (performFunc == performButton3) {
            button_1and2();
        }

        // Remember the button state for the next time around the loop

        wasEitherButtonPressed = isEitherButtonPressed;
    }
}

Note: You may have to change lines 11 & 12 depending on the value of the button when pressed. I based it off of your example code, but most times, buttons read as '0' when pressed, which is opposite of what is shown here.

It's easy to handle the 2 button detection if you don't hit both buttons are exactly the same time, the logic needs to be:

If two buttons are pressed perform the action for 2 buttons.

If 1 button is pressed only perform the action for that button if the previous state was no buttons.

 if (isB1Pressed && isB2Pressed) 
    performFunc = performButton3;
 else {
    if (!wasEitherButtonPressed) {
       if (isB1Pressed)
           performFunc = performButton1;
       if (isB2Pressed)
           performFunc = performButton2;
        }
  }

Of course you could still get the single button function called once before it sees the two buttons but without including a delay to allow for other buttons before executing the function there isn't a lot you can do about that. The easiest way to avoid false single button triggers would be to no do anything until the buttons are released but that then requires robust de-bouncing and isn't always an option for other reasons.

posted by Andy A 15 Mar 2017

Hello again :) Your informations and example code was realy helpful for me. Thank you again. But now I have another problem and I will be thankful if you can help me :) How with your example or how I can make: Now when I press button is executed the one of the voids and so on... But here with LED the voids are small in my actual program my voids are huge, and sometime I need to interupt the voids when press other button. Thank you.

posted by Viktoria Vladimirova 18 Apr 2017
7 years, 9 months ago.

Here's a variation for a crude debounce (caution: mentally executed only).

void main() {
    BusIn nibble(p5, p6);   // whatever port pins you want. bit0:p5, bit1:p6 
    uint8_t last = 0x03 & nibble;        // capture an initial state to compare 2. use ~nibble if active low

    while (true) {
        Thread::wait(20);                // We'll use 20 msec as the sample interval. Might want 40 msec
        uint8_t curState = 0x03 & nibble;    // use ~nibble if active low
        if (curState == last) {
            switch(curState) {
                case 1:  // only p5
                    p5Function();
                    break;
                case 2:  // only p6
                    p6Function();
                    break;
                case 3:  // p5 and p6
                    p56Function();
                    break;
                case 0:  // nothing pressed
                    break;
                default:  // anything unexpected
                    break;
            }
        } else {
            // they are different, do nothing.
        }
    }
}

Depending on your needs, you might want to use a timer instead of a wait, or you might want to count some multiples of the wait interval for debouncing.

void main() {
    BusIn nibble(p5, p6);   // whatever port pins you want. bit0:p5, bit1:p6
    uint8_t last = 0x03 & nibble;        // capture an initial state to compare 2. use ~nibble if active low
    int sampleCount = 5;

    while (true) {
        Thread::wait(10);                // We'll use 10 msec as the basic sample interval, and sampleCount multiples for full debounce
        uint8_t curState = 0x03 & nibble;    // use ~nibble if active low
        if (curState == last) {
            if (sampleCount) {
                sampleCount--;
                continue;
            }
            switch(curState) {
                case 1:  // only p5
                    p5Function();
                    break;
                case 2:  // only p6
                    p6Function();
                    break;
                case 3:  // p5 and p6
                    p56Function();
                    break;
                case 0:  // nothing pressed
                    break;
                default:  // anything unexpected
                    break;
            }
        } else {
            // they are different, reset the counter.
            sampleCount = 5;
        }
    }
}

For more on debouncing switches, including more code, see Jack Ganssle's 2 part series - http://www.ganssle.com/debouncing.htm.

Super , Thank you for the fast answer. Really helpful. I will try to implement in my code. Thank you again if I have more questions I will write. :)

posted by Viktoria Vladimirova 16 Mar 2017

At the bottom of the loop should be

last = curState;
posted by David Smart 16 Mar 2017