7 years, 4 months ago.

Problem with using two buttons.

Hello! I have a program which receives input from two SPST buttons. I have tried using the onboard pull-up resistors AND my own external pullup resistors and either way, I receive an output which switches between the correct and incorrect output for each button. Essentially, if I press a button, there is about an 80% chance that it will do what it's supposed to do. Please see the serial monitor below as well as my code. If anyone has even the slightest idea of what I could do, please let me know! I'm using the STM Nucleo F446RE with the inputs: DigitalIn emergencyButton(PA_9); DigitalIn takeOverButton(PB_5); these buttons are connected to ground and their corresponding pins.

/media/uploads/Akrogg/error1.png

Code

#include "mbed.h"
#include "OpenChair.h"
//Define variables
char str [80];
int i;
int TO;

//Open serial port
Serial pc(SERIAL_TX, SERIAL_RX);
//Initialise OpenChair
OpenChair chair(PC_12,PD_2,PC_10,PC_11,60,150); //60,150

//Define Peripherals
//DigitalIn emergencyButton(USER_BUTTON);
DigitalIn emergencyButton(PA_9);
DigitalIn takeOverButton(PB_5);
AnalogIn potentiometerX(PA_0);
AnalogIn potentiometerY(PA_1);
DigitalOut notifierLED(PB_13);
DigitalOut relay(PB_6);
DigitalOut buzzer(PB_12); //led pb3

int main() {
  emergencyButton.mode(PullUp);
  takeOverButton.mode(PullUp);

  //State the variables which hold the data for the position of the potentiometers of the addon box.
  pc.baud(115200);
  double valueX;
  double valueY;

  //Turn on board and hold the power button after poweroff so that the release of it causes the motherboard to turn off.
    pc.printf ("Relay Starting\n");
  wait(1); // Wait one second before beginning turn on sequence incase system startup is due to someone playing around with the switch.
  relay = 1;
  wait(0.5);
  relay = 0;
  wait(0.5);
  relay = 1;
    pc.printf ("Relay Finishing\n");
  // Begin serial communication.
  pc.baud(115200);
    pc.printf ("Starting Loop\n");
while(1) {
  

  if (emergencyButton == 0) {

    pc.printf ("Emergency mode activated. Shutting down.\n");
    //relay = 0;
      pc.printf ("Relay off\n");
    /*while (1) {
      pc.printf ("Buzzer on\n");
      buzzer = 1;
      wait(0.1);
      pc.printf ("Buzzer off\n");
      buzzer = 0;
      wait(0.1);
    }*/ wait(0.2);
    }else if (takeOverButton == 0) {
      pc.printf ("Takeover button on\n");
        TO = TO*-1;
        pc.printf ("Takeover button toggled\n");
     wait(0.2);
    } else if (TO == 1) {
      pc.printf ("Takeover button variable activated and joystick drive enacted\n");
      valueX= (double) (potentiometerX.read()*2-1);
      valueY= (double) (potentiometerY.read()*2-1);
      pc.printf("Potentiometer Values: %.02f    %.02f\n",valueX,valueY);
      chair.drive(valueX, valueY, 1);
      wait_ms(50);
    } else if (TO == 0) {
/*
        pc.scanf ("%s",str);
      //pc.printf ("%s\n",str,i);
      if (str[0] == 'F') {
        pc.printf ("Going forward\n");
        chair.drive(1.00, 1.00, 1);
        wait_ms(50);
        continue;
      } else if (str[0] == 'B') {
        pc.printf ("Going back\n");
        chair.drive(-1.00, -1.00, 1);
        wait_ms(50);
        continue;
      } else if (str[0] == 'L') {
        pc.printf ("Rotating left\n");
        chair.drive(-1.00, 1.00, 1);
        wait_ms(50);
        continue;
      } else if (str[0] == 'R') {
        pc.printf ("Rotating right\n");
        chair.drive(1.00, -1.00, 1);
        wait_ms(50);
        continue;
      } else {continue;}*/
    }
  } // end while
} //end main

It's a bit unclear what you're trying to achieve here, but TO is undefined, thus can contain any value, so if you're relying on that variable, you will see issues. Declare it as int TO = 0;. Also, if you want to respond to button presses, it's probably better to use InterruptIn rather than polling, as using an interrupt you won't miss any events.

posted by Jan Jongboom 04 Aug 2017

It would probably help if you could provide the simplest possible example with one button that demonstrates the problem. I would try to decouple the button reading from taking action. Which is what Jan is suggesting by reading the button via interrupt.

Obviously an issue you always have to worry about with push buttons is debouncing. If it works 80% of the time that could be the issue. I've not used it, but you could try this library. At quick glance it looks like a pretty good strategy and similar to what I have done on my own before.

https://developer.mbed.org/users/AjK/code/DebounceIn/

posted by Graham S. 05 Aug 2017

