Button Function - Call throughout when button action needed

Hello all, new here so normal applies - be gentle with me!

I’ve been trying to learn what’s what and was struggling with a 4 button set-up function that I could call whenever needed (I only have halts to respond to in my project, not interupts).

The below function seams to be working as I want (the full code drives the response to a LCD) but it also appears to be a little too simple. That normally means I’m going to fry something! All tac buttons have a 10K pulldown on them & individual channels as I can spare them.

Your thoughts or alternative would be greatly appreciated:

int buttonPress(){
buttonState = 0;
buttonPressed = 0;
do
{
for(int x = 0; x <4; x ++) {
int pin = x +2;
buttonState = digitalRead(pin); delay(10);
if (buttonState == HIGH) {
buttonPressed = x+1;
}
else{
}
}//For
} while (buttonState == LOW && buttonPressed == 0);

}//buttonPress

You can -for example- make your code more advance via adding classes and objects. Try to create a new class in your sketch with the name ‘Button’ and create your general button press method. Then, create four objects. Each object should represent a physical button.

I hope this helps you.

Hi, the first two (standard) suggestions are:

  • use the “code” button in the editor when posting (ehm) code… it’s the one with a “#” on it;
  • properly indent your code so it’s easier to read (and bugs - at least obvious ones - are easier to spot); use CTRL-T in the Arduino IDE to help you on this.

Here’s the result (with some commends added by me):

int buttonPress()  {
    buttonState = 0;
    buttonPressed = 0; 
    do
    { 
        for (int x = 0; x <4; x ++)  {
            int pin = x + 2;                     // button pin numbers - better make it more explicit and visible
            buttonState = digitalRead(pin); 
            delay(10);                            // why this delay ?
            if (buttonState == HIGH) {
                buttonPressed = x+1;
            }
            else {                // why this empty "else" ?
            }
        } //For
    } 
    while (buttonState == LOW && buttonPressed == 0); 

} //buttonPress

Some random suggestions…
Button pin numbers are better stated at the beginning of the sketch, with integer constants, like this:

const short int BTN1_PIN = 2;

Since you have 4 buttons, you could put them in an array:

#define ARY_LEN(a) (sizeof(a)/sizeof(a[0]))

const short int buttonsPin[] = { 2, 3, 4, 5 };

const short NUM_BUTTONS = ARY_SIZE(buttonsPin);

// later in the code...
boolean buttonPressed = (digitalRead(buttonsPin[0]) == HIGH);    // or LOW, depending on circuit

The advantage of this solution is that you can have non-contiguous pin numbers but process them in a four loop nonetheless. For example:

for (i = 0; i < NUM_BUTTONS; i++) {
    pinStatus[i] = digitalRead(buttonsPin[i]);
}

HTH

Hi, In my RC Car/Go Kart lap timer project I have 4 keys to drive a user interface - scroll up, scroll down, ok, cancel.

The following very simple functions drive this -

getKeys - Very simply poles the pins to see which buttons are pressed - non blocking

waitForKeyPress - This one loops until one of the keys passed when the function is called gets pressed, for example if I am looking for OK or Cancel and I am not interested in up and down I call waitForKeyPress(KEY_OK|KEY_CANCEL) this will ignore up and down but will return with ok or cancel if one of these two gets pressed

waitForKeyRelease - This one waits until all keys are released, its important when cancel might mean 'get me out of this mode' but then means 'delete' in the next mode - we need to wait until no keys are pressed before assuming a cancel press means the user wants us to delete something.

Its simple stuff, I don't see much to gain from classes and arrays for four buttons so here it is, as used in my lap timer project, feel free to use it, you may of course want to add or change buttons.

Project Intro Here - http://rcarduino.blogspot.com/2012/02/rc-lap-timer-go-kart-lap-timer-part-2.html

//////////////////////////////////////////////////////////////////////////////////
//
// Key related helpers
//
// getKeys - pole keys
// waitForKeyPress - block waiting for keys based on a mask
// waitForKeyRelease - block waiting until no keys are pressed - used between menu contexts
//
//////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////
//
// getKeys
//
// read the inputs and create a bit mask based on the buttons pressed
// this does not block, need to review whether we should make this block, in most
// cases we loop waiting for a key, sometimes we also loop waiting for no key
// could put both options here with an input parameter.
//
//////////////////////////////////////////////////////////////////////////////////
short getKeys()
{
 // Use bit flags for keys, we may have a future use for
 // combined key presses

 short sKeys = KEY_NONE;
 if(digitalRead(KEY_UP_PIN) == LOW)
 {
  sKeys |= KEY_UP; 
 }
 if(digitalRead(KEY_DOWN_PIN) == LOW)
 {
  sKeys |= KEY_DOWN;
 }
 if(digitalRead(KEY_OK_PIN) == LOW)
 {
  sKeys |= KEY_OK;
 }
 if(digitalRead(KEY_CANCEL_PIN) == LOW)
 {
  sKeys |= KEY_CANCEL;
 }

 // absorb any switch bounce here
 delay(200);

 return sKeys;
}

//////////////////////////////////////////////////////////////////////////////////
//
// waitForKeyRelease
//
// we can enter a function while the activating key is still pressed, in the new
// context the key can have a different purpose, so lets wait until it is released
// before reading it as pressed in the new context
// 
//////////////////////////////////////////////////////////////////////////////////
void waitForKeyRelease()
{
  do
  {
    // do nothing
  }
  while(getKeys() != KEY_NONE);
}

//////////////////////////////////////////////////////////////////////////////////
//
// waitForKeyPress
//
// convenience function, loop doing nothing until one of the sKeyMask keys is 
// pressed
// 
//////////////////////////////////////////////////////////////////////////////////
uint8_t waitForKeyPress(uint8_t sKeyMask)
{
  uint8_t sKey = KEY_NONE;
  
  do
  {
    sKey = getKeys() & sKeyMask;    
  }
  while(sKey == KEY_NONE);
  
  return sKey;
}

Duane B

rcarduino.blogspot.com

// absorb any switch bounce here delay(200);

Don't have a scope and a switch at hand, but to me that seems a really long delay... Also, you're basically making a function block for 200ms for no good reason, as after that delay you simply return what you read 200ms before. What if at the time you sampled the inputs those were HIGH because of bounce ? I think debouncing logic should either belong to a higher level, or the delay should be kept to the strict minimum, otherwise the result will be a program that just delay()s most of the time... All of this IMHO, obviously :-)

Hi, Your are right, reading through an unrelated thread, someone mentioned 20ms as more than sufficient to debounce a switch, I will update accordingly.

Thanks

Duane B.

rcarduino.blogspot.com

20ms sound reasonable to me, but could still be a waste of time (happened to me). If you can, take a digital oscilloscope and measure the signal you get when you close or open the switch. That'll let you better evaluate what debounce time you should use.

HTH

Hi, We might be getting off the OPs topic at this point, but a reasonable improvement from your suggestions would be to make the delay a parameter of the function.

In addition it would also be possible to pass the mask to getKeys so that only the keys of interest are poled and the delay is only active if a LOW is detected on a key of interest.

The three functions obviously implement a blocking/poling approach to the user interface, it is the simplest approach and based on the original topic - 'Button Function - Call throughout when button action needed' would appear to be an appropriate response.

Duane B.

rcarduino.blogspot.com