A better way to debounce buttons for sending UART keyboard messages.

Hello,

I am trying to figure out a better method than I am using currently to debounce, keeping track of the states of pushbuttons.

I need the buttons to send a uart single report on the push on and another single uart report on the release, like a real keyboard.

As you can see, if I add another 12 buttons this working sketch it will become very large. I was thinking a button array, possibly. All the examples I see on the web do not send just a single report when pushing the button down and then another on the release.

Any ideas or better methods to reduce code? I am also worried about SRAM usage.

By the way, the other part void uart_stream() is a sensor that continuously is sending data when activated until it is deactivated.

// UART Header Data to go before UART 1 RX data

byte uartData[9] = { 0xAA, 0xBB, 0xCC, 0xDD };

// UART Button ON Reports

byte downOn[] = {0xAA, 0xBB, 0xCC, 0xDD, 0x00, 0x51, 0x00, 0x00, 0x00, 0x00, 0x00};
byte leftOn[] = {0xAA, 0xBB, 0xCC, 0xDD, 0x00, 0x50, 0x00, 0x00, 0x00, 0x00, 0x00};
byte rightOn[] = {0xAA, 0xBB, 0xCC, 0xDD, 0x00, 0x4F, 0x00, 0x00, 0x00, 0x00, 0x00};
byte upOn[] = {0xAA, 0xBB, 0xCC, 0xDD, 0x00, 0x52, 0x00, 0x00, 0x00, 0x00, 0x00};

// UART Button OFF Reports