3 Answers

7 years, 4 months ago.

Hello Andrew,

See below an example of using InterruptIn for buttons (as suggested by Jan) with simple button debouncing (as suggested by Graham):

#include "mbed.h"
//#include "OpenChair.h"

//Define variables
char            str[80];
int             i;
bool            TO = false;

//Open serial port
Serial          pc(SERIAL_TX, SERIAL_RX);

//Initialise OpenChair
OpenChair       chair(PC_12,PD_2,PC_10,PC_11,60,150); //60,150
//Define      Peripherals
InterruptIn     emergencyButton(PA_9);
volatile bool   emergencyBtnEnabled = true;
volatile bool   emergencyBtnPressed = false;
InterruptIn     takeOverButton(PB_5);
volatile bool   takeOverBtnEnabled = true;
volatile bool   takeOverBtnPressed = false;
AnalogIn        potentiometerX(PA_0);
AnalogIn        potentiometerY(PA_1);
DigitalOut      notifierLED(PB_13);
DigitalOut      relay(PB_6);
DigitalOut      buzzer(PB_12);  //led pb3
Timeout         debounceBtn;    // button bouncing Timeout

// Enables Emergency button when bouncing is over
void enableEmergencyBtn(void) {
    emergencyBtnEnabled = true;
}

// ISR handling Emergency button press event
void onEmergencyBtnPressed(void) {
    if (emergencyBtnEnabled) { // disabled while the button is bouncing
        emergencyBtnEnabled = false;
        emergencyBtnPressed = true;
        debounceBtn.attach(callback(enableEmergencyBtn), 0.3);  // debounce time = 0.3s
    }
}

// Enables TakeOver button when bouncing is over
void enableTakeOverBtn(void) {
    takeOverBtnEnabled = true;
}

// ISR handling TakeOver button press event
void onTakeOverBtnPressed(void) {
    if (takeOverBtnEnabled) { // disabled while the button is bouncing
        takeOverBtnEnabled = false;
        takeOverBtnPressed = true;
        debounceBtn.attach(callback(enableTakeOverBtn), 0.3);   // debounce time = 0.3s
    }
}

int main(void) {
    emergencyButton.mode(PullUp);
    takeOverButton.mode(PullUp);

    emergencyButton.fall(callback(onEmergencyBtnPressed)); // attach ISR to handle button press event
    takeOverButton.fall(callback(onTakeOverBtnPressed));   // attach ISR to handle button press event

    //State the variables which hold the data for the position of the potentiometers of the addon box.
    pc.baud(115200);

    double  valueX;
    double  valueY;

    //Turn on board and hold the power button after poweroff so that the release of it causes the motherboard to turn off.

    pc.printf("Relay Starting\n");
    wait(1);    // Wait one second before beginning turn on sequence incase system startup is due to someone playing around with the switch.
    relay = 1;
    wait(0.5);
    relay = 0;
    wait(0.5);
    relay = 1;
    pc.printf("Relay Finishing\n");

    // Begin serial communication.
    pc.baud(115200);
    pc.printf("Starting Loop\n");
    while (1) {
        if (emergencyBtnPressed) {
            emergencyBtnPressed = false;
            pc.printf("Emergency mode activated. Shutting down.\n");

            //relay = 0;
            pc.printf("Relay off\n");
        }
        else
        if (takeOverBtnPressed) {
            takeOverBtnPressed = false;
            pc.printf("Takeover button on\n");
            TO = !TO;
            pc.printf("Takeover button toggled\n");
        }
        else
        if (TO == true) {
            pc.printf("Takeover button variable activated and joystick drive enacted\n");
            valueX = (double)(potentiometerX.read() * 2 - 1);
            valueY = (double)(potentiometerY.read() * 2 - 1);
            pc.printf("Potentiometer Values: %.02f    %.02f\n", valueX, valueY);

            chair.drive(valueX, valueY, 1);
            wait_ms(50);
        }
        else
        if (TO == false) {
            // ...
        }
    }   // end while
}   //end main

Accepted Answer

Wim is right abut TO. A bool type (as above) would be more simple to use.

posted by Zoltan Hudak 06 Aug 2017
7 years, 4 months ago.

There is another issue with the flag value T0. You multiply T0 by -1 presumably to flip it between 1 and -1. That means you should test T0 against either 1 or -1 as well. You currently test against 1 and 0. Also note that T0 should be initialised as either 1 or -1. Without initialisation it should be 0 in C++.

Thank you for your help, Wim! I have corrected this error :))

posted by Andrew Kroger 10 Aug 2017
7 years, 4 months ago.

I wrote a Button library with debounce, auto-repeat, press, long press features. You can use it, or check source for ideas. https://developer.mbed.org/users/vargham/code/Button/

Thank you for your help, Mark!

posted by Andrew Kroger 10 Aug 2017