How to debounce two button combinations

Hi,
I am using a NANO 328p to send IR commands. I am wondering what the best way to detect buttons, given 5 buttons that map below to pins. I want to debounce the press and do that for combinations also.

These are button inputs on PortD with internal pullups enabled on all listed pins.
Fwd = 12
Rev = 11
Lef = 10
Rit = 9
Tbo = 8

So I can have a combination of button presses I want to do. Like:
Fwd
Fwd + Lef
Fwd + Rit
Rev
Rev + Lef
Rev + Rit
etc.....

Appreciate the help! Thanks.

Scan your switches every 50ms; look for switch change in state.

When you press two buttons "at the same time", how long do you want to wait to determine if the first button that closes is a single button or part of a combination?

This is for a real time remote controlling a moving vehicle. So 10ms debounce. Maybe 20ms for settling two presses.

I took a stab at making a debounce but I think I have logic holes in what I want to accomplish. I want to look for changes on PINB which is the upper byte of PORTD pin status register on Nano 328P. I verified that masking off the upper 3 bits and looking at Pin8 ~ Pin12 works. These inputs are all pull high so unpressed state is B00011111.

So now I have the port status for the state of the pins I am interested in. This pins are connected to momentary switches. Each correspond to a direction to control a remote vehicle.
pin 12 - FWD
pin 11 - REV
pin 10 - Right
pin 9 - Left
pin 8 - Turbo

So I guess I am debouncing 5 pins for changes. The problem is if a change happens during my while loop, I will exit with the status of the pins not completing the debounce. loadTX-Decode is used by my switch case statement to decode 1 button or 2 buttons correspond to what action.
Example: I can push and hold FWD, then while doing that, push and hold RIGHT or LEFT.

Since I am controlling something in real time, sending a 0 or stop command between button combinations is going to make movement jerky and non-continuous. Adding in more than 10ms debounce will serious lag the response of the vehicle. Not sure how to handle this.

void readButtonPress() {
   
   Whatisinit = PINB & B00011111;                // apply mask to focus on pins of interest
   if (Whatisinit != B00011111){                   // a button was pressed
    WhatNow = PINB & B00011111;
    count = 0;
    while ((Whatisinit = WhatNow) && (count < 5)) {
      delay(4); 
      WhatNow = PINB & B00011111;
      count++ ;
      loadTX_Decode = WhatNow;      // pass along the debounced switch presses to decode function
    }  
   }else{    
   loadTX_Decode = B00011111;     // pin 8 to pin 12 all high means no button press or all stop
   }
 }

I see what you are trying and I think this might do what you want:

void readButtonPress()
{
  static byte wereUnpressed = B00011111;
  static boolean newChange = false;
  byte areUnpressed = PINB & B00011111; // apply mask to focus on pins of interest

  if (areUnpressed != wereUnpressed)
  {
    // The pattern has changed. Start a timer.
    lastChangeTime = millis();
    newChange = true;
  }
  else
  {
    // The pattern has NOT changed
    if (newChange && millis() - lastChangeTime > 20)
    {
      // The change has been present for 20 ms
      wereUnpressed = areUnpressed;  // Remember the new pattern
      loadTX_Decode = areUnpressed;  // Act on the new pattern
      newChange = false;  // Mark the pattern as handled.
    }
  }
}

Ah, I see where I went off the track. I was of the mindset that I needed to hold the debounce in a captive loop. Falling through to the next pass through is the right way. I will give it a try tomorrow. Today was family day :). Thanks for the help!

Hi John,

I had a chance to test the function. It keeps returning 31 no matter what button I press. Also, it seems to send it over and over even when the button is released. Trying to figure out where it is hanging up. Also, updates the serial monitor only when the key is let go. Not while it is held down.

OK, I modified your code and now seems to be working. But I think it is not debouncing anything. I increased the > 20 to seconds and it instantly decodes the button press. Still not where I want it to be....I will continue to tinker.

void readButtonPress(){
  
  static byte wereUnpressed = B00011111;
  byte lastChangeTime;
  static boolean newChange = false;
  byte areUnpressed = PINB & B00011111;                             // apply mask to focus on pins of interest

  if (areUnpressed != wereUnpressed)
  {                                                                 
    lastChangeTime = millis();                                      // The pattern has changed. Start a timer.
    newChange = true;
  }
 
    if (newChange && (millis() - lastChangeTime) > 20)             // The pattern has NOT changed
    {
                                                                   // The change has been present for 20 ms
      wereUnpressed = areUnpressed;                                // Remember the new pattern
      loadTX_Decode = areUnpressed;                                // Act on the new pattern
      newChange = false;                                           // Mark the pattern as handled.
    }
  }

The value 31 (B00011111) means none of the buttons are pressed. Just ignore that value. If pressing a button is not changing the pattern then I suspect your buttons are wired wrong.

The variable 'loadTX_Decode' will always have a value. Do you have a way to detect when it has a NEW value? I would probably use a value like B00100000. Act on the pattern only when it is not B00100000. When done with a value, set loadTX_Decode to B00100000.

I have something that works. It is going through and evaluating the millis() difference in timing.
I send the content of myTime3 to serial monitor at 1200 baud (the output needed for IR). The loop count comes back at 33ms. When I bump up the serial output to 115,200 baud it comes back as expected and counts, 0, 1, 2 , 3, 4, 5---> jumps out and write the bit pattern out.

I thought serial UART was a hardware function.....so why is 1200 baud causing my loop delay to multiply by 6 or so......33ms with a 5 millisecond count?

I am using an Arduino NANO 328p version.

void readButtonPress(){
  
  static byte wereUnpressed = B00011111;
  static byte lastChangeTime;
  static boolean newChange = false ;
  static byte areUnpressed = PINB & B00011111;                            // apply mask to focus on pins of interest
 
       
    areUnpressed = PINB & B00011111;                           
    if (areUnpressed != B00011111){  
       myTime3 = (millis() - myTime2);            
       if (myTime3 > 5){
         myTime2=  millis();  
         loadTX_Decode = areUnpressed;  
         myTime3 =0;             
       }         
    }else{
      myTime2 = 0;
      myTime3 = 0;
      areUnpressed = PINB & B00011111;
      loadTX_Decode = areUnpressed ;
    }
}             

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.