byte downOff[] = {0xAA, 0xBB, 0xCC, 0xDD, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
byte leftOff[] = {0xAA, 0xBB, 0xCC, 0xDD, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
byte rightOff[] = {0xAA, 0xBB, 0xCC, 0xDD, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
byte upOff[] = {0xAA, 0xBB, 0xCC, 0xDD, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};


int ledPin = 13;                //MEGA 2560 Board LED ON/OFF Pin13
int button0Pin = 53;            //input 53pin for pushbutton 0
int button1Pin = 52;            //input 52pin for pushbutton 1
int button2Pin = 51;            //input 51pin for pushbutton 2
int button3Pin = 50;            //input 50pin for pushbutton 3


int button0Val = 0;              //variable for reading the button status
int button1Val = 0;
int button2Val = 0;
int button3Val = 0;

int button0State = 0;            //variable to hold the buttons current state
int button1State = 0;
int button2State = 0;
int button3State = 0;

int bounce0Check = 0;            //variable for debouncing
int bounce1Check = 0; 
int bounce2Check = 0; 
int bounce3Check = 0; 

void setup() {
  pinMode(ledPin, OUTPUT);      //declare LED as output
  pinMode(button0Pin, INPUT);    //declare pushbutton as input
  pinMode(button1Pin, INPUT);
  pinMode(button2Pin, INPUT);
  pinMode(button3Pin, INPUT);
 
               
  Serial.begin(9600);           //begin serial communication at 9600 baud
  Serial1.begin(9600);
  Serial2.begin(9600);
}

// if 9 bytes on UART 1 then write uartData[i] on UART 2, if not do nothing

void uart_Stream()
{

  if (Serial1.available())
  { 
    for (int i=4; i<9; i++)
    
    {
      
      while (Serial1.available() == 0)
      
      {
        //do nothing
      }
      
      uartData[i] = Serial1.read();
    
    }
    
    for (int i=0; i<9; i++)
    {
      Serial2.write(uartData[i]);
    }
  }
}

void check_switches() // sends UART (ON) report on Button is pressed and another UART (OFF) report when button is released (like keyboard)
{
  // Button 0 Pin 53 
  button0Val = digitalRead(button0Pin);     //read input value from button
  delay(1);                              //wait 10ms
  bounce0Check = digitalRead(button0Pin);   //check again
  
  if(button0Val == bounce0Check){           //if val is the same then not a bounce
  
    if (button0Val == HIGH && button0State == 1)    //check if the input is HIGH
     {
      digitalWrite(ledPin, LOW);         //turn LED OFF
      Serial2.write(downOff, sizeof(downOff));
      //Serial.println("OFF");
      button0State = 0;
     }
    if(button0Val == LOW && button0State == 0)
     {
      digitalWrite(ledPin, HIGH);       //turn LED ON
      Serial2.write(downOn, sizeof(downOn));
      //Serial.println("ON");
      button0State = 1;
     }
  }   
  // Button 1 Pin 52 
  
  button1Val = digitalRead(button1Pin);     //read input value from button
  delay(1);                              //wait 10ms
  bounce1Check = digitalRead(button1Pin);   //check again
  
  if(button1Val == bounce1Check){           //if val is the same then not a bounce
  
    if (button1Val == HIGH && button1State == 1)    //check if the input is HIGH
     {
      digitalWrite(ledPin, LOW);         //turn LED OFF
      Serial2.write(leftOff, sizeof(leftOff));
      //Serial.println("OFF");
      button1State = 0;
     }
    if(button1Val == LOW && button1State == 0)
     {
      digitalWrite(ledPin, HIGH);       //turn LED ON
      Serial2.write(leftOn, sizeof(leftOn));
      //Serial.println("ON");
      button1State = 1;
     }
  }     
  // Button 2 Pin 51 
  button2Val = digitalRead(button2Pin);     //read input value from button
  delay(1);                              //wait 10ms
  bounce2Check = digitalRead(button2Pin);   //check again
  
  if(button2Val == bounce2Check){           //if val is the same then not a bounce
  
    if (button2Val == HIGH && button2State == 1)    //check if the input is HIGH
     {
      digitalWrite(ledPin, LOW);         //turn LED OFF
      Serial2.write(rightOff, sizeof(rightOff));
      //Serial.println("OFF");
      button2State = 0;
     }
    if(button2Val == LOW && button2State == 0)
     {
      digitalWrite(ledPin, HIGH);       //turn LED ON
      Serial2.write(rightOn, sizeof(rightOn));
      //Serial.println("ON");
      button2State = 1;
     }
  }     
   // Button 3 Pin 50 
  button3Val = digitalRead(button3Pin);     //read input value from button
  delay(1);                              //wait 10ms
  bounce3Check = digitalRead(button3Pin);   //check again
  
  if(button3Val == bounce3Check){           //if val is the same then not a bounce
  
    if (button3Val == HIGH && button3State == 1)    //check if the input is HIGH
     {
      digitalWrite(ledPin, LOW);         //turn LED OFF
      Serial2.write(upOff, sizeof(upOff));
      //Serial.println("OFF");
      button3State = 0;
     }
    if(button3Val == LOW && button3State == 0)
     {
      digitalWrite(ledPin, HIGH);       //turn LED ON
      Serial2.write(upOn, sizeof(upOn));
      //Serial.println("ON");
      button3State = 1;
     }
  }
} 


void loop()
{

   check_switches();
  
   uart_Stream();
  
}

Sorry for the length of the code, I minimized it as much as possible to post what I am trying to do.

Thanks in advance!

There are definitely some things you can do to improve your code but because you need state tracking for the buttons you have the added benefit of already using the best method for debouncing buttons. You just need to turn your state tracking into a state machine by using a switch/case statement.

hurley: I was thinking a button array, possibly.

That's the method I used in the keypad driver. You can save a lot of space by using the bitRead() and bitWrite() functions found on the Arduino Reference page.

All the examples I see on the web do not send just a single report when pushing the button down and then another on the release.

That's generally a problem caused by not using a state machine or state tracking. They can't tell when a button has actually changed so the code gets out of hand very quickly.

Any ideas or better methods to reduce code? I am also worried about SRAM usage.

Yes, but I'm at work right now so this will be a bit short to start with.

You need to move your state tracking into a separate function that takes the button's previous state and pin number as variables so you can do all your state checking/updating only when called.

As I said above, create a bitMap array of any type of variable that can be used by bitRead() and bitWrite() and use that to store your states for each button.

That will help clean up your code but I would wait until you are through making everything work before you try to reduce ram usage.

It's important to get your terminology right, so that people can understand what you are asking for. What you want is not debouncing,but edge detection

Read the StateChangeDetection example in the 02.Digital group, and adapt that code to your needs.

@Jiggy-Ninja I already tried edge detection (button state). See posted code.

@mstanley I am trying to figure this out. The array I can get (although not sure how to set to Arduino pin #'s). I also saw bitRead () and bitWrite(), but do not see how to use to determine button state with case statements to execute the Serial.write ().

I am trying to understand this, but am confused.

int button0Val = 0;              //variable for reading the button status

int button1Val = 0;
int button2Val = 0;
int button3Val = 0;

int button0State = 0;            //variable to hold the buttons current state
int button1State = 0;
int button2State = 0;
int button3State = 0;

int bounce0Check = 0;            //variable for debouncing
int bounce1Check = 0;
int bounce2Check = 0;
int bounce3Check = 0;

Read up on arrays. As soon as you have 0/1/2/3 in variable names that is crying out for an array, eg.

int buttonVal [4];
int buttonState [4];
int bounceCheck [4];
  delay(1);                              //wait 10ms

If you are going to have useless comments, they should at least match the code.

1 millisecond is too short for debouncing a switch.

    if (button0Val == HIGH && button0State == 1)    //check if the input is HIGH
     {
      digitalWrite(ledPin, LOW);         //turn LED OFF
      Serial2.write(downOff, sizeof(downOff));
      //Serial.println("OFF");
      button0State = 0;
     }
    if(button0Val == LOW && button0State == 0)
     {
      digitalWrite(ledPin, HIGH);       //turn LED ON
      Serial2.write(downOn, sizeof(downOn));
      //Serial.println("ON");
      button0State = 1;
     }

This code would be easier to understand if you had an if test to determine that the state of the pin had changed, and then an inner if/else to deal with the to pressed and to released transitions. Writing the pin to the switch state would be good, too.

Most of this belongs in a function that is passed a pin number and array name. Combining that with arrays, and you could add 12 more switches by changing (not adding) just three lines - the pin number array, the 2D action array, and the count of pin numbers.

The array I can get (although not sure how to set to Arduino pin #'s).

byte pinNums[] = { 2, 3, 4, 5 };

I am trying to understand this, but am confused.

We can't help with the confusion. But, if you ask questions, we can answer them.